diff --git a/.eslintrc.json b/.eslintrc.json
index d35ae2b..83d4599 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -23,6 +23,8 @@
"no-console": "off",
"react/prop-types": "off",
"no-shadow": "off",
+ "no-unused-vars": "off",
+ "spaced-comment": "off",
"react/jsx-props-no-spreading": "off",
"react/react-in-jsx-scope": "off",
"import/extensions": [
diff --git a/src/qqq/components/EntityForm/index.tsx b/src/qqq/components/EntityForm/index.tsx
index 298ebe2..97a6a2f 100644
--- a/src/qqq/components/EntityForm/index.tsx
+++ b/src/qqq/components/EntityForm/index.tsx
@@ -60,17 +60,7 @@ function EntityForm({ id }: Props): JSX.Element {
setTableMetaData(tableMetaData);
if (id !== null) {
- const records = await qController.query(tableName, 250);
- let foundRecord: QRecord;
- records.forEach((innerRecord) => {
- const fieldKeys = [...innerRecord.values.keys()];
- fieldKeys.forEach((key) => {
- const value = innerRecord.values.get(key);
- if (key === tableMetaData.primaryKeyField && `${value}` === `${id}`) {
- foundRecord = innerRecord;
- }
- });
- });
+ const foundRecord = await qController.get(tableName, id);
tableMetaData.fields.forEach((fieldMetaData, key) => {
formValues[key] = foundRecord.values.get(key);
diff --git a/src/qqq/components/QDynamicForm/index.tsx b/src/qqq/components/QDynamicForm/index.tsx
new file mode 100644
index 0000000..0119315
--- /dev/null
+++ b/src/qqq/components/QDynamicForm/index.tsx
@@ -0,0 +1,162 @@
+/**
+ =========================================================
+ * Material Dashboard 2 PRO React TS - v1.0.0
+ =========================================================
+
+ * Product Page: https://www.creative-tim.com/product/material-dashboard-2-pro-react-ts
+ * Copyright 2022 Creative Tim (https://www.creative-tim.com)
+
+ 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.
+ */
+
+// @mui material components
+import Grid from "@mui/material/Grid";
+
+// Material Dashboard 2 PRO React TS components
+import MDBox from "components/MDBox";
+import MDTypography from "components/MDTypography";
+
+// NewUser page components
+import FormField from "layouts/pages/users/new-user/components/FormField";
+import { QFrontendStepMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFrontendStepMetaData";
+
+interface Props {
+ formData: any;
+ step?: QFrontendStepMetaData | undefined;
+}
+
+function QDynamicForm(props: Props): JSX.Element {
+ const { formData, step } = props;
+ const { formFields, values, errors, touched } = formData;
+
+ /*
+ const {
+ firstName: firstNameV,
+ lastName: lastNameV,
+ company: companyV,
+ email: emailV,
+ password: passwordV,
+ repeatPassword: repeatPasswordV,
+ } = values;
+ */
+
+ return (
+
+
+ {step?.label}
+ {/* TODO - help text
+
+ Mandatory information
+
+ */}
+
+
+
+ {formFields &&
+ Object.keys(formFields).length > 0 &&
+ Object.keys(formFields).map((fieldName: any) => {
+ const field = formFields[fieldName];
+ if (values[fieldName] === undefined) {
+ values[fieldName] = "";
+ }
+ return (
+
+
+
+ );
+ })}
+
+ {/*
+
+
+ 0 && !errors.firstName}
+ />
+
+
+ 0 && !errors.lastName}
+ />
+
+
+
+
+
+
+
+ 0 && !errors.email}
+ />
+
+
+
+
+ 0 && !errors.password}
+ inputProps={{ autoComplete: "" }}
+ />
+
+
+ 0 && !errors.repeatPassword}
+ inputProps={{ autoComplete: "" }}
+ />
+
+
+ */}
+
+
+ );
+}
+
+QDynamicForm.defaultProps = {
+ step: undefined,
+};
+
+export default QDynamicForm;
diff --git a/src/qqq/pages/entity-list/index.tsx b/src/qqq/pages/entity-list/index.tsx
index 0a35bb6..5d18b0d 100644
--- a/src/qqq/pages/entity-list/index.tsx
+++ b/src/qqq/pages/entity-list/index.tsx
@@ -71,7 +71,7 @@ function EntityList({ table }: Props): JSX.Element {
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: [],
@@ -170,7 +170,7 @@ function EntityList({ table }: Props): JSX.Element {
keyboard_arrow_down
)}
- {/* renderActionsMenu */}
+ {renderActionsMenu}
{
- const fieldKeys = [...innerRecord.values.keys()];
- fieldKeys.forEach((key) => {
- const value = innerRecord.values.get(key);
- if (key === tableMetaData.primaryKeyField && `${value}` === `${id}`) {
- foundRecord = innerRecord;
- }
- });
- });
+ const foundRecord = await qController.get(tableName, id);
nameValues.push(
diff --git a/src/qqq/pages/process-run/index.tsx b/src/qqq/pages/process-run/index.tsx
new file mode 100644
index 0000000..1415c9d
--- /dev/null
+++ b/src/qqq/pages/process-run/index.tsx
@@ -0,0 +1,239 @@
+/**
+ =========================================================
+ * Material Dashboard 2 PRO React TS - v1.0.0
+ =========================================================
+
+ * Product Page: https://www.creative-tim.com/product/material-dashboard-2-pro-react-ts
+ * Copyright 2022 Creative Tim (https://www.creative-tim.com)
+
+ 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.
+ */
+
+import { useReducer, useState } from "react";
+
+// formik components
+import { Formik, Form } from "formik";
+
+// @mui material components
+import Grid from "@mui/material/Grid";
+import Card from "@mui/material/Card";
+import Stepper from "@mui/material/Stepper";
+import Step from "@mui/material/Step";
+import StepLabel from "@mui/material/StepLabel";
+
+// Material Dashboard 2 PRO React TS components
+import MDBox from "components/MDBox";
+import MDButton from "components/MDButton";
+
+// Material Dashboard 2 PRO React TS examples components
+import DashboardLayout from "examples/LayoutContainers/DashboardLayout";
+import DashboardNavbar from "examples/Navbars/DashboardNavbar";
+import Footer from "examples/Footer";
+
+// ProcessRun page components
+import UserInfo from "layouts/pages/users/new-user/components/UserInfo";
+import Address from "layouts/pages/users/new-user/components/Address";
+import Socials from "layouts/pages/users/new-user/components/Socials";
+import Profile from "layouts/pages/users/new-user/components/Profile";
+
+// ProcessRun layout schemas for form and form fields
+import * as Yup from "yup";
+import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QController";
+import { QFrontendStepMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFrontendStepMetaData";
+import { useParams } from "react-router-dom";
+import QDynamicForm from "../../components/QDynamicForm";
+
+function getDynamicStepContent(stepIndex: number, stepParam: any, formData: any): JSX.Element {
+ const { formFields, values, errors, touched } = formData;
+ const { step } = stepParam;
+ // console.log(`in getDynamicStepContent: step label ${step?.label}`);
+
+ if (!Object.keys(formFields).length) {
+ console.log("in getDynamicStepContent. No fields yet, so returning 'loading'");
+ return Loading...
;
+ }
+
+ return ;
+}
+
+const qController = new QController("");
+console.log(qController);
+
+function ProcessRun(): JSX.Element {
+ const { processName } = useParams();
+ const [activeStepIndex, setActiveStepIndex] = useState(0);
+ const [activeStep, setActiveStep] = useState(null as QFrontendStepMetaData);
+ const [steps, setSteps] = useState([] as QFrontendStepMetaData[]);
+ const [loadCounter, setLoadCounter] = useState(0);
+ const [processMetaData, setProcessMetaData] = useState(null);
+ const [formId, setFormId] = useState("");
+ const [formFields, setFormFields] = useState({});
+ const [initialValues, setInitialValues] = useState({});
+ const [validations, setValidations] = useState({});
+ // const currentValidation = validations[activeStepIndex];
+ const [_, forceUpdate] = useReducer((x) => x + 1, 0);
+ const isLastStep = activeStepIndex === steps.length - 1;
+
+ console.log("In the function");
+
+ const updateActiveStep = (newIndex: number, steps: QFrontendStepMetaData[]) => {
+ console.log(`Steps are: ${steps}`);
+ console.log(`Setting step to ${newIndex}`);
+ setActiveStepIndex(newIndex);
+
+ if (steps) {
+ const activeStep = steps[newIndex];
+ setActiveStep(activeStep);
+ setFormId(activeStep.name);
+
+ const formFields: any = {};
+ const initialValues: any = {};
+ const validations: any = {};
+
+ activeStep.formFields.forEach((field) => {
+ formFields[field.name] = {
+ name: field.name,
+ label: field.label,
+ type: "text", // todo better
+ // todo invalidMsg: "Zipcode is not valid (e.g. 70000).",
+ };
+
+ // todo - not working - also, needs real value.
+ initialValues[field.name] = "Hi";
+
+ // todo - all this based on type and other metadata.
+ // see src/layouts/pages/users/new-user/schemas/validations.ts
+ validations[field.name] = Yup.string().required(`${field.label} is required.`);
+ // validations[field.name] = Yup.string().optional();
+ });
+
+ setFormFields(formFields);
+ setInitialValues(initialValues);
+ setValidations(Yup.object().shape(validations));
+ console.log(`in updateActiveStep: formFields ${JSON.stringify(formFields)}`);
+ console.log(`in updateActiveStep: initialValues ${JSON.stringify(initialValues)}`);
+ }
+ };
+
+ const doInitialLoad = async () => {
+ console.log("Starting doInitialLoad");
+ const processMetaData = await qController.loadProcessMetaData(processName);
+ console.log(processMetaData);
+ setProcessMetaData(processMetaData);
+ setSteps(processMetaData.frontendSteps);
+ updateActiveStep(0, processMetaData.frontendSteps);
+ console.log("Done with doInitialLoad");
+ };
+
+ if (loadCounter === 0) {
+ setLoadCounter(1);
+ doInitialLoad();
+ }
+
+ const sleep = (ms: any) =>
+ new Promise((resolve) => {
+ setTimeout(resolve, ms);
+ });
+ const handleBack = () => updateActiveStep(activeStepIndex - 1, processMetaData.frontendSteps);
+
+ const submitForm = async (values: any, actions: any) => {
+ await sleep(1000);
+
+ // eslint-disable-next-line no-alert
+ alert(JSON.stringify(values, null, 2));
+
+ actions.setSubmitting(false);
+ actions.resetForm();
+
+ updateActiveStep(0, processMetaData.frontendSteps);
+ };
+
+ const handleSubmit = (values: any, actions: any) => {
+ submitForm(values, actions);
+
+ // if (isLastStep) {
+ // submitForm(values, actions);
+ // } else {
+ // updateActiveStep(activeStepIndex + 1, processMetaData.frontendSteps);
+ // actions.setTouched({});
+ // actions.setSubmitting(false);
+ // }
+ };
+
+ return (
+
+
+
+
+
+
+ {({ values, errors, touched, isSubmitting }) => (
+
+ )}
+
+
+
+
+
+
+ );
+}
+
+export default ProcessRun;