From e2a050302490123eba106d6e23433dcd44cf1c11 Mon Sep 17 00:00:00 2001 From: Ian Bolton Date: Tue, 12 Mar 2024 22:08:08 -0400 Subject: [PATCH 1/3] :sparkles: Integrate col mgmt modal feature with table hooks Signed-off-by: Ian Bolton --- .../components/answer-table/answer-table.tsx | 1 + .../questions-table/questions-table.tsx | 1 + client/src/app/hooks/table-controls/DOCS.md | 1 + .../table-controls/column/useColumnState.ts | 28 +++ client/src/app/hooks/table-controls/types.ts | 34 +++- .../table-controls/useLocalTableControls.ts | 3 + .../table-controls/useTableControlProps.ts | 6 + .../table-controls/useTableControlState.ts | 15 ++ .../applications-table/applications-table.tsx | 190 +++++++++++------- .../components/manage-columns-modal.css | 10 + .../components/manage-columns-modal.tsx | 105 ++++++++++ .../components/manage-columns-toolbar.tsx | 51 +++++ .../manage-imports/manage-imports.tsx | 1 + .../app/pages/archetypes/archetypes-page.tsx | 1 + .../assessment-settings-page.tsx | 1 + .../components/questionnaires-table.tsx | 1 + .../business-services/business-services.tsx | 1 + .../stakeholder-groups/stakeholder-groups.tsx | 1 + .../controls/stakeholders/stakeholders.tsx | 1 + .../app/pages/dependencies/dependencies.tsx | 1 + .../dependencies/dependency-apps-table.tsx | 1 + .../src/app/pages/external/jira/trackers.tsx | 1 + .../affected-applications.tsx | 1 + .../file-all-incidents-table.tsx | 1 + .../issue-affected-files-table.tsx | 1 + client/src/app/pages/issues/issues-table.tsx | 1 + .../components/manage-applications-form.tsx | 1 + .../components/stakeholders-table.tsx | 1 + .../components/wave-applications-table.tsx | 1 + .../components/wave-status-table.tsx | 1 + .../pages/migration-waves/migration-waves.tsx | 1 + .../adoption-candidate-table.tsx | 1 + .../identified-risks-table.tsx | 1 + 33 files changed, 388 insertions(+), 78 deletions(-) create mode 100644 client/src/app/hooks/table-controls/column/useColumnState.ts create mode 100644 client/src/app/pages/applications/applications-table/components/manage-columns-modal.css create mode 100644 client/src/app/pages/applications/applications-table/components/manage-columns-modal.tsx create mode 100644 client/src/app/pages/applications/applications-table/components/manage-columns-toolbar.tsx diff --git a/client/src/app/components/answer-table/answer-table.tsx b/client/src/app/components/answer-table/answer-table.tsx index c8d56e4c3a..8f015fe588 100644 --- a/client/src/app/components/answer-table/answer-table.tsx +++ b/client/src/app/components/answer-table/answer-table.tsx @@ -31,6 +31,7 @@ const AnswerTable: React.FC = ({ const { t } = useTranslation(); const tableControls = useLocalTableControls({ + tableName: "answer-table", idProperty: "text", items: hideAnswerKey ? answers.filter((answer) => answer.selected) diff --git a/client/src/app/components/questions-table/questions-table.tsx b/client/src/app/components/questions-table/questions-table.tsx index 729a7b036c..4a1a48f14c 100644 --- a/client/src/app/components/questions-table/questions-table.tsx +++ b/client/src/app/components/questions-table/questions-table.tsx @@ -38,6 +38,7 @@ const QuestionsTable: React.FC<{ hideAnswerKey, }) => { const tableControls = useLocalTableControls({ + tableName: "questions-table", idProperty: "text", items: questions || [], columnNames: { diff --git a/client/src/app/hooks/table-controls/DOCS.md b/client/src/app/hooks/table-controls/DOCS.md index ab19bef9fe..987bac09bc 100644 --- a/client/src/app/hooks/table-controls/DOCS.md +++ b/client/src/app/hooks/table-controls/DOCS.md @@ -38,6 +38,7 @@ const things: Thing[] = [ ]; const tableControls = useLocalTableControls({ + tableName: 'page-table-name' // A unique name of the table idProperty: "id", // The name of a unique string or number property on the data items. items: things, // The generic type `TItem` is inferred from the items passed here. columnNames: { diff --git a/client/src/app/hooks/table-controls/column/useColumnState.ts b/client/src/app/hooks/table-controls/column/useColumnState.ts new file mode 100644 index 0000000000..cdfaf29e28 --- /dev/null +++ b/client/src/app/hooks/table-controls/column/useColumnState.ts @@ -0,0 +1,28 @@ +import { useLocalStorage } from "@migtools/lib-ui"; + +export interface ColumnState { + id: TColumnKey; + label: string; + isVisible: boolean; +} + +export interface IColumnState { + columns: ColumnState[]; + setColumns: (newColumns: ColumnState[]) => void; +} + +interface IColumnStateArgs { + initialColumns: ColumnState[]; + columnsKey: string; +} + +export const useColumnState = ( + args: IColumnStateArgs +): IColumnState => { + const [columns, setColumns] = useLocalStorage[]>({ + key: args.columnsKey, + defaultValue: args.initialColumns, + }); + + return { columns, setColumns }; +}; diff --git a/client/src/app/hooks/table-controls/types.ts b/client/src/app/hooks/table-controls/types.ts index a96829c6a1..5aea4d7e55 100644 --- a/client/src/app/hooks/table-controls/types.ts +++ b/client/src/app/hooks/table-controls/types.ts @@ -38,6 +38,7 @@ import { import { IFilterToolbarProps } from "@app/components/FilterToolbar"; import { IToolbarBulkSelectorProps } from "@app/components/ToolbarBulkSelector"; import { IExpansionPropHelpersExternalArgs } from "./expansion/useExpansionPropHelpers"; +import { IColumnState } from "./column/useColumnState"; // Generic type params used here: // TItem - The actual API objects represented by rows in the table. Can be any object. @@ -56,7 +57,8 @@ export type TableFeature = | "pagination" | "selection" | "expansion" - | "activeItem"; + | "activeItem" + | "columns"; /** * Identifier for where to persist state for a single table feature or for all table features. @@ -136,12 +138,19 @@ export type IUseTableControlStateArgs< TFilterCategoryKey extends string = string, TPersistenceKeyPrefix extends string = string, > = { + /** + * Unique table identifier. Used for state persistence and to distinguish between stored state between multiple tables. + */ + tableName: string; /** * An ordered mapping of unique keys to human-readable column name strings. * - Keys of this object are used as unique identifiers for columns (`columnKey`). * - Values of this object are rendered in the column headers by default (can be overridden by passing children to ) and used as `dataLabel` for cells in the column. */ columnNames: Record; + /** + * Initial state for the columns feature. If omitted, all columns are enabled by default. + */ } & IFilterStateArgs & ISortStateArgs & IPaginationStateArgs & { @@ -193,6 +202,10 @@ export type ITableControlState< * State for the active item feature. Returned by useActiveItemState. */ activeItemState: IActiveItemState; + /** + * State for the columns feature. Returned by useColumnState. + */ + columnState: IColumnState; }; /** @@ -288,6 +301,10 @@ export type IUseTableControlPropsArgs< * @todo this won't be included here when useSelectionState gets moved from lib-ui. It is separated from the other state temporarily and used only at render time. */ selectionState: ReturnType>; + /** + * The state for the columns feature. Returned by useColumnState. + */ + columnState: IColumnState; }; /** @@ -325,9 +342,18 @@ export type ITableControls< * Values derived at render time from the expansion feature state. Includes helper functions for convenience. */ expansionDerivedState: IExpansionDerivedState; + /** + * Values derived at render time from the column feature state. Includes helper functions for convenience. + * + * + * + * + */ + columnState: IColumnState; /** * Values derived at render time from the active-item feature state. Includes helper functions for convenience. */ + activeItemDerivedState: IActiveItemDerivedState; /** * Prop helpers: where it all comes together. @@ -406,6 +432,12 @@ export type ITableControls< * The two Trs for the expandable row and expanded content row should be contained in a Tbody with no other Tr components. */ getExpandedContentTdProps: (args: { item: TItem }) => Omit; + + /** + * Returns the visibility of a column + */ + + getColumnVisibility: (columnKey: TColumnKey) => boolean; }; }; diff --git a/client/src/app/hooks/table-controls/useLocalTableControls.ts b/client/src/app/hooks/table-controls/useLocalTableControls.ts index c24d0d70c6..7c6cc89178 100644 --- a/client/src/app/hooks/table-controls/useLocalTableControls.ts +++ b/client/src/app/hooks/table-controls/useLocalTableControls.ts @@ -33,6 +33,7 @@ export const useLocalTableControls = < > => { const state = useTableControlState(args); const derivedState = getLocalTableControlDerivedState({ ...args, ...state }); + const { columnState } = state; return useTableControlProps({ ...args, ...state, @@ -42,5 +43,7 @@ export const useLocalTableControls = < ...args, isEqual: (a, b) => a[args.idProperty] === b[args.idProperty], }), + idProperty: args.idProperty, + ...columnState, }); }; diff --git a/client/src/app/hooks/table-controls/useTableControlProps.ts b/client/src/app/hooks/table-controls/useTableControlProps.ts index 6169d1f491..a0ea625f37 100644 --- a/client/src/app/hooks/table-controls/useTableControlProps.ts +++ b/client/src/app/hooks/table-controls/useTableControlProps.ts @@ -74,6 +74,7 @@ export const useTableControlProps = < isSelectionEnabled, isExpansionEnabled, isActiveItemEnabled, + columnState: { columns }, } = args; const columnKeys = objectKeys(columnNames); @@ -171,6 +172,10 @@ export const useTableControlProps = < }, }); + const getColumnVisibility = (columnKey: TColumnKey) => { + return columns.find((column) => column.id === columnKey)?.isVisible ?? true; + }; + return { ...args, numColumnsBeforeData, @@ -191,6 +196,7 @@ export const useTableControlProps = < getSelectCheckboxTdProps, getSingleExpandButtonTdProps, getExpandedContentTdProps, + getColumnVisibility, }, }; }; diff --git a/client/src/app/hooks/table-controls/useTableControlState.ts b/client/src/app/hooks/table-controls/useTableControlState.ts index 830a933270..980e35ac64 100644 --- a/client/src/app/hooks/table-controls/useTableControlState.ts +++ b/client/src/app/hooks/table-controls/useTableControlState.ts @@ -9,6 +9,7 @@ import { useSortState } from "./sorting"; import { usePaginationState } from "./pagination"; import { useActiveItemState } from "./active-item"; import { useExpansionState } from "./expansion"; +import { useColumnState } from "./column/useColumnState"; /** * Provides the "source of truth" state for all table features. @@ -66,6 +67,19 @@ export const useTableControlState = < ...args, persistTo: getPersistTo("activeItem"), }); + + const { columnNames, tableName } = args; + + const initialColumns = Object.entries(columnNames).map(([id, label]) => ({ + id: id as TColumnKey, + label: label as string, + isVisible: true, + })); + + const columnState = useColumnState({ + columnsKey: tableName, + initialColumns, + }); return { ...args, filterState, @@ -73,5 +87,6 @@ export const useTableControlState = < paginationState, expansionState, activeItemState, + columnState, }; }; diff --git a/client/src/app/pages/applications/applications-table/applications-table.tsx b/client/src/app/pages/applications/applications-table/applications-table.tsx index e596026ba1..6116c3b3f4 100644 --- a/client/src/app/pages/applications/applications-table/applications-table.tsx +++ b/client/src/app/pages/applications/applications-table/applications-table.tsx @@ -108,6 +108,7 @@ import { ApplicationReviewStatus } from "../components/application-review-status import { KebabDropdown } from "@app/components/KebabDropdown"; import { useFetchArchetypes } from "@app/queries/archetypes"; import { ApplicationFormModal } from "../components/application-form"; +import { ManageColumnsToolbar } from "./components/manage-columns-toolbar"; export const ApplicationsTable: React.FC = () => { const { t } = useTranslation(); @@ -214,7 +215,7 @@ export const ApplicationsTable: React.FC = () => { refetch: fetchApplications, } = useFetchApplications(!hasActiveTasks); - const { assessments, isFetching: isFetchingAssesments } = + const { assessments, isFetching: isFetchingAssessments } = useFetchAssessments(); const { archetypes, isFetching: isFetchingArchetypes } = useFetchArchetypes(); @@ -310,6 +311,7 @@ export const ApplicationsTable: React.FC = () => { const deserializedFilterValues = deserializeFilterUrlParams({ filters }); const tableControls = useLocalTableControls({ + tableName: "applications", idProperty: "id", items: applications || [], columnNames: { @@ -517,10 +519,12 @@ export const ApplicationsTable: React.FC = () => { getTrProps, getTdProps, toolbarBulkSelectorProps, + getColumnVisibility, }, activeItemDerivedState: { activeItem, clearActiveItem }, selectionState: { selectedItems: selectedRows }, + columnState, } = tableControls; const clearFilters = () => { @@ -811,6 +815,10 @@ export const ApplicationsTable: React.FC = () => { ) : ( <> )} + @@ -826,16 +834,30 @@ export const ApplicationsTable: React.FC = () => { - - - - - - - + {getColumnVisibility("name") && ( + + )} + {getColumnVisibility("businessService") && ( + + )} + {getColumnVisibility("assessment") && ( + + )} + {getColumnVisibility("review") && ( + + )} + {getColumnVisibility("analysis") && ( + + )} + {getColumnVisibility("tags") && ( + + )} + {getColumnVisibility("effort") && ( + + )} @@ -871,73 +893,87 @@ export const ApplicationsTable: React.FC = () => { item={application} rowIndex={rowIndex} > - - {application.name} - - - {application.businessService && ( - + {application.name} + + )} + {getColumnVisibility("businessService") && ( + + {application.businessService && ( + + )} + + )} + {getColumnVisibility("assessment") && ( + + - )} - - - - - - - - - - - - - {application.tags ? application.tags.length : 0} - - - {application?.effort ?? "-"} - + + )} + {getColumnVisibility("review") && ( + + + + )} + {getColumnVisibility("analysis") && ( + + + + )} + {getColumnVisibility("tags") && ( + + + {application.tags ? application.tags.length : 0} + + )} + {getColumnVisibility("effort") && ( + + {application?.effort ?? "-"} + + )} {applicationWriteAccess && ( diff --git a/client/src/app/pages/applications/applications-table/components/manage-columns-modal.css b/client/src/app/pages/applications/applications-table/components/manage-columns-modal.css new file mode 100644 index 0000000000..547823fd77 --- /dev/null +++ b/client/src/app/pages/applications/applications-table/components/manage-columns-modal.css @@ -0,0 +1,10 @@ +.custom-data-list-item-row { + display: flex; + align-items: center; +} + +.custom-data-list-cell { + flex: 1; + display: flex; + align-items: center; +} diff --git a/client/src/app/pages/applications/applications-table/components/manage-columns-modal.tsx b/client/src/app/pages/applications/applications-table/components/manage-columns-modal.tsx new file mode 100644 index 0000000000..ac0c8a9881 --- /dev/null +++ b/client/src/app/pages/applications/applications-table/components/manage-columns-modal.tsx @@ -0,0 +1,105 @@ +import "./manage-columns-modal.css"; + +import React, { useState } from "react"; +import { + Button, + DataList, + DataListCell, + DataListCheck, + DataListControl, + DataListItem, + DataListItemCells, + DataListItemRow, + Modal, + Text, + TextContent, + TextVariants, +} from "@patternfly/react-core"; +import { ColumnState } from "@app/hooks/table-controls/column/useColumnState"; + +export interface ManagedColumnsProps { + showModal: boolean; + onClose(): void; + columns: ColumnState[]; + setColumns: (newColumns: ColumnState[]) => void; + description?: string; + saveLabel?: string; + cancelLabel?: string; + title?: string; +} + +export const ManageColumnsModal = ({ + showModal, + description = "Selected columns will be displayed in the table.", + onClose, + columns, + setColumns, + saveLabel = "Save", + cancelLabel = "Cancel", + title = "Manage Columns", +}: ManagedColumnsProps) => { + const [editedColumns, setEditedColumns] = + useState[]>(columns); + + const onSelect = (id: TColumnKey, isVisible: boolean): void => { + setEditedColumns( + editedColumns.map((col) => ({ + ...col, + isVisible: col.id === id ? isVisible : col.isVisible, + })) + ); + }; + + const onSave = () => { + // If ordering is implemented, update accordingly + setColumns(editedColumns); + onClose(); + }; + + return ( + + {description} + + } + onClose={onClose} + actions={[ + , + , + ]} + > + + {editedColumns.map(({ id, label, isVisible }, index) => ( + + + + onSelect(id, checked)} + /> + + + {label} + , + ]} + /> + + + ))} + + + ); +}; diff --git a/client/src/app/pages/applications/applications-table/components/manage-columns-toolbar.tsx b/client/src/app/pages/applications/applications-table/components/manage-columns-toolbar.tsx new file mode 100644 index 0000000000..8403a44b0f --- /dev/null +++ b/client/src/app/pages/applications/applications-table/components/manage-columns-toolbar.tsx @@ -0,0 +1,51 @@ +import { + Button, + OverflowMenu, + OverflowMenuGroup, + OverflowMenuItem, + ToolbarItem, +} from "@patternfly/react-core"; +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { ColumnState } from "@app/hooks/table-controls/column/useColumnState"; +import { ManageColumnsModal } from "./manage-columns-modal"; + +// Define props to accept columns and setColumns directly +interface ManageColumnsToolbarProps { + columns: ColumnState[]; + setColumns: (newColumns: ColumnState[]) => void; +} + +export const ManageColumnsToolbar = ({ + columns, + setColumns, +}: ManageColumnsToolbarProps) => { + const { t } = useTranslation(); + const [isOpen, setIsOpen] = useState(false); + return ( + <> + + + + + + + + + + + setIsOpen(false)} + description={t("Selected columns will be displayed in the table.")} + setColumns={setColumns} + columns={columns} + saveLabel={t("Save")} + cancelLabel={t("Cancel")} + title={t("Manage Columns")} + /> + + ); +}; diff --git a/client/src/app/pages/applications/manage-imports/manage-imports.tsx b/client/src/app/pages/applications/manage-imports/manage-imports.tsx index ed07a061cf..351ab51e79 100644 --- a/client/src/app/pages/applications/manage-imports/manage-imports.tsx +++ b/client/src/app/pages/applications/manage-imports/manage-imports.tsx @@ -78,6 +78,7 @@ export const ManageImports: React.FC = () => { ); const tableControls = useLocalTableControls({ + tableName: "manage-imports", idProperty: "id", items: importSummaries, columnNames: { diff --git a/client/src/app/pages/archetypes/archetypes-page.tsx b/client/src/app/pages/archetypes/archetypes-page.tsx index b11e247497..f72ab8c27f 100644 --- a/client/src/app/pages/archetypes/archetypes-page.tsx +++ b/client/src/app/pages/archetypes/archetypes-page.tsx @@ -192,6 +192,7 @@ const Archetypes: React.FC = () => { const deserializedFilterValues = deserializeFilterUrlParams({ filters }); const tableControls = useLocalTableControls({ + tableName: "archetypes-table", persistTo: "urlParams", persistenceKeyPrefix: TablePersistenceKeyPrefix.archetypes, idProperty: "id", diff --git a/client/src/app/pages/assessment-management/assessment-settings/assessment-settings-page.tsx b/client/src/app/pages/assessment-management/assessment-settings/assessment-settings-page.tsx index fbf1384b74..2cd16dff6c 100644 --- a/client/src/app/pages/assessment-management/assessment-settings/assessment-settings-page.tsx +++ b/client/src/app/pages/assessment-management/assessment-settings/assessment-settings-page.tsx @@ -101,6 +101,7 @@ const AssessmentSettings: React.FC = () => { const [questionnaireToDelete, setQuestionnaireToDelete] = React.useState(); const tableControls = useLocalTableControls({ + tableName: "questionnaires-table", idProperty: "id", items: questionnaires || [], columnNames: { diff --git a/client/src/app/pages/assessment/components/assessment-actions/components/questionnaires-table.tsx b/client/src/app/pages/assessment/components/assessment-actions/components/questionnaires-table.tsx index ef3687b839..48384839e4 100644 --- a/client/src/app/pages/assessment/components/assessment-actions/components/questionnaires-table.tsx +++ b/client/src/app/pages/assessment/components/assessment-actions/components/questionnaires-table.tsx @@ -37,6 +37,7 @@ const QuestionnairesTable: React.FC = ({ tableName, }) => { const tableControls = useLocalTableControls({ + tableName: "questionnaires-table", idProperty: "id", items: questionnaires || [], columnNames: { diff --git a/client/src/app/pages/controls/business-services/business-services.tsx b/client/src/app/pages/controls/business-services/business-services.tsx index e45f556af9..c5f9608aba 100644 --- a/client/src/app/pages/controls/business-services/business-services.tsx +++ b/client/src/app/pages/controls/business-services/business-services.tsx @@ -81,6 +81,7 @@ export const BusinessServices: React.FC = () => { const { data: applications } = useFetchApplications(); const tableControls = useLocalTableControls({ + tableName: "business-services-table", idProperty: "name", items: businessServices, columnNames: { diff --git a/client/src/app/pages/controls/stakeholder-groups/stakeholder-groups.tsx b/client/src/app/pages/controls/stakeholder-groups/stakeholder-groups.tsx index ae388d4b7f..eba7a03100 100644 --- a/client/src/app/pages/controls/stakeholder-groups/stakeholder-groups.tsx +++ b/client/src/app/pages/controls/stakeholder-groups/stakeholder-groups.tsx @@ -99,6 +99,7 @@ export const StakeholderGroups: React.FC = () => { }; const tableControls = useLocalTableControls({ + tableName: "stakeholder-groups-table", idProperty: "name", items: stakeholderGroups, columnNames: { diff --git a/client/src/app/pages/controls/stakeholders/stakeholders.tsx b/client/src/app/pages/controls/stakeholders/stakeholders.tsx index cf8a16540e..5fe48a8b3a 100644 --- a/client/src/app/pages/controls/stakeholders/stakeholders.tsx +++ b/client/src/app/pages/controls/stakeholders/stakeholders.tsx @@ -95,6 +95,7 @@ export const Stakeholders: React.FC = () => { }; const tableControls = useLocalTableControls({ + tableName: "stakeholders-table", idProperty: "email", items: stakeholders, columnNames: { diff --git a/client/src/app/pages/dependencies/dependencies.tsx b/client/src/app/pages/dependencies/dependencies.tsx index f05e95c595..53dee126dd 100644 --- a/client/src/app/pages/dependencies/dependencies.tsx +++ b/client/src/app/pages/dependencies/dependencies.tsx @@ -44,6 +44,7 @@ export const Dependencies: React.FC = () => { const deserializedFilterValues = deserializeFilterUrlParams({ filters }); const tableControlState = useTableControlState({ + tableName: "dependencies-table", persistTo: "urlParams", persistenceKeyPrefix: TablePersistenceKeyPrefix.dependencies, columnNames: { diff --git a/client/src/app/pages/dependencies/dependency-apps-table.tsx b/client/src/app/pages/dependencies/dependency-apps-table.tsx index 0efcf836bb..bd8bd9cb18 100644 --- a/client/src/app/pages/dependencies/dependency-apps-table.tsx +++ b/client/src/app/pages/dependencies/dependency-apps-table.tsx @@ -51,6 +51,7 @@ export const DependencyAppsTable: React.FC = ({ const deserializedFilterValues = deserializeFilterUrlParams({ filters }); const tableControlState = useTableControlState({ + tableName: "dependency-apps-table", persistTo: "urlParams", persistenceKeyPrefix: TablePersistenceKeyPrefix.dependencyApplications, columnNames: { diff --git a/client/src/app/pages/external/jira/trackers.tsx b/client/src/app/pages/external/jira/trackers.tsx index 2e09b2aaac..321d3e4acb 100644 --- a/client/src/app/pages/external/jira/trackers.tsx +++ b/client/src/app/pages/external/jira/trackers.tsx @@ -92,6 +92,7 @@ export const JiraTrackers: React.FC = () => { ); const tableControls = useLocalTableControls({ + tableName: "jira-Tracker-table", idProperty: "name", items: trackers, columnNames: { diff --git a/client/src/app/pages/issues/affected-applications/affected-applications.tsx b/client/src/app/pages/issues/affected-applications/affected-applications.tsx index deebaaa4fb..c0db18e0fd 100644 --- a/client/src/app/pages/issues/affected-applications/affected-applications.tsx +++ b/client/src/app/pages/issues/affected-applications/affected-applications.tsx @@ -53,6 +53,7 @@ export const AffectedApplications: React.FC = () => { "Active rule"; const tableControlState = useTableControlState({ + tableName: "affected-applications-table", persistTo: "urlParams", persistenceKeyPrefix: TablePersistenceKeyPrefix.issuesAffectedApps, columnNames: { diff --git a/client/src/app/pages/issues/issue-detail-drawer/file-incidents-detail-modal/file-all-incidents-table.tsx b/client/src/app/pages/issues/issue-detail-drawer/file-incidents-detail-modal/file-all-incidents-table.tsx index 07638c4d30..360856ac0e 100644 --- a/client/src/app/pages/issues/issue-detail-drawer/file-incidents-detail-modal/file-all-incidents-table.tsx +++ b/client/src/app/pages/issues/issue-detail-drawer/file-incidents-detail-modal/file-all-incidents-table.tsx @@ -26,6 +26,7 @@ export const FileAllIncidentsTable: React.FC< IFileRemainingIncidentsTableProps > = ({ fileReport }) => { const tableControlState = useTableControlState({ + tableName: "file-all-incidents-table", persistTo: "urlParams", persistenceKeyPrefix: TablePersistenceKeyPrefix.issuesRemainingIncidents, columnNames: { diff --git a/client/src/app/pages/issues/issue-detail-drawer/issue-affected-files-table.tsx b/client/src/app/pages/issues/issue-detail-drawer/issue-affected-files-table.tsx index 49569a649e..61048d886e 100644 --- a/client/src/app/pages/issues/issue-detail-drawer/issue-affected-files-table.tsx +++ b/client/src/app/pages/issues/issue-detail-drawer/issue-affected-files-table.tsx @@ -37,6 +37,7 @@ export const IssueAffectedFilesTable: React.FC< const { t } = useTranslation(); const tableControlState = useTableControlState({ + tableName: "affected-files-table", persistTo: "urlParams", persistenceKeyPrefix: TablePersistenceKeyPrefix.issuesAffectedFiles, columnNames: { diff --git a/client/src/app/pages/issues/issues-table.tsx b/client/src/app/pages/issues/issues-table.tsx index 401e724eba..17d2dce479 100644 --- a/client/src/app/pages/issues/issues-table.tsx +++ b/client/src/app/pages/issues/issues-table.tsx @@ -96,6 +96,7 @@ export const IssuesTable: React.FC = ({ mode }) => { useSharedAffectedApplicationFilterCategories(); const tableControlState = useTableControlState({ + tableName: "issues-table", persistTo: "urlParams", persistenceKeyPrefix: TablePersistenceKeyPrefix.issues, columnNames: { diff --git a/client/src/app/pages/migration-waves/components/manage-applications-form.tsx b/client/src/app/pages/migration-waves/components/manage-applications-form.tsx index e0fbedb8eb..a1166c51e7 100644 --- a/client/src/app/pages/migration-waves/components/manage-applications-form.tsx +++ b/client/src/app/pages/migration-waves/components/manage-applications-form.tsx @@ -100,6 +100,7 @@ export const ManageApplicationsForm: React.FC = ({ ); const tableControls = useLocalTableControls({ + tableName: "manage-applications-table", idProperty: "name", items: availableApplications, columnNames: { diff --git a/client/src/app/pages/migration-waves/components/stakeholders-table.tsx b/client/src/app/pages/migration-waves/components/stakeholders-table.tsx index e40eac74e3..fb2ab2c879 100644 --- a/client/src/app/pages/migration-waves/components/stakeholders-table.tsx +++ b/client/src/app/pages/migration-waves/components/stakeholders-table.tsx @@ -18,6 +18,7 @@ export const WaveStakeholdersTable: React.FC = ({ migrationWave, }) => { const tableControls = useLocalTableControls({ + tableName: "wave-stakeholders-table", idProperty: "name", items: migrationWave.allStakeholders, columnNames: { diff --git a/client/src/app/pages/migration-waves/components/wave-applications-table.tsx b/client/src/app/pages/migration-waves/components/wave-applications-table.tsx index f56baa1a09..a922a7f448 100644 --- a/client/src/app/pages/migration-waves/components/wave-applications-table.tsx +++ b/client/src/app/pages/migration-waves/components/wave-applications-table.tsx @@ -35,6 +35,7 @@ export const WaveApplicationsTable: React.FC = ({ const { tickets } = useFetchTickets(); const tableControls = useLocalTableControls({ + tableName: "wave-applications-table", idProperty: "name", items: migrationWave.fullApplications, columnNames: { diff --git a/client/src/app/pages/migration-waves/components/wave-status-table.tsx b/client/src/app/pages/migration-waves/components/wave-status-table.tsx index c2e9c2f08b..8e26a22e9e 100644 --- a/client/src/app/pages/migration-waves/components/wave-status-table.tsx +++ b/client/src/app/pages/migration-waves/components/wave-status-table.tsx @@ -61,6 +61,7 @@ export const WaveStatusTable: React.FC = ({ const { mutate: deleteTicket } = useDeleteTicketMutation(); const tableControls = useLocalTableControls({ + tableName: "wave-applications-table", idProperty: "name", items: migrationWave.fullApplications, columnNames: { diff --git a/client/src/app/pages/migration-waves/migration-waves.tsx b/client/src/app/pages/migration-waves/migration-waves.tsx index 5dc78ca762..ae44e79e2f 100644 --- a/client/src/app/pages/migration-waves/migration-waves.tsx +++ b/client/src/app/pages/migration-waves/migration-waves.tsx @@ -180,6 +180,7 @@ export const MigrationWaves: React.FC = () => { }; const tableControls = useLocalTableControls({ + tableName: "migration-waves-table", idProperty: "id", items: migrationWaves, columnNames: { diff --git a/client/src/app/pages/reports/components/adoption-candidate-table/adoption-candidate-table.tsx b/client/src/app/pages/reports/components/adoption-candidate-table/adoption-candidate-table.tsx index 5833a35f3f..bf3b1f1ac0 100644 --- a/client/src/app/pages/reports/components/adoption-candidate-table/adoption-candidate-table.tsx +++ b/client/src/app/pages/reports/components/adoption-candidate-table/adoption-candidate-table.tsx @@ -51,6 +51,7 @@ const AdoptionCandidateTable: React.FC = () => { }, [allApplications, reviews]); const tableControls = useLocalTableControls({ + tableName: "adoption-candidate-table", idProperty: "id", items: applicationsWithReviews || [], columnNames: { diff --git a/client/src/app/pages/reports/components/identified-risks-table/identified-risks-table.tsx b/client/src/app/pages/reports/components/identified-risks-table/identified-risks-table.tsx index cc97ee7cd9..86862521aa 100644 --- a/client/src/app/pages/reports/components/identified-risks-table/identified-risks-table.tsx +++ b/client/src/app/pages/reports/components/identified-risks-table/identified-risks-table.tsx @@ -141,6 +141,7 @@ export const IdentifiedRisksTable: React.FC = ({ }); const tableControls = useLocalTableControls({ + tableName: "identified-risks-table", idProperty: "questionId", items: tableData || [], columnNames: { From 797d15274b74070e3eb84657bf93a9a56132239c Mon Sep 17 00:00:00 2001 From: Ian Bolton Date: Tue, 26 Mar 2024 10:17:07 -0400 Subject: [PATCH 2/3] PR suggestions Signed-off-by: Ian Bolton --- .../applications-table/applications-table.tsx | 2 ++ .../components/manage-columns-modal.tsx | 4 +-- .../components/manage-columns-toolbar.tsx | 34 ++++++++++--------- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/client/src/app/pages/applications/applications-table/applications-table.tsx b/client/src/app/pages/applications/applications-table/applications-table.tsx index 6116c3b3f4..720f0daf5c 100644 --- a/client/src/app/pages/applications/applications-table/applications-table.tsx +++ b/client/src/app/pages/applications/applications-table/applications-table.tsx @@ -805,6 +805,8 @@ export const ApplicationsTable: React.FC = () => { + + {dropdownItems.length ? ( { - showModal: boolean; onClose(): void; columns: ColumnState[]; setColumns: (newColumns: ColumnState[]) => void; @@ -29,7 +28,6 @@ export interface ManagedColumnsProps { } export const ManageColumnsModal = ({ - showModal, description = "Selected columns will be displayed in the table.", onClose, columns, @@ -59,7 +57,7 @@ export const ManageColumnsModal = ({ return ( diff --git a/client/src/app/pages/applications/applications-table/components/manage-columns-toolbar.tsx b/client/src/app/pages/applications/applications-table/components/manage-columns-toolbar.tsx index 8403a44b0f..91d4f5a726 100644 --- a/client/src/app/pages/applications/applications-table/components/manage-columns-toolbar.tsx +++ b/client/src/app/pages/applications/applications-table/components/manage-columns-toolbar.tsx @@ -9,8 +9,8 @@ import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { ColumnState } from "@app/hooks/table-controls/column/useColumnState"; import { ManageColumnsModal } from "./manage-columns-modal"; +import { ColumnsIcon } from "@patternfly/react-icons"; -// Define props to accept columns and setColumns directly interface ManageColumnsToolbarProps { columns: ColumnState[]; setColumns: (newColumns: ColumnState[]) => void; @@ -24,28 +24,30 @@ export const ManageColumnsToolbar = ({ const [isOpen, setIsOpen] = useState(false); return ( <> - + - + - - setIsOpen(false)} - description={t("Selected columns will be displayed in the table.")} - setColumns={setColumns} - columns={columns} - saveLabel={t("Save")} - cancelLabel={t("Cancel")} - title={t("Manage Columns")} - /> + {isOpen && ( + setIsOpen(false)} + description={t("Selected columns will be displayed in the table.")} + setColumns={setColumns} + columns={columns} + saveLabel={t("Save")} + cancelLabel={t("Cancel")} + title={t("Manage Columns")} + /> + )} ); }; From 7d245ed99b23b2498cf3db42580fa9016e8fdd10 Mon Sep 17 00:00:00 2001 From: Ian Bolton Date: Tue, 26 Mar 2024 13:57:08 -0400 Subject: [PATCH 3/3] PR suggestions Signed-off-by: Ian Bolton --- client/public/locales/en/translation.json | 2 ++ .../components/manage-columns-modal.tsx | 2 ++ .../components/manage-columns-toolbar.tsx | 8 ++++---- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/client/public/locales/en/translation.json b/client/public/locales/en/translation.json index 161c2e055f..379a37d354 100644 --- a/client/public/locales/en/translation.json +++ b/client/public/locales/en/translation.json @@ -132,6 +132,7 @@ "import": "Import {{what}}", "leavePage": "Leave page", "leaveAssessment": "Leave assessment", + "manageColumns": "Manage columns", "new": "New {{what}}", "newArchetype": "Create new archetype", "newAssessment": "New assessment", @@ -213,6 +214,7 @@ "selectedBecauseArchetypeTags": "Selected because the archetype's tags include {{tags}}", "selectedBecauseAppOrArchetypeTags": "Selected because the application or archetype's tags include {{tags}}", "selectOwnerFromStakeholdersList": "Select owner from list of stakeholders", + "manageColumnsDescription": "Select the columns you want to display in the table view.", "suggestedAdoptionPlanHelpText": "The suggested approach to migration based on effort, priority, and dependencies.", "taskInProgressForTags": "A new analysis is in-progress. Tags may be updated upon completion.", "toTagApplication": "Either no tags exist yet or you may not have permission to view any. If you have permission, try creating a new custom tag.", diff --git a/client/src/app/pages/applications/applications-table/components/manage-columns-modal.tsx b/client/src/app/pages/applications/applications-table/components/manage-columns-modal.tsx index d8aec5d7aa..ffbbb8dd33 100644 --- a/client/src/app/pages/applications/applications-table/components/manage-columns-modal.tsx +++ b/client/src/app/pages/applications/applications-table/components/manage-columns-modal.tsx @@ -82,6 +82,8 @@ export const ManageColumnsModal = ({