From 01b395c75e0dc5e99a0da4ff94ff20cd78b67d04 Mon Sep 17 00:00:00 2001 From: ibolton336 Date: Mon, 20 Nov 2023 16:56:53 -0500 Subject: [PATCH] :bug: Update manage imports table --- .../manage-imports/manage-imports.tsx | 538 +++++++++--------- 1 file changed, 258 insertions(+), 280 deletions(-) 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 50f705dfa4..af38d7bb5a 100644 --- a/client/src/app/pages/applications/manage-imports/manage-imports.tsx +++ b/client/src/app/pages/applications/manage-imports/manage-imports.tsx @@ -4,77 +4,58 @@ import { useTranslation } from "react-i18next"; import { Button, ButtonVariant, - DropdownItem, Modal, PageSection, - Popover, + Toolbar, + ToolbarContent, ToolbarGroup, ToolbarItem, + EmptyState, + EmptyStateIcon, + EmptyStateBody, + Title, + DropdownItem, + Popover, } from "@patternfly/react-core"; -import { - cellWidth, - IAction, - ICell, - IRow, - IRowData, - ISeparator, - sortable, - truncate, -} from "@patternfly/react-table"; +import { Table, Tbody, Td, Th, Thead, Tr } from "@patternfly/react-table"; +import CubesIcon from "@patternfly/react-icons/dist/js/icons/cubes-icon"; -import { IconedStatus } from "@app/components/IconedStatus"; -import { ConfirmDialog } from "@app/components/ConfirmDialog"; +import { useLocalTableControls } from "@app/hooks/table-controls"; import { Paths } from "@app/Paths"; import { ApplicationImportSummary } from "@app/api/models"; -import { formatDate, formatPath } from "@app/utils/utils"; -import { ImportApplicationsForm } from "../components/import-applications-form"; -import { useLegacyPaginationState } from "@app/hooks/useLegacyPaginationState"; +import { AppPlaceholder } from "@app/components/AppPlaceholder"; +import { ConditionalRender } from "@app/components/ConditionalRender"; +import { ConfirmDialog } from "@app/components/ConfirmDialog"; +import { FilterType, FilterToolbar } from "@app/components/FilterToolbar"; +import { IconedStatus } from "@app/components/IconedStatus"; +import { KebabDropdown } from "@app/components/KebabDropdown"; +import { NotificationsContext } from "@app/components/NotificationsContext"; +import { SimplePagination } from "@app/components/SimplePagination"; +import { + TableHeaderContentWithControls, + ConditionalTableBody, +} from "@app/components/TableControls"; import { - useDeleteImportSummaryMutation, useFetchImportSummaries, + useDeleteImportSummaryMutation, } from "@app/queries/imports"; -import { useLegacyFilterState } from "@app/hooks/useLegacyFilterState"; -import { - FilterCategory, - FilterToolbar, - FilterType, -} from "@app/components/FilterToolbar/FilterToolbar"; -import { useLegacySortState } from "@app/hooks/useLegacySortState"; -import TooltipTitle from "@app/components/TooltipTitle"; -import { NotificationsContext } from "@app/components/NotificationsContext"; +import { formatDate, formatPath } from "@app/utils/utils"; +import { ImportApplicationsForm } from "../components/import-applications-form"; import { PageHeader } from "@app/components/PageHeader"; -import { ConditionalRender } from "@app/components/ConditionalRender"; -import { AppPlaceholder } from "@app/components/AppPlaceholder"; -import { AppTableWithControls } from "@app/components/AppTableWithControls"; -import { KebabDropdown } from "@app/components/KebabDropdown"; - -const ENTITY_FIELD = "entity"; - -const getRow = (rowData: IRowData): ApplicationImportSummary => { - return rowData[ENTITY_FIELD]; -}; export const ManageImports: React.FC = () => { - // i18 const { t } = useTranslation(); - - const [importSummaryToDelete, setImportSummaryToDelete] = - React.useState(); - - const { pushNotification } = React.useContext(NotificationsContext); - - // Router const history = useHistory(); + const { pushNotification } = React.useContext(NotificationsContext); const { importSummaries, isFetching, fetchError, refetch } = useFetchImportSummaries(); + const [importSummaryToDelete, setImportSummaryToDelete] = + useState(); - // Application import modal const [isApplicationImportModalOpen, setIsApplicationImportModalOpen] = useState(false); - // Delete - const onDeleteImportSummarySuccess = () => { pushNotification({ title: t("terms.importSummaryDeleted"), @@ -95,183 +76,62 @@ export const ManageImports: React.FC = () => { onDeleteImportSummaryError ); - const filterCategories: FilterCategory< - ApplicationImportSummary, - "filename" - >[] = [ - { - key: "filename", - title: "File Name", - type: FilterType.search, - placeholderText: "Filter by filename...", - getItemValue: (item) => { - return item?.filename || ""; - }, + const tableControls = useLocalTableControls({ + idProperty: "id", + items: importSummaries, + columnNames: { + importTime: "Import Time", + createUser: "User", + filename: "Filename", + importStatus: "Status", + validCount: "Accepted", + invalidCount: "Rejected", }, - ]; - - const { filterValues, setFilterValues, filteredItems } = useLegacyFilterState( - importSummaries || [], - filterCategories - ); - - const getSortValues = (item: ApplicationImportSummary) => [ - item?.importTime, - item?.createUser.toLowerCase(), - item?.filename?.toLowerCase() || "", - item?.importStatus, - "", // Action column - ]; - - const { sortBy, onSort, sortedItems } = useLegacySortState( - filteredItems, - getSortValues - ); - - const { currentPageItems, setPageNumber, paginationProps } = - useLegacyPaginationState(sortedItems, 10); - - // Table - const columns: ICell[] = [ - { - title: t("terms.date"), - transforms: [sortable, cellWidth(25)], - }, - { - title: t("terms.user"), - transforms: [sortable, cellWidth(15)], - cellTransforms: [truncate], - }, - { - title: t("terms.filename"), - transforms: [sortable, cellWidth(30)], - cellTransforms: [truncate], - }, - { - title: t("terms.status"), - transforms: [sortable, cellWidth(10)], - cellTransforms: [truncate], - }, - { - title: ( - - ), - transforms: [cellWidth(10)], - }, - { - title: ( - - ), - transforms: [cellWidth(10)], - }, - ]; - - const rows: IRow[] = []; - currentPageItems.forEach((item) => { - let status; - if (item.importStatus === "Completed") { - status = ; - } else if (item.importStatus === "In Progress") { - status = ; - } else { - status = ( - {t("message.importErrorCheckDocumentation")} - } - footerContent={ - - } - > - - - } - /> - ); - } - - rows.push({ - [ENTITY_FIELD]: item, - cells: [ - { - title: item.importTime ? formatDate(new Date(item.importTime)) : "", - }, - { - title: item.createUser, + isFilterEnabled: true, + isSortEnabled: true, + isPaginationEnabled: true, + isExpansionEnabled: false, + hasActionsColumn: true, + filterCategories: [ + { + key: "filename", + title: t("terms.filename"), + type: FilterType.search, + placeholderText: + t("actions.filterBy", { + what: t("terms.filename").toLowerCase(), + }) + "...", + getItemValue: (item) => { + return item?.filename || ""; }, - { - title: item.filename, - }, - { - title: status, - }, - { - title: item.validCount, - }, - { - title: item.invalidCount, - }, - ], - }); - }); - - const actionResolver = (rowData: IRowData): (IAction | ISeparator)[] => { - const row: ApplicationImportSummary = getRow(rowData); - if (!row) { - return []; - } - - const actions: (IAction | ISeparator)[] = []; - actions.push({ - title: t("actions.delete"), - onClick: ( - event: React.MouseEvent, - rowIndex: number, - rowData: IRowData - ) => { - const row: ApplicationImportSummary = getRow(rowData); - deleteRow(row); }, - }); - - if (row.importStatus === "Completed" && row.invalidCount > 0) { - actions.push({ - title: t("actions.viewErrorReport"), - onClick: ( - event: React.MouseEvent, - rowIndex: number, - rowData: IRowData - ) => { - const row: ApplicationImportSummary = getRow(rowData); - viewRowDetails(row); - }, - }); - } - - return actions; - }; + ], + sortableColumns: ["importTime", "createUser", "filename", "importStatus"], + getSortValues: (item) => ({ + importTime: item.importTime ? new Date(item.importTime).getTime() : 0, // Assuming importTime is a date, convert it to a timestamp + createUser: item.createUser.toLowerCase(), + filename: item.filename?.toLowerCase() || "", + importStatus: item.importStatus.toLowerCase(), + }), + initialSort: { columnKey: "importTime", direction: "desc" }, + isLoading: isFetching, + }); + const { + currentPageItems, + numRenderedColumns, + propHelpers: { + toolbarProps, + filterToolbarProps, + paginationToolbarItemProps, + paginationProps, + tableProps, + getThProps, + getTrProps, + getTdProps, + }, + expansionDerivedState: { isCellExpanded }, + } = tableControls; - // Row actions const deleteRow = (row: ApplicationImportSummary) => { setImportSummaryToDelete(row); }; @@ -284,10 +144,6 @@ export const ManageImports: React.FC = () => { ); }; - const handleOnClearAllFilters = () => { - setFilterValues({}); - }; - return ( <> @@ -310,65 +166,187 @@ export const ManageImports: React.FC = () => { when={isFetching && !(importSummaries || fetchError)} then={} > - + + + + + + + + ( + + )} + > + {t("actions.downloadCsvTemplate")} + , + ]} + /> + + + + + + + + + + + + + + + + + {t("composed.noDataStateTitle", { + what: t("terms.importSummary").toLowerCase(), + })} + + + {t("composed.noDataStateBody", { + what: t("terms.importSummary").toLowerCase(), + })} + + + } + numRenderedColumns={numRenderedColumns} + > + {currentPageItems?.map((importSummary, rowIndex) => { + return ( + + + + + + + + + + + + ); + })} + +
+ + + + + + +
+ {importSummary.importTime + ? formatDate(new Date(importSummary.importTime)) + : ""} + + {importSummary.createUser} + + {importSummary.filename} + + {importSummary.importStatus === "Completed" ? ( + + ) : importSummary.importStatus === "In Progress" ? ( + + ) : ( + + {t("message.importErrorCheckDocumentation")} + + } + footerContent={ + + } + > + + + } + /> + )} + {importSummary.validCount} + {importSummary.invalidCount > 0 && ( + {importSummary.invalidCount} + )} + + deleteRow(importSummary)} + > + {t("actions.delete")} + , + importSummary.importStatus === "Completed" && + importSummary.invalidCount > 0 && ( + viewRowDetails(importSummary)} + > + {t("actions.viewErrorReport")} + + ), + ]} + /> +
+ - } - toolbarActions={ - <> - - - - - - ( -
- )} - > - {t("actions.downloadCsvTemplate")} - , - ]} - /> - - - - } />
-