Update to get back processes in metaData; add actions menu to entity-list; fix routing directly to entity lists

This commit is contained in:
2022-07-05 15:35:37 -05:00
parent e834c60bda
commit 97a9754bcf
4 changed files with 121 additions and 107 deletions

View File

@ -13,14 +13,7 @@ Coded by www.creative-tim.com
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/ */
import React, { import React, { useState, useEffect, JSXElementConstructor, Key, ReactElement } from "react";
useState,
useEffect,
useMemo,
JSXElementConstructor,
Key,
ReactElement,
} from "react";
// react-router components // react-router components
import { Routes, Route, Navigate, useLocation } from "react-router-dom"; import { Routes, Route, Navigate, useLocation } from "react-router-dom";
@ -39,15 +32,12 @@ import Configurator from "examples/Configurator";
// Material Dashboard 2 PRO React TS themes // Material Dashboard 2 PRO React TS themes
import theme from "assets/theme"; import theme from "assets/theme";
import themeRTL from "assets/theme/theme-rtl";
// Material Dashboard 2 PRO React TS Dark Mode themes // Material Dashboard 2 PRO React TS Dark Mode themes
import themeDark from "assets/theme-dark"; import themeDark from "assets/theme-dark";
import themeDarkRTL from "assets/theme-dark/theme-rtl";
// RTL plugins // RTL plugins
import rtlPlugin from "stylis-plugin-rtl"; import rtlPlugin from "stylis-plugin-rtl";
import { CacheProvider } from "@emotion/react";
import createCache from "@emotion/cache"; import createCache from "@emotion/cache";
// Material Dashboard 2 PRO React TS routes // Material Dashboard 2 PRO React TS routes
@ -60,8 +50,10 @@ import { useMaterialUIController, setMiniSidenav, setOpenConfigurator } from "co
import brandWhite from "assets/images/logo-ct.png"; import brandWhite from "assets/images/logo-ct.png";
import brandDark from "assets/images/logo-ct-dark.png"; import brandDark from "assets/images/logo-ct-dark.png";
import EntityCreate from "./qqq/pages/entity-create"; import EntityCreate from "./qqq/pages/entity-create";
import EntityList from "./qqq/pages/entity-list";
import EntityView from "./qqq/pages/entity-view"; import EntityView from "./qqq/pages/entity-view";
import EntityEdit from "./qqq/pages/entity-edit"; import EntityEdit from "./qqq/pages/entity-edit";
import ProcessRun from "./qqq/pages/process-run";
export default function App() { export default function App() {
const [controller, dispatch] = useMaterialUIController(); const [controller, dispatch] = useMaterialUIController();
@ -76,20 +68,8 @@ export default function App() {
darkMode, darkMode,
} = controller; } = controller;
const [onMouseEnter, setOnMouseEnter] = useState(false); const [onMouseEnter, setOnMouseEnter] = useState(false);
const [rtlCache, setRtlCache] = useState(null);
const { pathname } = useLocation(); const { pathname } = useLocation();
// Cache for the rtl
useMemo(() => {
const pluginRtl: any = rtlPlugin;
const cacheRtl = createCache({
key: "rtl",
stylisPlugins: [pluginRtl],
});
setRtlCache(cacheRtl);
}, []);
// Open sidenav when mouse enter on mini sidenav // Open sidenav when mouse enter on mini sidenav
const handleOnMouseEnter = () => { const handleOnMouseEnter = () => {
if (miniSidenav && !onMouseEnter) { if (miniSidenav && !onMouseEnter) {
@ -164,39 +144,13 @@ export default function App() {
</MDBox> </MDBox>
); );
const entityListElement = <EntityList />;
const entityCreateElement = <EntityCreate />; const entityCreateElement = <EntityCreate />;
const entityViewElement = <EntityView />; const entityViewElement = <EntityView />;
const entityEditElement = <EntityEdit />; const entityEditElement = <EntityEdit />;
const processRunElement = <ProcessRun />;
return direction === "rtl" ? ( return (
<CacheProvider value={rtlCache}>
<ThemeProvider theme={darkMode ? themeDarkRTL : themeRTL}>
<CssBaseline />
{layout === "dashboard" && (
<>
<Sidenav
color={sidenavColor}
brand={(transparentSidenav && !darkMode) || whiteSidenav ? brandDark : brandWhite}
brandName="Material Dashboard PRO"
routes={routes}
onMouseEnter={handleOnMouseEnter}
onMouseLeave={handleOnMouseLeave}
/>
<Configurator />
{configsButton}
</>
)}
{layout === "vr" && <Configurator />}
<Routes>
<Route path="*" element={<Navigate to="/dashboards/analytics" />} />
<Route path="/:tableName/create" element={entityCreateElement} key="entity-create" />;
<Route path="/:tableName/view/:id" element={entityViewElement} key="entity-view" />;
<Route path="/:tableName/edit/:id" element={entityEditElement} key="entity-edit" />;
{getRoutes(routes)}
</Routes>
</ThemeProvider>
</CacheProvider>
) : (
<ThemeProvider theme={darkMode ? themeDark : theme}> <ThemeProvider theme={darkMode ? themeDark : theme}>
<CssBaseline /> <CssBaseline />
{layout === "dashboard" && ( {layout === "dashboard" && (
@ -216,9 +170,11 @@ export default function App() {
{layout === "vr" && <Configurator />} {layout === "vr" && <Configurator />}
<Routes> <Routes>
<Route path="*" element={<Navigate to="/dashboards/analytics" />} /> <Route path="*" element={<Navigate to="/dashboards/analytics" />} />
<Route path="/:tableName/list" element={entityListElement} key="entity-list" />;
<Route path="/:tableName/create" element={entityCreateElement} key="entity-create" />; <Route path="/:tableName/create" element={entityCreateElement} key="entity-create" />;
<Route path="/:tableName/view/:id" element={entityViewElement} key="entity-view" />; <Route path="/:tableName/view/:id" element={entityViewElement} key="entity-view" />;
<Route path="/:tableName/edit/:id" element={entityEditElement} key="entity-edit" />; <Route path="/:tableName/edit/:id" element={entityEditElement} key="entity-edit" />;
<Route path="/processes/:processName" element={processRunElement} key="process-run" />;
{getRoutes(routes)} {getRoutes(routes)}
</Routes> </Routes>
</ThemeProvider> </ThemeProvider>

View File

@ -34,18 +34,20 @@ import DashboardNavbar from "examples/Navbars/DashboardNavbar";
import DataTable from "examples/Tables/DataTable"; import DataTable from "examples/Tables/DataTable";
// Data // Data
import { QProcessMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData";
import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QController"; import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QController";
import Link from "@mui/material/Link"; import Link from "@mui/material/Link";
import { QTableMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData"; import { QTableMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import { useParams } from "react-router-dom";
import IdCell from "./components/IdCell"; import IdCell from "./components/IdCell";
import Footer from "../../components/Footer"; import Footer from "../../components/Footer";
import EntityForm from "../../components/EntityForm";
const qController = new QController(""); const qController = new QController("");
console.log(qController);
// Declaring props types for DefaultCell // Declaring props types for DefaultCell
interface Props { interface Props {
table: QTableMetaData; table?: QTableMetaData;
} }
let dataTableData = { let dataTableData = {
@ -54,62 +56,97 @@ let dataTableData = {
}; };
function EntityList({ table }: Props): JSX.Element { function EntityList({ table }: Props): JSX.Element {
const [menu, setMenu] = useState(null); const tableNameParam = useParams().tableName;
const tableName = table === null ? tableNameParam : table.name;
const [filtersMenu, setFiltersMenu] = useState(null);
const [actionsMenu, setActionsMenu] = useState(null);
const [tableState, setTableState] = useState(""); const [tableState, setTableState] = useState("");
const [tableProcesses, setTableProcesses] = useState([] as QProcessMetaData[]);
console.log(tableState); console.log(tableState);
const newEntity = (event: any) => setMenu(event.currentTarget); const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
const openMenu = (event: any) => setMenu(event.currentTarget); const closeActionsMenu = () => setActionsMenu(null);
const closeMenu = () => setMenu(null); const openFiltersMenu = (event: any) => setFiltersMenu(event.currentTarget);
const closeFiltersMenu = () => setFiltersMenu(null);
const createPath = `/${table.name}/create`; const createPath = `/${tableName}/create`;
(async () => { if (tableState === "") {
const tableMetaData = await qController.loadTableMetaData(table.name); (async () => {
const results = await qController.query(table.name, 250); const tableMetaData = await qController.loadTableMetaData(tableName);
dataTableData = { const metaData = await qController.loadMetaData();
columns: [], const results = await qController.query(tableName, 250);
rows: [], dataTableData = {
}; columns: [],
rows: [],
};
const sortedKeys = [...tableMetaData.fields.keys()].sort(); const sortedKeys = [...tableMetaData.fields.keys()].sort();
sortedKeys.forEach((key) => { sortedKeys.forEach((key) => {
const field = tableMetaData.fields.get(key); const field = tableMetaData.fields.get(key);
if (key === tableMetaData.primaryKeyField) { if (key === tableMetaData.primaryKeyField) {
dataTableData.columns.splice(0, 0, { dataTableData.columns.splice(0, 0, {
Header: field.label, Header: field.label,
accessor: key, accessor: key,
Cell: ({ value }: any) => <IdCell id={value} />, Cell: ({ value }: any) => <IdCell id={value} />,
}); });
} else { } else {
dataTableData.columns.push({ dataTableData.columns.push({
Header: field.label, Header: field.label,
accessor: key, accessor: key,
}); });
} }
}); });
results.forEach((record) => { results.forEach((record) => {
dataTableData.rows.push(Object.fromEntries(record.values.entries())); dataTableData.rows.push(Object.fromEntries(record.values.entries()));
}); });
setTableState(table.name); const matchingProcesses: QProcessMetaData[] = [];
})(); const processKeys = [...metaData.processes.keys()];
processKeys.forEach((key) => {
const process = metaData.processes.get(key);
if (process.tableName === tableName) {
matchingProcesses.push(process);
}
});
setTableProcesses(matchingProcesses);
const renderMenu = ( setTableState(tableName);
})();
}
const renderActionsMenu = (
<Menu <Menu
anchorEl={menu} anchorEl={actionsMenu}
anchorOrigin={{ vertical: "bottom", horizontal: "left" }} anchorOrigin={{ vertical: "bottom", horizontal: "left" }}
transformOrigin={{ vertical: "top", horizontal: "left" }} transformOrigin={{ vertical: "top", horizontal: "left" }}
open={Boolean(menu)} open={Boolean(actionsMenu)}
onClose={closeMenu} onClose={closeActionsMenu}
keepMounted keepMounted
> >
<MenuItem onClick={closeMenu}>Status: Paid</MenuItem> {tableProcesses.map((process) => (
<MenuItem onClick={closeMenu}>Status: Refunded</MenuItem> <MenuItem key={process.name}>
<MenuItem onClick={closeMenu}>Status: Canceled</MenuItem> <Link href={`/processes/${process.name}`}>{process.label}</Link>
</MenuItem>
))}
</Menu>
);
const renderFiltersMenu = (
<Menu
anchorEl={filtersMenu}
anchorOrigin={{ vertical: "bottom", horizontal: "left" }}
transformOrigin={{ vertical: "top", horizontal: "left" }}
open={Boolean(filtersMenu)}
onClose={closeFiltersMenu}
keepMounted
>
<MenuItem onClick={closeFiltersMenu}>Status: Paid</MenuItem>
<MenuItem onClick={closeFiltersMenu}>Status: Refunded</MenuItem>
<MenuItem onClick={closeFiltersMenu}>Status: Canceled</MenuItem>
<Divider sx={{ margin: "0.5rem 0" }} /> <Divider sx={{ margin: "0.5rem 0" }} />
<MenuItem onClick={closeMenu}> <MenuItem onClick={closeFiltersMenu}>
<MDTypography variant="button" color="error" fontWeight="regular"> <MDTypography variant="button" color="error" fontWeight="regular">
Remove Filter Remove Filter
</MDTypography> </MDTypography>
@ -122,15 +159,32 @@ function EntityList({ table }: Props): JSX.Element {
<DashboardNavbar /> <DashboardNavbar />
<MDBox my={3}> <MDBox my={3}>
<MDBox display="flex" justifyContent="space-between" alignItems="flex-start" mb={2}> <MDBox display="flex" justifyContent="space-between" alignItems="flex-start" mb={2}>
<MDButton variant="gradient" color="info" onClick={newEntity}> <MDButton variant="gradient" color="info">
<Link href={createPath}>new {table.label}</Link> <Link href={createPath}>new {tableName}</Link>
</MDButton> </MDButton>
<MDBox display="flex"> <MDBox display="flex">
<MDButton variant={menu ? "contained" : "outlined"} color="dark" onClick={openMenu}> {tableProcesses.length > 0 && (
filters&nbsp; <MDButton
<Icon>keyboard_arrow_down</Icon> variant={actionsMenu ? "contained" : "outlined"}
</MDButton> color="dark"
{renderMenu} onClick={openActionsMenu}
>
actions&nbsp;
<Icon>keyboard_arrow_down</Icon>
</MDButton>
)}
{renderActionsMenu}
<MDBox ml={1}>
<MDButton
variant={filtersMenu ? "contained" : "outlined"}
color="dark"
onClick={openFiltersMenu}
>
filters&nbsp;
<Icon>keyboard_arrow_down</Icon>
</MDButton>
{renderFiltersMenu}
</MDBox>
<MDBox ml={1}> <MDBox ml={1}>
<MDButton variant="outlined" color="dark"> <MDButton variant="outlined" color="dark">
<Icon>description</Icon> <Icon>description</Icon>
@ -148,4 +202,9 @@ function EntityList({ table }: Props): JSX.Element {
); );
} }
// Declaring default props for DefaultCell
EntityList.defaultProps = {
table: null,
};
export default EntityList; export default EntityList;

View File

@ -391,13 +391,12 @@ console.log(qController);
(async () => { (async () => {
const metaData = await qController.loadMetaData(); const metaData = await qController.loadMetaData();
console.log(`metaData: ${metaData}`);
// get the keys sorted // get the keys sorted
const keys = [...metaData.keys()].sort(); const keys = [...metaData.tables.keys()].sort();
const tableList = [] as any[]; const tableList = [] as any[];
keys.forEach((key) => { keys.forEach((key) => {
const table = metaData.get(key); const table = metaData.tables.get(key);
tableList.push({ tableList.push({
name: table.label, name: table.label,
key: table.name, key: table.name,

View File

@ -554,8 +554,8 @@ console.log(qController);
console.log(`metaData: ${metaData}`); console.log(`metaData: ${metaData}`);
const tableList = [] as any[]; const tableList = [] as any[];
metaData.forEach((value, key) => { metaData.tables.forEach((value, key) => {
const table = metaData.get(key); const table = metaData.tables.get(key);
console.log(`TABLE: ${table}`); console.log(`TABLE: ${table}`);
tableList.push({ tableList.push({
name: table.label, name: table.label,