mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-17 12:50:43 +00:00
QQQ-21: updated list table to paginate properly
This commit is contained in:
@ -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",
|
||||
|
@ -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>
|
||||
)}
|
||||
|
@ -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
57
src/qqq/utils/QClient.ts
Normal 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;
|
Reference in New Issue
Block a user