From 9e6d5c10fbda048a453dbc4ebc1145d8b0904046 Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Tue, 24 Oct 2023 11:36:10 -0500 Subject: [PATCH] CE-604 Updates to DataTable for fixed-sticky footer and expandable rows; Misc style updates going along with e.g., card border change --- .../components/widgets/DashboardWidgets.tsx | 2 +- .../components/widgets/tables/DataTable.tsx | 261 ++++++++++++------ .../components/widgets/tables/TableCard.tsx | 6 +- .../components/widgets/tables/TableWidget.tsx | 2 + src/qqq/pages/processes/ProcessRun.tsx | 1 + src/qqq/pages/records/query/RecordQuery.tsx | 1 + src/qqq/styles/qqq-override-styles.css | 11 + 7 files changed, 201 insertions(+), 83 deletions(-) diff --git a/src/qqq/components/widgets/DashboardWidgets.tsx b/src/qqq/components/widgets/DashboardWidgets.tsx index edd577c..d285cf6 100644 --- a/src/qqq/components/widgets/DashboardWidgets.tsx +++ b/src/qqq/components/widgets/DashboardWidgets.tsx @@ -505,7 +505,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit if (wrapWidgetsInTabPanels) { - renderedWidget = ( + renderedWidget = ( {renderedWidget} ); } diff --git a/src/qqq/components/widgets/tables/DataTable.tsx b/src/qqq/components/widgets/tables/DataTable.tsx index fbcbaec..9cb3a97 100644 --- a/src/qqq/components/widgets/tables/DataTable.tsx +++ b/src/qqq/components/widgets/tables/DataTable.tsx @@ -30,7 +30,7 @@ import TableRow from "@mui/material/TableRow"; import Tooltip from "@mui/material/Tooltip"; import parse from "html-react-parser"; import {useEffect, useMemo, useState} from "react"; -import {useAsyncDebounce, useGlobalFilter, usePagination, useSortBy, useTable} from "react-table"; +import {useAsyncDebounce, useGlobalFilter, usePagination, useSortBy, useTable, useExpanded} from "react-table"; import MDInput from "qqq/components/legacy/MDInput"; import MDPagination from "qqq/components/legacy/MDPagination"; import MDTypography from "qqq/components/legacy/MDTypography"; @@ -47,6 +47,8 @@ interface Props canSearch?: boolean; showTotalEntries?: boolean; hidePaginationDropdown?: boolean; + fixedStickyLastRow?: boolean; + fixedHeight?: number; table: TableDataInput; pagination?: { variant: "contained" | "gradient"; @@ -56,6 +58,18 @@ interface Props noEndBorder?: boolean; } +DataTable.defaultProps = { + entriesPerPage: 10, + entriesPerPageOptions: ["5", "10", "15", "20", "25"], + canSearch: false, + showTotalEntries: true, + fixedStickyLastRow: false, + fixedHeight: null, + pagination: {variant: "gradient", color: "info"}, + isSorted: true, + noEndBorder: false, +}; + const NoMaxWidthTooltip = styled(({className, ...props}: TooltipProps) => ( ))({ @@ -71,6 +85,8 @@ function DataTable({ hidePaginationDropdown, canSearch, showTotalEntries, + fixedStickyLastRow, + fixedHeight, table, pagination, isSorted, @@ -83,8 +99,73 @@ function DataTable({ defaultValue = (entriesPerPage) ? entriesPerPage : "10"; entries = entriesPerPageOptions ? entriesPerPageOptions : ["10", "25", "50", "100"]; - const columns = useMemo(() => table.columns, [table]); + let widths = []; + for(let i = 0; i ( + // + // {isAllRowsExpanded ? "yes" : "no"} + // + // ), + header: () => (), + + // @ts-ignore + cell: ({row}) => + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // Use the row.canExpand and row.getToggleRowExpandedProps prop getter to build the toggle for expanding a row // + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// + row.canExpand ? ( + + {row.isExpanded ? "expand_less" : "chevron_right"} + + ) : null, + }, + ); + } + + const columns = useMemo(() => columnsToMemo, [table]); const data = useMemo(() => table.rows, [table]); + const gridTemplateColumns = widths.join(" "); if (!columns || !data) { @@ -95,6 +176,7 @@ function DataTable({ {columns, data, initialState: {pageIndex: 0}}, useGlobalFilter, useSortBy, + useExpanded, usePagination ); @@ -113,7 +195,7 @@ function DataTable({ previousPage, setPageSize, setGlobalFilter, - state: {pageIndex, pageSize, globalFilter}, + state: {pageIndex, pageSize, globalFilter, expanded}, }: any = tableInstance; // Set the default value for the entries per page when component mounts @@ -193,79 +275,45 @@ function DataTable({ entriesEnd = pageSize * (pageIndex + 1); } - return ( - - {entriesPerPage && ((hidePaginationDropdown !== undefined && ! hidePaginationDropdown) || canSearch) ? ( - - {entriesPerPage && (hidePaginationDropdown === undefined || ! hidePaginationDropdown) && ( - - - { - if(typeof newValues === "string") - { - setEntriesPerPage(parseInt(newValues, 10)); - } - else - { - setEntriesPerPage(parseInt(newValues[0], 10)); - } - }} - size="small" - sx={{width: "5rem"}} - renderInput={(params) => } - /> - -   entries per page - - - )} - {canSearch && ( - - - { - setSearch(search); - onSearchChange(currentTarget.value); - }} - /> - - )} - - ) : null} + function getTable(includeHead: boolean, rows: any, isFooter: boolean) + { + let boxStyle = {}; + if(fixedStickyLastRow) + { + boxStyle = isFooter ? {overflowY: "visible", borderTop: "0.0625rem solid #f0f2f5;"} : {height: fixedHeight ? `${fixedHeight}px` : "360px", overflowY: "auto"}; + } + + const className = isFooter ? "hideScrollbars" : ""; + return - - {headerGroups.map((headerGroup: any, i: number) => ( - - {headerGroup.headers.map((column: any) => ( - column.type !== "hidden" && ( - - {column.render("header")} - - ) + { + includeHead && ( + + {headerGroups.map((headerGroup: any, i: number) => ( + + {headerGroup.headers.map((column: any) => ( + column.type !== "hidden" && ( + + {column.render("header")} + + ) + ))} + ))} - - ))} - + + ) + } - {page.map((row: any, key: any) => + {rows.map((row: any, key: any) => { prepareRow(row); return ( - + {row.cells.map((cell: any) => ( cell.column.type !== "hidden" && ( ) } + { + (cell.column.id === "__expander") && cell.render("cell") + } ) ))} @@ -316,6 +367,65 @@ function DataTable({ })}
+
+ } + + return ( + + {entriesPerPage && ((hidePaginationDropdown !== undefined && !hidePaginationDropdown) || canSearch) ? ( + + {entriesPerPage && (hidePaginationDropdown === undefined || !hidePaginationDropdown) && ( + + + { + if (typeof newValues === "string") + { + setEntriesPerPage(parseInt(newValues, 10)); + } + else + { + setEntriesPerPage(parseInt(newValues[0], 10)); + } + }} + size="small" + sx={{width: "5rem"}} + renderInput={(params) => } + /> + +   entries per page + + + )} + {canSearch && ( + + + { + setSearch(search); + onSearchChange(currentTarget.value); + }} + /> + + )} + + ) : null} + + { + fixedStickyLastRow ? ( + <> + {getTable(true, page.slice(0, page.length -1), false)} + {getTable(false, page.slice(page.length-1), true)} + + ) : getTable(true, page, false) + } diff --git a/src/qqq/pages/processes/ProcessRun.tsx b/src/qqq/pages/processes/ProcessRun.tsx index d0e0a0b..3206ff8 100644 --- a/src/qqq/pages/processes/ProcessRun.tsx +++ b/src/qqq/pages/processes/ProcessRun.tsx @@ -1284,6 +1284,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is { mainCardStyles.background = "none"; mainCardStyles.boxShadow = "none"; + mainCardStyles.border = "none"; mainCardStyles.minHeight = ""; mainCardStyles.alignItems = "stretch"; mainCardStyles.flexGrow = 1; diff --git a/src/qqq/pages/records/query/RecordQuery.tsx b/src/qqq/pages/records/query/RecordQuery.tsx index 7328214..ec7f813 100644 --- a/src/qqq/pages/records/query/RecordQuery.tsx +++ b/src/qqq/pages/records/query/RecordQuery.tsx @@ -2043,6 +2043,7 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element getRowId={(row) => row.__rowIndex} selectionModel={rowSelectionModel} hideFooterSelectedRowCount={true} + sx={{border: 0}} /> diff --git a/src/qqq/styles/qqq-override-styles.css b/src/qqq/styles/qqq-override-styles.css index a48a7c1..81ebe89 100644 --- a/src/qqq/styles/qqq-override-styles.css +++ b/src/qqq/styles/qqq-override-styles.css @@ -564,3 +564,14 @@ input[type="search"]::-webkit-search-results-decoration { display: none; } display: inline; right: .5rem } + +.hideScrollbars::-webkit-scrollbar { + background: transparent; /* Chrome/Safari/Webkit */ + width: 0; +} + +.hideScrollbars { + padding-right: 8px; /* pad-right for about half the width of a scrollbar.. */ + scrollbar-width: none; /* Firefox */ + -ms-overflow-style: none; /* IE 10+ */ +} \ No newline at end of file