ONE-38: checkpoint commit of frontend MVP goal

This commit is contained in:
Tim Chamberlain
2022-07-06 10:35:42 -05:00
parent 97a9754bcf
commit ab1009115e
15 changed files with 186 additions and 1056 deletions

View File

@ -30,7 +30,7 @@ interface Props {
function IdCell({ id, checked }: Props): JSX.Element {
const pathParts = window.location.pathname.split("/");
const tableName = pathParts[1];
const href = `/${tableName}/view/${id}/`;
const href = `/${tableName}/${id}`;
const link = <Link href={href}>{id}</Link>;
return (

View File

@ -13,10 +13,14 @@
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
/* eslint-disable no-unused-vars */
/* eslint-disable spaced-comment */
// react imports
import { useParams } from "react-router-dom";
import React, { useReducer, useState } from "react";
// qqq imports
import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QController";
import { QRecord } from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
import { QFieldType } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType";
// @material-ui core components
import Card from "@mui/material/Card";
@ -25,52 +29,36 @@ import Grid from "@mui/material/Grid";
// Material Dashboard 2 PRO React TS components
import MDBox from "components/MDBox";
import MDTypography from "components/MDTypography";
// Settings page components
import FormField from "layouts/pages/account/components/FormField";
// qqq imports
import { QTableMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QController";
import { QRecord } from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
import React, { useState } from "react";
import { QTableRecord } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableRecord";
import MDButton from "../../../components/MDButton";
const qController = new QController("");
// Declaring props types for EntityForm
interface Props {
id?: string;
}
function EntityForm({ id }: Props): JSX.Element {
const qController = new QController("");
const { tableName } = useParams();
const [asyncLoadInited, setAsyncLoadInited] = useState(false);
const [formValues, setFormValues] = useState({} as { [key: string]: string });
const [formFields, setFormFields] = useState([] as JSX.Element[]);
const defaultValues: { [key: string]: string } = {};
const [formValues, setFormValues] = useState(defaultValues);
const [loadCounter, setLoadCounter] = useState(0);
const [tableMetaData, setTableMetaData] = useState(null);
const [, forceUpdate] = useReducer((x) => x + 1, 0);
const handleInputChange = (e: { target: { name: any; value: any } }) => {
console.log("A");
const { name, value } = e.target;
console.log(name);
console.log(value);
formValues[name] = value;
setFormValues(formValues);
};
if (loadCounter === 0) {
setLoadCounter(1);
if (!asyncLoadInited) {
setAsyncLoadInited(true);
(async () => {
// await qController.loadTableMetaData(tableName).then((tableMetaData) => {
const tableMetaData = await qController.loadTableMetaData(tableName);
setTableMetaData(tableMetaData);
const formFields = [] as JSX.Element[];
// make a call to query (just get all for now, and iterate and filter like a caveman)
if (id !== null) {
const records = await qController.query(tableName, 250);
let foundRecord: QRecord;
@ -84,55 +72,56 @@ function EntityForm({ id }: Props): JSX.Element {
});
});
const sortedKeys = [...tableMetaData.fields.keys()].sort();
sortedKeys.forEach((key) => {
tableMetaData.fields.forEach((fieldMetaData, key) => {
formValues[key] = foundRecord.values.get(key);
const fieldMetaData = tableMetaData.fields.get(key);
if (fieldMetaData.name !== tableMetaData.primaryKeyField) {
if (formValues[fieldMetaData.name] == null) {
formValues[fieldMetaData.name] = "";
}
formFields.push(
<Grid item xs={12} sm={4} key={fieldMetaData.name}>
<FormField
key={fieldMetaData.name}
name={fieldMetaData.name}
id={fieldMetaData.name}
label={fieldMetaData.label}
value={formValues[fieldMetaData.name]}
onChange={handleInputChange}
/>
</Grid>
);
}
});
setLoadCounter(2);
setFormValues(formValues);
} else {
const sortedKeys = [...tableMetaData.fields.keys()].sort();
sortedKeys.forEach((key) => {
const fieldMetaData = tableMetaData.fields.get(key);
if (fieldMetaData.name !== tableMetaData.primaryKeyField) {
formFields.push(
<Grid item xs={12} sm={4} key={fieldMetaData.name}>
<FormField
key={fieldMetaData.name}
name={fieldMetaData.name}
id={fieldMetaData.name}
label={fieldMetaData.label}
value={formValues[fieldMetaData.name]}
onChange={handleInputChange}
/>
</Grid>
);
}
});
}
const sortedKeys = [...tableMetaData.fields.keys()].sort();
sortedKeys.forEach((key) => {
const fieldMetaData = tableMetaData.fields.get(key);
if (fieldMetaData.name !== tableMetaData.primaryKeyField) {
let fieldType: string;
switch (fieldMetaData.type.toString()) {
case QFieldType.DECIMAL:
case QFieldType.INTEGER:
fieldType = "number";
break;
case QFieldType.DATE_TIME:
fieldType = "datetime-local";
break;
case QFieldType.PASSWORD:
case QFieldType.TIME:
case QFieldType.DATE:
fieldType = fieldMetaData.type.toString();
break;
case QFieldType.TEXT:
case QFieldType.HTML:
case QFieldType.STRING:
default:
fieldType = "text";
}
formFields.push(
<Grid item xs={12} sm={4} key={fieldMetaData.name}>
<FormField
id={fieldMetaData.name}
key={fieldMetaData.name}
name={fieldMetaData.name}
label={fieldMetaData.label}
type={fieldType}
defaultValue={formValues[fieldMetaData.name]}
onChange={handleInputChange}
/>
</Grid>
);
}
});
setFormFields(formFields);
forceUpdate();
})();
}
@ -140,13 +129,20 @@ function EntityForm({ id }: Props): JSX.Element {
event.preventDefault();
(async () => {
await qController.create(tableName, formValues).then((record) => {
window.location.href = `/${tableName}/view/${record.values.get("id")}`; // todo - primaryKeyField
});
if (id !== null) {
await qController.update(tableName, id, formValues).then((record) => {
window.location.href = `/${tableName}/view/${record.values.get("id")}`; // todo - primaryKeyField
});
} else {
await qController.create(tableName, formValues).then((record) => {
window.location.href = `/${tableName}/view/${record.values.get("id")}`; // todo - primaryKeyField
});
}
})();
};
const pageTitle = id != null ? `Edit ${tableMetaData?.label}` : `Create ${tableMetaData?.label}`;
const pageTitle =
id != null ? `Edit ${tableMetaData?.label} (${id})` : `Create New ${tableMetaData?.label}`;
return (
<Card id="basic-info" sx={{ overflow: "visible" }}>
@ -157,6 +153,8 @@ function EntityForm({ id }: Props): JSX.Element {
<Grid key="fieldsGrid" container spacing={3}>
{formFields}
</Grid>
</MDBox>
<MDBox p={3}>
<Grid key="buttonGrid" container spacing={3}>
<MDBox ml="auto">
<MDButton type="submit" variant="gradient" color="dark" size="small">

View File

@ -39,9 +39,8 @@ import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QContr
import Link from "@mui/material/Link";
import { QTableMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import { useParams } from "react-router-dom";
import IdCell from "./components/IdCell";
import Footer from "../../components/Footer";
import EntityForm from "../../components/EntityForm";
import IdCell from "../../components/EntityForm/components/IdCell";
const qController = new QController("");
@ -69,12 +68,10 @@ function EntityList({ table }: Props): JSX.Element {
const openFiltersMenu = (event: any) => setFiltersMenu(event.currentTarget);
const closeFiltersMenu = () => setFiltersMenu(null);
const createPath = `/${tableName}/create`;
if (tableState === "") {
(async () => {
const tableMetaData = await qController.loadTableMetaData(tableName);
const metaData = await qController.loadMetaData();
// const metaData = await qController.loadMetaData();
const results = await qController.query(tableName, 250);
dataTableData = {
columns: [],
@ -160,7 +157,7 @@ function EntityList({ table }: Props): JSX.Element {
<MDBox my={3}>
<MDBox display="flex" justifyContent="space-between" alignItems="flex-start" mb={2}>
<MDButton variant="gradient" color="info">
<Link href={createPath}>new {tableName}</Link>
<Link href={`/${tableName}/create`}>new {tableName}</Link>
</MDButton>
<MDBox display="flex">
{tableProcesses.length > 0 && (
@ -173,7 +170,7 @@ function EntityList({ table }: Props): JSX.Element {
<Icon>keyboard_arrow_down</Icon>
</MDButton>
)}
{renderActionsMenu}
{/* renderActionsMenu */}
<MDBox ml={1}>
<MDButton
variant={filtersMenu ? "contained" : "outlined"}

View File

@ -13,15 +13,18 @@
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
/* eslint-disable no-unused-vars */
/* eslint-disable spaced-comment */
/* eslint-disable react/no-array-index-key */
import { useParams } from "react-router-dom";
// @material-ui core components
import Card from "@mui/material/Card";
import Grid from "@mui/material/Grid";
import Link from "@mui/material/Link";
import Dialog from "@mui/material/Dialog";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogActions from "@mui/material/DialogActions";
import Button from "@mui/material/Button";
// Material Dashboard 2 PRO React TS components
import MDBox from "components/MDBox";
@ -32,21 +35,11 @@ import MDTypography from "components/MDTypography";
// qqq imports
import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QController";
import { QRecord } from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
import React, { useState } from "react";
import React, { useReducer, useState } from "react";
import Link from "@mui/material/Link";
import Dialog from "@mui/material/Dialog";
import DialogTitle from "@mui/material/DialogTitle";
import DialogContent from "@mui/material/DialogContent";
import DialogContentText from "@mui/material/DialogContentText";
import DialogActions from "@mui/material/DialogActions";
import Button from "@mui/material/Button";
import { QTableMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
import MDButton from "../../../../../components/MDButton";
const qController = new QController("");
console.log(qController);
// Declaring props types for ViewForm
interface Props {
@ -55,32 +48,21 @@ interface Props {
function ViewContents({ id }: Props): JSX.Element {
const { tableName } = useParams();
const [asyncLoadInited, setAsyncLoadInited] = useState(false);
const [nameValues, setNameValues] = useState([] as JSX.Element[]);
const [loadCounter, setLoadCounter] = useState(0);
const [open, setOpen] = useState(false);
const [tableMetaData, setTableMetaData] = useState(null);
const [record, setRecord] = useState(null);
const [, forceUpdate] = useReducer((x) => x + 1, 0);
const handleConfirmDelete = (event: { preventDefault: () => void }) => {
event.preventDefault();
(async () => {
await qController.delete(tableName, id).then((results) => {
window.location.href = `/${tableName}/list/`;
});
})();
};
if (loadCounter === 0) {
setLoadCounter(1);
if (!asyncLoadInited) {
setAsyncLoadInited(true);
(async () => {
const tableMetaData = await qController.loadTableMetaData(tableName);
console.log("@dk: table meta data");
console.log(tableMetaData);
setTableMetaData(tableMetaData);
// make a call to query (just get all for now, and iterate and filter like a caveman)
// TODO: make a call to query (just get all for now, and iterate and filter like a caveman) - FIX!
const records = await qController.query(tableName, 250);
let foundRecord: QRecord;
records.forEach((innerRecord) => {
@ -89,7 +71,6 @@ function ViewContents({ id }: Props): JSX.Element {
const value = innerRecord.values.get(key);
if (key === tableMetaData.primaryKeyField && `${value}` === `${id}`) {
foundRecord = innerRecord;
setRecord(innerRecord);
}
});
});
@ -121,18 +102,32 @@ function ViewContents({ id }: Props): JSX.Element {
}
});
setLoadCounter(2);
setNameValues(nameValues);
forceUpdate();
})();
}
const handleConfirmDeleteOpen = () => {
// setOpen(true);
const handleClickConfirmOpen = () => {
setOpen(true);
};
const handleConfirmDeleteClose = () => {
// setOpen(false);
const handleClickConfirmClose = () => {
setOpen(false);
};
/*
const handleDelete = (event: { preventDefault: () => void }) => {
event.preventDefault();
/*
(async () => {
await qController.delete(tableName, id).then(() => {
window.location.href = `/${tableName}/list/`;
});
})();
};
*/
const editPath = `/${tableName}/edit/${id}`;
return (
@ -145,19 +140,19 @@ function ViewContents({ id }: Props): JSX.Element {
<MDBox p={3}>{nameValues}</MDBox>
<MDBox component="form" pb={3} px={3}>
<Grid key="tres" container spacing={3}>
<MDBox ml="auto" mr={5}>
<MDBox ml="auto" mr={3}>
<MDButton
type="submit"
variant="gradient"
color="primary"
size="small"
onClick={handleConfirmDelete}
onClick={handleClickConfirmOpen}
>
delete {tableMetaData?.label}
</MDButton>
<Dialog
open={open}
onClose={handleConfirmDeleteClose}
onClose={handleClickConfirmClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
@ -168,12 +163,14 @@ function ViewContents({ id }: Props): JSX.Element {
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleConfirmDeleteClose}>No</Button>
<Button onClick={handleConfirmDelete} autoFocus>
<Button onClick={handleClickConfirmClose}>No</Button>
<Button onClick={handleClickConfirmClose} autoFocus>
Yes
</Button>
</DialogActions>
</Dialog>
</MDBox>
<MDBox>
<MDButton type="submit" variant="gradient" color="dark" size="small">
<Link href={editPath}>edit {tableMetaData?.label}</Link>
</MDButton>

View File

@ -39,31 +39,8 @@
import Analytics from "layouts/dashboards/analytics";
import Sales from "layouts/dashboards/sales";
import ProfileOverview from "layouts/pages/profile/profile-overview";
// import AllProjects from "layouts/pages/profile/all-projects";
// import NewUser from "layouts/pages/users/new-user";
import Settings from "layouts/pages/account/settings";
// import Billing from "layouts/pages/account/billing";
// import Invoice from "layouts/pages/account/invoice";
// import Timeline from "layouts/pages/projects/timeline";
// import PricingPage from "layouts/pages/pricing-page";
// import Widgets from "layouts/pages/widgets";
// import RTL from "layouts/pages/rtl";
// import Charts from "layouts/pages/charts";
// import Notifications from "layouts/pages/notifications";
// import Kanban from "layouts/applications/kanban";
// import Wizard from "layouts/applications/wizard";
// import DataTables from "layouts/applications/data-tables";
// import Calendar from "layouts/applications/calendar";
// import NewProduct from "layouts/ecommerce/products/new-product";
// import EditProduct from "layouts/ecommerce/products/edit-product";
// import ProductPage from "layouts/ecommerce/products/product-page";
// import OrderList from "layouts/ecommerce/orders/order-list";
// import OrderDetails from "layouts/ecommerce/orders/order-details";
import SignInBasic from "layouts/authentication/sign-in/basic";
// import SignInCover from "layouts/authentication/sign-in/cover";
// import SignInIllustration from "layouts/authentication/sign-in/illustration";
// import SignUpCover from "layouts/authentication/sign-up/cover";
// import ResetCover from "layouts/authentication/reset-password/cover";
// Material Dashboard 2 PRO React TS components
import MDAvatar from "components/MDAvatar";
@ -76,16 +53,8 @@ import profilePicture from "assets/images/team-3.jpg";
// QQQ
import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QController";
import EntityList from "./pages/entity-list";
// import { QTableMetaData } from "qqq-frontend-core/lib/model/metaData/QTableMetaData";
// import thing from "qqq-frontend-core/lib/qqq-frontend-core.js";
// import QController from "qqq-frontend-core/lib/qqq-frontend-core.js";
// import {QTableMetaData} from "qqq-frontend-core/lib/model/metaData/QTableMetaData";
// import {QFieldMetaData} from "qqq-frontend-core/lib/model/metaData/QFieldMetaData";
// import {QFieldType} from "qqq-frontend-core/lib/model/metaData/QFieldType";
const qqqRoutes = [
{
type: "collapse",
@ -134,260 +103,11 @@ const qqqRoutes = [
},
],
},
/*
{ type: "title", title: "Pages", key: "title-pages" },
{
type: "collapse",
name: "Pages",
key: "pages",
icon: <Icon fontSize="medium">image</Icon>,
collapse: [
{
name: "Profile",
key: "profile",
collapse: [
{
name: "Profile Overview",
key: "profile-overview",
route: "/pages/profile/profile-overview",
component: <ProfileOverview />,
},
{
name: "All Projects",
key: "all-projects",
route: "/pages/profile/all-projects",
component: <AllProjects />,
},
],
},
{
name: "Users",
key: "users",
collapse: [
{
name: "New User",
key: "new-user",
route: "/pages/users/new-user",
component: <NewUser />,
},
],
},
{
name: "Account",
key: "account",
collapse: [
{
name: "Settings",
key: "settings",
route: "/pages/account/settings",
component: <Settings />,
},
{
name: "Billing",
key: "billing",
route: "/pages/account/billing",
component: <Billing />,
},
{
name: "Invoice",
key: "invoice",
route: "/pages/account/invoice",
component: <Invoice />,
},
],
},
{
name: "Projects",
key: "projects",
collapse: [
{
name: "Timeline",
key: "timeline",
route: "/pages/projects/timeline",
component: <Timeline />,
},
],
},
{
name: "Pricing Page",
key: "pricing-page",
route: "/pages/pricing-page",
component: <PricingPage />,
},
{ name: "RTL", key: "rtl", route: "/pages/rtl", component: <RTL /> },
{ name: "Widgets", key: "widgets", route: "/pages/widgets", component: <Widgets /> },
{ name: "Charts", key: "charts", route: "/pages/charts", component: <Charts /> },
{
name: "Notfications",
key: "notifications",
route: "/pages/notifications",
component: <Notifications />,
},
],
},
{
type: "collapse",
name: "Applications",
key: "applications",
icon: <Icon fontSize="medium">apps</Icon>,
collapse: [
{
name: "Kanban",
key: "kanban",
route: "/applications/kanban",
component: <Kanban />,
},
{
name: "Wizard",
key: "wizard",
route: "/applications/wizard",
component: <Wizard />,
},
{
name: "Data Tables",
key: "data-tables",
route: "/applications/data-tables",
component: <DataTables />,
},
{
name: "Calendar",
key: "calendar",
route: "/applications/calendar",
component: <Calendar />,
},
],
},
{
type: "collapse",
name: "Ecommerce",
key: "ecommerce",
icon: <Icon fontSize="medium">shopping_basket</Icon>,
collapse: [
{
name: "Products",
key: "products",
collapse: [
{
name: "New Product",
key: "new-product",
route: "/ecommerce/products/new-product",
component: <NewProduct />,
},
{
name: "Edit Product",
key: "edit-product",
route: "/ecommerce/products/edit-product",
component: <EditProduct />,
},
{
name: "Product Page",
key: "product-page",
route: "/ecommerce/products/product-page",
component: <ProductPage />,
},
],
},
{
name: "Orders",
key: "orders",
collapse: [
{
name: "Order List",
key: "order-list",
route: "/ecommerce/orders/order-list",
component: <OrderList />,
},
{
name: "Order Details",
key: "order-details",
route: "/ecommerce/orders/order-details",
component: <OrderDetails />,
},
],
},
{
name: "Orders",
key: "orders",
collapse: [
{
name: "Order List",
key: "order-list",
route: "/ecommerce/orders/order-list",
component: <OrderList />,
},
{
name: "Order Details",
key: "order-details",
route: "/ecommerce/orders/order-details",
component: <OrderDetails />,
},
],
},
],
},
{
type: "collapse",
name: "Authentication",
key: "authentication",
icon: <Icon fontSize="medium">content_paste</Icon>,
collapse: [
{
name: "Sign In",
key: "sign-in",
collapse: [
{
name: "Basic",
key: "basic",
route: "/authentication/sign-in/basic",
component: <SignInBasic />,
},
{
name: "Cover",
key: "cover",
route: "/authentication/sign-in/cover",
component: <SignInCover />,
},
{
name: "Illustration",
key: "illustration",
route: "/authentication/sign-in/illustration",
component: <SignInIllustration />,
},
],
},
{
name: "Sign Up",
key: "sign-up",
collapse: [
{
name: "Cover",
key: "cover",
route: "/authentication/sign-up/cover",
component: <SignUpCover />,
},
],
},
{
name: "Reset Password",
key: "reset-password",
collapse: [
{
name: "Cover",
key: "cover",
route: "/authentication/reset-password/cover",
component: <ResetCover />,
},
],
},
],
},
*/
{ type: "divider", key: "divider-1" },
{ type: "title", title: "Tables", key: "title-docs" },
];
const qController = new QController("");
console.log(qController);
(async () => {
const metaData = await qController.loadMetaData();
@ -398,9 +118,9 @@ console.log(qController);
keys.forEach((key) => {
const table = metaData.tables.get(key);
tableList.push({
name: table.label,
name: `${table.label}`,
key: table.name,
route: `/${table.name}/list`,
route: `/${table.name}`,
component: <EntityList table={table} />,
});
});