QQQ-21: updated list table to paginate properly

This commit is contained in:
Tim Chamberlain
2022-07-08 15:37:55 -05:00
parent 34c7f84ec6
commit de365708b3
4 changed files with 171 additions and 66 deletions

View File

@ -16,6 +16,7 @@
"@mui/icons-material": "5.4.1",
"@mui/material": "5.4.1",
"@mui/styled-engine": "5.4.1",
"@mui/x-data-grid": "5.13.0",
"@react-jvectormap/core": "1.0.1",
"@react-jvectormap/world": "1.0.0",
"@testing-library/jest-dom": "5.16.2",

View File

@ -100,7 +100,7 @@ function EntityForm({ id }: Props): JSX.Element {
})();
};
const pageTitle =
const formTitle =
id != null ? `Edit ${tableMetaData?.label} (${id})` : `Create New ${tableMetaData?.label}`;
const formId =
id != null ? `edit-${tableMetaData?.label}-form` : `create-${tableMetaData?.label}-form`;
@ -108,7 +108,7 @@ function EntityForm({ id }: Props): JSX.Element {
return (
<Card id="edit-form-container" sx={{ overflow: "visible" }}>
<MDBox p={3}>
<MDTypography variant="h5">{pageTitle}</MDTypography>
<MDTypography variant="h5">{formTitle}</MDTypography>
</MDBox>
<MDBox pb={3} px={3}>
<Grid key="fields-grid" container spacing={3}>
@ -120,24 +120,22 @@ function EntityForm({ id }: Props): JSX.Element {
{({ values, errors, touched, isSubmitting }) => (
<Form id={formId} autoComplete="off">
<MDBox p={3} width="100%">
<MDBox>
{/***************************************************************************
** step content - e.g., the appropriate form or other screen for the step **
***************************************************************************/}
{getDynamicStepContent({
values,
touched,
formFields,
errors,
})}
<Grid key="buttonGrid" container spacing={3}>
<MDBox mt={5} ml="auto">
<MDButton type="submit" variant="gradient" color="dark" size="small">
save {tableMetaData?.label}
</MDButton>
</MDBox>
</Grid>
</MDBox>
{/***************************************************************************
** step content - e.g., the appropriate form or other screen for the step **
***************************************************************************/}
{getDynamicStepContent({
values,
touched,
formFields,
errors,
})}
<Grid key="buttonGrid" container spacing={3}>
<MDBox mt={5} ml="auto">
<MDButton type="submit" variant="gradient" color="dark" size="small">
save {tableMetaData?.label}
</MDButton>
</MDBox>
</Grid>
</MDBox>
</Form>
)}

View File

@ -14,7 +14,7 @@
*/
/* eslint-disable react/no-unstable-nested-components */
import React, { useState } from "react";
import React, { useEffect, useReducer, useState } from "react";
// @mui material components
import Card from "@mui/material/Card";
@ -23,82 +23,108 @@ import Menu from "@mui/material/Menu";
import MenuItem from "@mui/material/MenuItem";
import Divider from "@mui/material/Divider";
import Link from "@mui/material/Link";
// Material Dashboard 2 PRO React TS examples components
import DashboardLayout from "examples/LayoutContainers/DashboardLayout";
import DashboardNavbar from "examples/Navbars/DashboardNavbar";
import DataTable from "examples/Tables/DataTable";
// QQQ
import { QProcessMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData";
import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QController";
import { QTableMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import { useParams } from "react-router-dom";
import DynamicFormUtils from "qqq/components/QDynamicForm/utils/DynamicFormUtils";
import { makeStyles } from "@mui/material";
import { DataGrid, GridColDef, GridRowParams, GridRowsProp } from "@mui/x-data-grid";
// Material Dashboard 2 PRO React TS components
import DashboardLayout from "examples/LayoutContainers/DashboardLayout";
import DashboardNavbar from "examples/Navbars/DashboardNavbar";
import MDBox from "components/MDBox";
import MDTypography from "components/MDTypography";
import MDButton from "components/MDButton";
import Footer from "../../components/Footer";
import IdCell from "../../components/EntityForm/components/IdCell";
const qController = new QController("");
// QQQ
import { QProcessMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData";
import { QTableMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import { useParams } from "react-router-dom";
import QClient from "qqq/utils/QClient";
import Footer from "../../components/Footer";
// Declaring props types for DefaultCell
interface Props {
table?: QTableMetaData;
}
let dataTableData = {
columns: [] as any[],
rows: [] as any[],
};
function EntityList({ table }: Props): JSX.Element {
const tableNameParam = useParams().tableName;
const tableName = table === null ? tableNameParam : table.name;
const [tableState, setTableState] = useState("");
const [filtersMenu, setFiltersMenu] = useState(null);
const [actionsMenu, setActionsMenu] = useState(null);
const [tableState, setTableState] = useState("");
const [tableProcesses, setTableProcesses] = useState([] as QProcessMetaData[]);
console.log(tableState);
const [pageNumber, setPageNumber] = useState(1);
const [totalRecords, setTotalRecords] = useState(0);
const [rowsPerPage, setRowsPerPage] = useState(10);
const [columns, setColumns] = useState([] as GridColDef[]);
const [rows, setRows] = useState([] as GridRowsProp[]);
const [loading, setLoading] = useState(true);
const [, forceUpdate] = useReducer((x) => x + 1, 0);
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
const closeActionsMenu = () => setActionsMenu(null);
const openFiltersMenu = (event: any) => setFiltersMenu(event.currentTarget);
const closeFiltersMenu = () => setFiltersMenu(null);
if (tableState === "") {
console.log("DERPSSS");
console.log(`hoc${tableState}`);
const updateTable = () => {
(async () => {
const tableMetaData = await qController.loadTableMetaData(tableName);
const metaData = await qController.loadMetaData();
const results = await qController.query(tableName, 250);
dataTableData = {
columns: [],
rows: [],
};
const tableMetaData = await QClient.loadTableMetaData(tableName);
const count = await QClient.count(tableName);
setTotalRecords(count);
const columns = [] as GridColDef[];
const results = await QClient.query(tableName, rowsPerPage, pageNumber * rowsPerPage);
const rows = [] as any[];
results.forEach((record) => {
rows.push(Object.fromEntries(record.values.entries()));
});
const sortedKeys = [...tableMetaData.fields.keys()].sort();
sortedKeys.forEach((key) => {
const field = tableMetaData.fields.get(key);
const column = {
field: field.name,
headerName: field.label,
width: 200,
};
if (key === tableMetaData.primaryKeyField) {
dataTableData.columns.splice(0, 0, {
Header: field.label,
accessor: key,
Cell: ({ value }: any) => <IdCell id={value} />,
});
columns.splice(0, 0, column);
} else {
dataTableData.columns.push({
Header: field.label,
accessor: key,
});
columns.push(column);
}
});
results.forEach((record) => {
dataTableData.rows.push(Object.fromEntries(record.values.entries()));
});
setColumns(columns);
setRows(rows);
setLoading(false);
forceUpdate();
})();
};
const handlePageChange = (page: number) => {
setPageNumber(page);
};
const handleRowsPerPageChange = (size: number) => {
setRowsPerPage(size);
};
const handleRowClick = (params: GridRowParams) => {
document.location.href = `/${tableName}/${params.id}`;
};
if (tableName !== tableState) {
(async () => {
console.log("DDDDDDDDDDDDOOOOOOOOOOO ITTTTTTTTTTTT");
setTableState(tableName);
const metaData = await QClient.loadMetaData();
const matchingProcesses: QProcessMetaData[] = [];
const processKeys = [...metaData.processes.keys()];
@ -110,7 +136,8 @@ function EntityList({ table }: Props): JSX.Element {
});
setTableProcesses(matchingProcesses);
setTableState(tableName);
// reset rows to trigger rerender
setRows([]);
})();
}
@ -152,6 +179,10 @@ function EntityList({ table }: Props): JSX.Element {
</Menu>
);
useEffect(() => {
updateTable();
}, [pageNumber, rowsPerPage, tableState]);
return (
<DashboardLayout>
<DashboardNavbar />
@ -192,7 +223,26 @@ function EntityList({ table }: Props): JSX.Element {
</MDBox>
</MDBox>
<Card>
<DataTable table={dataTableData} entriesPerPage={false} canSearch />
<MDBox height="100%">
<DataGrid
page={pageNumber}
checkboxSelection
disableSelectionOnClick
autoHeight
rows={rows}
columns={columns}
rowBuffer={10}
rowCount={totalRecords}
pageSize={rowsPerPage}
rowsPerPageOptions={[10, 25, 50]}
onPageSizeChange={handleRowsPerPageChange}
onPageChange={handlePageChange}
onRowClick={handleRowClick}
paginationMode="server"
density="compact"
loading={loading}
/>
</MDBox>
</Card>
</MDBox>
<Footer />
@ -200,7 +250,6 @@ function EntityList({ table }: Props): JSX.Element {
);
}
// Declaring default props for DefaultCell
EntityList.defaultProps = {
table: null,
};

57
src/qqq/utils/QClient.ts Normal file
View File

@ -0,0 +1,57 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import { QFieldMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QController";
/*******************************************************************************
** client wrapper of qqq backend
**
*******************************************************************************/
class QClient {
private static qController: QController;
private static getInstance() {
if (this.qController == null) {
this.qController = new QController("");
}
return this.qController;
}
public static loadTableMetaData(tableName: string) {
return this.getInstance().loadTableMetaData(tableName);
}
public static loadMetaData() {
return this.getInstance().loadMetaData();
}
public static query(tableName: string, limit: number, skip: number) {
return this.getInstance().query(tableName, limit, skip);
}
public static count(tableName: string) {
return this.getInstance().count(tableName);
}
}
export default QClient;