mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-18 05:10:45 +00:00
QQQ-21 show records on process screen
This commit is contained in:
@ -24,7 +24,15 @@ import MenuItem from "@mui/material/MenuItem";
|
|||||||
import Divider from "@mui/material/Divider";
|
import Divider from "@mui/material/Divider";
|
||||||
import Link from "@mui/material/Link";
|
import Link from "@mui/material/Link";
|
||||||
import { makeStyles } from "@mui/material";
|
import { makeStyles } from "@mui/material";
|
||||||
import { DataGrid, GridColDef, GridRowParams, GridRowsProp } from "@mui/x-data-grid";
|
import {
|
||||||
|
DataGrid,
|
||||||
|
GridCallbackDetails,
|
||||||
|
GridColDef,
|
||||||
|
GridRowId,
|
||||||
|
GridRowParams,
|
||||||
|
GridRowsProp,
|
||||||
|
GridSelectionModel,
|
||||||
|
} from "@mui/x-data-grid";
|
||||||
|
|
||||||
// Material Dashboard 2 PRO React TS components
|
// Material Dashboard 2 PRO React TS components
|
||||||
import DashboardLayout from "examples/LayoutContainers/DashboardLayout";
|
import DashboardLayout from "examples/LayoutContainers/DashboardLayout";
|
||||||
@ -39,6 +47,7 @@ import { QTableMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/
|
|||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import QClient from "qqq/utils/QClient";
|
import QClient from "qqq/utils/QClient";
|
||||||
import Footer from "../../components/Footer";
|
import Footer from "../../components/Footer";
|
||||||
|
import QProcessUtils from "../../utils/QProcessUtils";
|
||||||
|
|
||||||
// Declaring props types for DefaultCell
|
// Declaring props types for DefaultCell
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -56,6 +65,7 @@ function EntityList({ table }: Props): JSX.Element {
|
|||||||
const [pageNumber, setPageNumber] = useState(0);
|
const [pageNumber, setPageNumber] = useState(0);
|
||||||
const [totalRecords, setTotalRecords] = useState(0);
|
const [totalRecords, setTotalRecords] = useState(0);
|
||||||
const [rowsPerPage, setRowsPerPage] = useState(10);
|
const [rowsPerPage, setRowsPerPage] = useState(10);
|
||||||
|
const [selectedIds, setSelectedIds] = useState([] as string[]);
|
||||||
const [columns, setColumns] = useState([] as GridColDef[]);
|
const [columns, setColumns] = useState([] as GridColDef[]);
|
||||||
const [rows, setRows] = useState([] as GridRowsProp[]);
|
const [rows, setRows] = useState([] as GridRowsProp[]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
@ -117,26 +127,33 @@ function EntityList({ table }: Props): JSX.Element {
|
|||||||
document.location.href = `/${tableName}/${params.id}`;
|
document.location.href = `/${tableName}/${params.id}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const selectionChanged = (selectionModel: GridSelectionModel, details: GridCallbackDetails) => {
|
||||||
|
const newSelectedIds: string[] = [];
|
||||||
|
selectionModel.forEach((value: GridRowId) => {
|
||||||
|
newSelectedIds.push(value as string);
|
||||||
|
});
|
||||||
|
setSelectedIds(newSelectedIds);
|
||||||
|
};
|
||||||
|
|
||||||
if (tableName !== tableState) {
|
if (tableName !== tableState) {
|
||||||
(async () => {
|
(async () => {
|
||||||
setTableState(tableName);
|
setTableState(tableName);
|
||||||
const metaData = await QClient.loadMetaData();
|
const metaData = await QClient.loadMetaData();
|
||||||
|
|
||||||
const matchingProcesses: QProcessMetaData[] = [];
|
setTableProcesses(QProcessUtils.getProcessesForTable(metaData, tableName));
|
||||||
const processKeys = [...metaData.processes.keys()];
|
|
||||||
processKeys.forEach((key) => {
|
|
||||||
const process = metaData.processes.get(key);
|
|
||||||
if (process.tableName === tableName) {
|
|
||||||
matchingProcesses.push(process);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setTableProcesses(matchingProcesses);
|
|
||||||
|
|
||||||
// reset rows to trigger rerender
|
// reset rows to trigger rerender
|
||||||
setRows([]);
|
setRows([]);
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRecordsQueryString() {
|
||||||
|
if (selectedIds.length > 0) {
|
||||||
|
return `?recordsParam=recordIds&recordIds=${selectedIds.join(",")}`;
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
const renderActionsMenu = (
|
const renderActionsMenu = (
|
||||||
<Menu
|
<Menu
|
||||||
anchorEl={actionsMenu}
|
anchorEl={actionsMenu}
|
||||||
@ -148,7 +165,7 @@ function EntityList({ table }: Props): JSX.Element {
|
|||||||
>
|
>
|
||||||
{tableProcesses.map((process) => (
|
{tableProcesses.map((process) => (
|
||||||
<MenuItem key={process.name}>
|
<MenuItem key={process.name}>
|
||||||
<Link href={`/processes/${process.name}`}>{process.label}</Link>
|
<Link href={`/processes/${process.name}${getRecordsQueryString()}`}>{process.label}</Link>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
))}
|
))}
|
||||||
</Menu>
|
</Menu>
|
||||||
@ -237,6 +254,7 @@ function EntityList({ table }: Props): JSX.Element {
|
|||||||
paginationMode="server"
|
paginationMode="server"
|
||||||
density="compact"
|
density="compact"
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
onSelectionModelChange={selectionChanged}
|
||||||
/>
|
/>
|
||||||
</MDBox>
|
</MDBox>
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -30,11 +30,16 @@ import Button from "@mui/material/Button";
|
|||||||
|
|
||||||
// qqq imports
|
// qqq imports
|
||||||
import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QController";
|
import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QController";
|
||||||
|
import { QProcessMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData";
|
||||||
|
|
||||||
// Material Dashboard 2 PRO React TS components
|
// Material Dashboard 2 PRO React TS components
|
||||||
import MDBox from "components/MDBox";
|
import MDBox from "components/MDBox";
|
||||||
import MDTypography from "components/MDTypography";
|
import MDTypography from "components/MDTypography";
|
||||||
|
import Menu from "@mui/material/Menu";
|
||||||
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
|
import Icon from "@mui/material/Icon";
|
||||||
import MDButton from "../../../../../components/MDButton";
|
import MDButton from "../../../../../components/MDButton";
|
||||||
|
import QProcessUtils from "../../../../utils/QProcessUtils";
|
||||||
|
|
||||||
const qController = new QController("");
|
const qController = new QController("");
|
||||||
|
|
||||||
@ -50,8 +55,13 @@ function ViewContents({ id }: Props): JSX.Element {
|
|||||||
const [nameValues, setNameValues] = useState([] as JSX.Element[]);
|
const [nameValues, setNameValues] = useState([] as JSX.Element[]);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [tableMetaData, setTableMetaData] = useState(null);
|
const [tableMetaData, setTableMetaData] = useState(null);
|
||||||
|
const [tableProcesses, setTableProcesses] = useState([] as QProcessMetaData[]);
|
||||||
|
const [actionsMenu, setActionsMenu] = useState(null);
|
||||||
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||||
|
|
||||||
|
const openActionsMenu = (event: any) => setActionsMenu(event.currentTarget);
|
||||||
|
const closeActionsMenu = () => setActionsMenu(null);
|
||||||
|
|
||||||
if (!asyncLoadInited) {
|
if (!asyncLoadInited) {
|
||||||
setAsyncLoadInited(true);
|
setAsyncLoadInited(true);
|
||||||
|
|
||||||
@ -59,6 +69,9 @@ function ViewContents({ id }: Props): JSX.Element {
|
|||||||
const tableMetaData = await qController.loadTableMetaData(tableName);
|
const tableMetaData = await qController.loadTableMetaData(tableName);
|
||||||
setTableMetaData(tableMetaData);
|
setTableMetaData(tableMetaData);
|
||||||
|
|
||||||
|
const metaData = await qController.loadMetaData();
|
||||||
|
setTableProcesses(QProcessUtils.getProcessesForTable(metaData, tableName));
|
||||||
|
|
||||||
const foundRecord = await qController.get(tableName, id);
|
const foundRecord = await qController.get(tableName, id);
|
||||||
|
|
||||||
nameValues.push(
|
nameValues.push(
|
||||||
@ -112,12 +125,42 @@ function ViewContents({ id }: Props): JSX.Element {
|
|||||||
|
|
||||||
const editPath = `/${tableName}/${id}/edit`;
|
const editPath = `/${tableName}/${id}/edit`;
|
||||||
|
|
||||||
|
const renderActionsMenu = (
|
||||||
|
<Menu
|
||||||
|
anchorEl={actionsMenu}
|
||||||
|
anchorOrigin={{ vertical: "bottom", horizontal: "left" }}
|
||||||
|
transformOrigin={{ vertical: "top", horizontal: "left" }}
|
||||||
|
open={Boolean(actionsMenu)}
|
||||||
|
onClose={closeActionsMenu}
|
||||||
|
keepMounted
|
||||||
|
>
|
||||||
|
{tableProcesses.map((process) => (
|
||||||
|
<MenuItem key={process.name}>
|
||||||
|
<Link href={`/processes/${process.name}?recordIds=${id}`}>{process.label}</Link>
|
||||||
|
</MenuItem>
|
||||||
|
))}
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card id="basic-info" sx={{ overflow: "visible" }}>
|
<Card id="basic-info" sx={{ overflow: "visible" }}>
|
||||||
<MDBox p={3}>
|
<MDBox p={3}>
|
||||||
|
<MDBox display="flex" justifyContent="space-between">
|
||||||
<MDTypography variant="h5">
|
<MDTypography variant="h5">
|
||||||
Viewing {tableMetaData?.label} ({id})
|
Viewing {tableMetaData?.label} ({id})
|
||||||
</MDTypography>
|
</MDTypography>
|
||||||
|
{tableProcesses.length > 0 && (
|
||||||
|
<MDButton
|
||||||
|
variant={actionsMenu ? "contained" : "outlined"}
|
||||||
|
color="dark"
|
||||||
|
onClick={openActionsMenu}
|
||||||
|
>
|
||||||
|
actions
|
||||||
|
<Icon>keyboard_arrow_down</Icon>
|
||||||
|
</MDButton>
|
||||||
|
)}
|
||||||
|
{renderActionsMenu}
|
||||||
|
</MDBox>
|
||||||
</MDBox>
|
</MDBox>
|
||||||
<MDBox p={3}>{nameValues}</MDBox>
|
<MDBox p={3}>{nameValues}</MDBox>
|
||||||
<MDBox component="form" pb={3} px={3}>
|
<MDBox component="form" pb={3} px={3}>
|
||||||
|
@ -37,13 +37,15 @@ import Footer from "examples/Footer";
|
|||||||
// ProcessRun layout schemas for form and form fields
|
// ProcessRun layout schemas for form and form fields
|
||||||
import * as Yup from "yup";
|
import * as Yup from "yup";
|
||||||
import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QController";
|
import { QController } from "@kingsrook/qqq-frontend-core/lib/controllers/QController";
|
||||||
|
import { QFieldMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldMetaData";
|
||||||
import { QFrontendStepMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFrontendStepMetaData";
|
import { QFrontendStepMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFrontendStepMetaData";
|
||||||
import { useParams } from "react-router-dom";
|
import { useLocation, useParams } from "react-router-dom";
|
||||||
import DynamicFormUtils from "qqq/components/QDynamicForm/utils/DynamicFormUtils";
|
import DynamicFormUtils from "qqq/components/QDynamicForm/utils/DynamicFormUtils";
|
||||||
import { QJobStarted } from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobStarted";
|
import { QJobStarted } from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobStarted";
|
||||||
import { QJobComplete } from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobComplete";
|
import { QJobComplete } from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobComplete";
|
||||||
import { QJobError } from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobError";
|
import { QJobError } from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobError";
|
||||||
import { QJobRunning } from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobRunning";
|
import { QJobRunning } from "@kingsrook/qqq-frontend-core/lib/model/processes/QJobRunning";
|
||||||
|
import { DataGrid, GridColDef, GridRowParams, GridRowsProp } from "@mui/x-data-grid";
|
||||||
import QDynamicForm from "../../components/QDynamicForm";
|
import QDynamicForm from "../../components/QDynamicForm";
|
||||||
import MDTypography from "../../../components/MDTypography";
|
import MDTypography from "../../../components/MDTypography";
|
||||||
|
|
||||||
@ -51,16 +53,13 @@ function getDynamicStepContent(
|
|||||||
stepIndex: number,
|
stepIndex: number,
|
||||||
step: any,
|
step: any,
|
||||||
formData: any,
|
formData: any,
|
||||||
processError: string
|
processError: string,
|
||||||
|
processValues: any,
|
||||||
|
recordConfig: any
|
||||||
): JSX.Element {
|
): JSX.Element {
|
||||||
const { formFields, values, errors, touched } = formData;
|
const { formFields, values, errors, touched } = formData;
|
||||||
// console.log(`in getDynamicStepContent: step label ${step?.label}`);
|
// console.log(`in getDynamicStepContent: step label ${step?.label}`);
|
||||||
|
|
||||||
if (!Object.keys(formFields).length) {
|
|
||||||
// console.log("in getDynamicStepContent. No fields yet, so returning 'loading'");
|
|
||||||
return <div>Loading...</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (processError) {
|
if (processError) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -72,7 +71,51 @@ function getDynamicStepContent(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return <QDynamicForm formData={formData} formLabel={step.label} />;
|
if (!Object.keys(formFields).length) {
|
||||||
|
// console.log("in getDynamicStepContent. No fields yet, so returning 'loading'");
|
||||||
|
return <div>Loading...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`in getDynamicStepContent. the step looks like: ${JSON.stringify(step)}`);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{step.formFields && <QDynamicForm formData={formData} formLabel={step.label} />}
|
||||||
|
{step.viewFields && (
|
||||||
|
<div>
|
||||||
|
{step.viewFields.map((field: QFieldMetaData) => (
|
||||||
|
<div key={field.name}>
|
||||||
|
<b>{field.label}:</b> {processValues[field.name]}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{step.recordListFields && (
|
||||||
|
<div>
|
||||||
|
<b>Records:</b> <br />
|
||||||
|
<MDBox height="100%">
|
||||||
|
<DataGrid
|
||||||
|
page={recordConfig.pageNo}
|
||||||
|
disableSelectionOnClick
|
||||||
|
autoHeight
|
||||||
|
rows={recordConfig.rows}
|
||||||
|
columns={recordConfig.columns}
|
||||||
|
rowBuffer={10}
|
||||||
|
rowCount={recordConfig.totalRecords}
|
||||||
|
pageSize={recordConfig.rowsPerPage}
|
||||||
|
rowsPerPageOptions={[10, 25, 50]}
|
||||||
|
onPageSizeChange={recordConfig.handleRowsPerPageChange}
|
||||||
|
onPageChange={recordConfig.handlePageChange}
|
||||||
|
onRowClick={recordConfig.handleRowClick}
|
||||||
|
paginationMode="server"
|
||||||
|
density="compact"
|
||||||
|
loading={recordConfig.loading}
|
||||||
|
/>
|
||||||
|
</MDBox>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function trace(name: string, isComponent: boolean = false) {
|
function trace(name: string, isComponent: boolean = false) {
|
||||||
@ -104,12 +147,17 @@ function ProcessRun(): JSX.Element {
|
|||||||
const [initialValues, setInitialValues] = useState({});
|
const [initialValues, setInitialValues] = useState({});
|
||||||
const [validations, setValidations] = useState({});
|
const [validations, setValidations] = useState({});
|
||||||
const [needToCheckJobStatus, setNeedToCheckJobStatus] = useState(false);
|
const [needToCheckJobStatus, setNeedToCheckJobStatus] = useState(false);
|
||||||
|
const [needRecords, setNeedRecords] = useState(false);
|
||||||
const [processError, setProcessError] = useState(null as string);
|
const [processError, setProcessError] = useState(null as string);
|
||||||
|
const [recordConfig, setRecordConfig] = useState({} as any);
|
||||||
const onLastStep = activeStepIndex === steps.length - 2;
|
const onLastStep = activeStepIndex === steps.length - 2;
|
||||||
const noMoreSteps = activeStepIndex === steps.length - 1;
|
const noMoreSteps = activeStepIndex === steps.length - 1;
|
||||||
|
|
||||||
trace("ProcessRun", true);
|
trace("ProcessRun", true);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// handle moving to another step in the process - e.g., after the backend told us what screen to show next. //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
trace("updateActiveStep");
|
trace("updateActiveStep");
|
||||||
|
|
||||||
@ -141,23 +189,79 @@ function ProcessRun(): JSX.Element {
|
|||||||
setActiveStep(activeStep);
|
setActiveStep(activeStep);
|
||||||
setFormId(activeStep.name);
|
setFormId(activeStep.name);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
// if this step has form fields, set up the form //
|
||||||
|
///////////////////////////////////////////////////
|
||||||
|
if (activeStep.formFields) {
|
||||||
|
const { dynamicFormFields, formValidations } = DynamicFormUtils.getFormData(
|
||||||
|
activeStep.formFields
|
||||||
|
);
|
||||||
|
|
||||||
const initialValues: any = {};
|
const initialValues: any = {};
|
||||||
activeStep.formFields.forEach((field) => {
|
activeStep.formFields.forEach((field) => {
|
||||||
initialValues[field.name] = processValues[field.name];
|
initialValues[field.name] = processValues[field.name];
|
||||||
});
|
});
|
||||||
|
|
||||||
const { dynamicFormFields, formValidations } = DynamicFormUtils.getFormData(
|
|
||||||
activeStep.formFields
|
|
||||||
);
|
|
||||||
|
|
||||||
setFormFields(dynamicFormFields);
|
setFormFields(dynamicFormFields);
|
||||||
setInitialValues(initialValues);
|
setInitialValues(initialValues);
|
||||||
setValidations(Yup.object().shape(formValidations));
|
setValidations(Yup.object().shape(formValidations));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeStep.recordListFields) {
|
||||||
|
const newRecordConfig = {} as any;
|
||||||
|
newRecordConfig.pageNo = 1;
|
||||||
|
newRecordConfig.rowsPerPage = 20;
|
||||||
|
newRecordConfig.columns = [] as GridColDef[];
|
||||||
|
newRecordConfig.rows = [];
|
||||||
|
newRecordConfig.totalRecords = 0;
|
||||||
|
newRecordConfig.handleRowsPerPageChange = null;
|
||||||
|
newRecordConfig.handlePageChange = null;
|
||||||
|
newRecordConfig.handleRowClick = null;
|
||||||
|
newRecordConfig.loading = true;
|
||||||
|
|
||||||
|
activeStep.recordListFields.forEach((field) => {
|
||||||
|
newRecordConfig.columns.push({ field: field.name, headerName: field.label });
|
||||||
|
});
|
||||||
|
|
||||||
|
setRecordConfig(newRecordConfig);
|
||||||
|
setNeedRecords(true);
|
||||||
|
}
|
||||||
|
|
||||||
// console.log(`in updateActiveStep: formFields ${JSON.stringify(dynamicFormFields)}`);
|
// console.log(`in updateActiveStep: formFields ${JSON.stringify(dynamicFormFields)}`);
|
||||||
// console.log(`in updateActiveStep: initialValues ${JSON.stringify(initialValues)}`);
|
// console.log(`in updateActiveStep: initialValues ${JSON.stringify(initialValues)}`);
|
||||||
}
|
}
|
||||||
}, [newStep]);
|
}, [newStep]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (needRecords) {
|
||||||
|
setNeedRecords(false);
|
||||||
|
(async () => {
|
||||||
|
const records = await qController.processRecords(
|
||||||
|
processName,
|
||||||
|
processUUID,
|
||||||
|
recordConfig.rowsPerPage * (recordConfig.pageNo - 1),
|
||||||
|
recordConfig.rowsPerPage
|
||||||
|
);
|
||||||
|
recordConfig.loading = false;
|
||||||
|
recordConfig.rows = [];
|
||||||
|
let rowId = 0;
|
||||||
|
records.forEach((record) => {
|
||||||
|
const row = Object.fromEntries(record.values.entries());
|
||||||
|
if (!row.id) {
|
||||||
|
row.id = ++rowId;
|
||||||
|
}
|
||||||
|
recordConfig.rows.push(row);
|
||||||
|
});
|
||||||
|
// todo count?
|
||||||
|
recordConfig.totalRecords = records.length;
|
||||||
|
setRecordConfig(recordConfig);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
}, [needRecords]);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// handle a response from the server - e.g., after starting a backend job, or getting its status/result //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (lastProcessResponse) {
|
if (lastProcessResponse) {
|
||||||
trace("handleProcessResponse");
|
trace("handleProcessResponse");
|
||||||
@ -183,53 +287,82 @@ function ProcessRun(): JSX.Element {
|
|||||||
}
|
}
|
||||||
}, [lastProcessResponse]);
|
}, [lastProcessResponse]);
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// while a backend async job is running, periodically check its status //
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (needToCheckJobStatus) {
|
if (needToCheckJobStatus) {
|
||||||
trace("checkJobStatus");
|
trace("checkJobStatus");
|
||||||
setNeedToCheckJobStatus(false);
|
setNeedToCheckJobStatus(false);
|
||||||
(async () => {
|
(async () => {
|
||||||
|
setTimeout(async () => {
|
||||||
const processResponse = await qController.processJobStatus(
|
const processResponse = await qController.processJobStatus(
|
||||||
processName,
|
processName,
|
||||||
processUUID,
|
processUUID,
|
||||||
jobUUID
|
jobUUID
|
||||||
);
|
);
|
||||||
setLastProcessResponse(processResponse);
|
setLastProcessResponse(processResponse);
|
||||||
|
}, 1500);
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
}, [needToCheckJobStatus]);
|
}, [needToCheckJobStatus]);
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// do the initial load of data for the process - that is, meta data, plus the init step //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
if (needInitialLoad) {
|
if (needInitialLoad) {
|
||||||
trace("initialLoad");
|
trace("initialLoad");
|
||||||
setNeedInitialLoad(false);
|
setNeedInitialLoad(false);
|
||||||
(async () => {
|
(async () => {
|
||||||
|
const { search } = useLocation();
|
||||||
|
const urlSearchParams = new URLSearchParams(search);
|
||||||
|
let queryStringForInit = null;
|
||||||
|
if (urlSearchParams.get("recordIds")) {
|
||||||
|
queryStringForInit = `recordsParam=recordIds&recordIds=${urlSearchParams.get("recordIds")}`;
|
||||||
|
} else if (urlSearchParams.get("filterJSON")) {
|
||||||
|
queryStringForInit = `recordsParam=filterJSON&filterJSON=${urlSearchParams.get(
|
||||||
|
"filterJSON"
|
||||||
|
)}`;
|
||||||
|
}
|
||||||
|
// todo once saved filters exist
|
||||||
|
//else if(urlSearchParams.get("filterId")) {
|
||||||
|
// queryStringForInit = `recordsParam=filterId&filterId=${urlSearchParams.get("filterId")}`
|
||||||
|
// }
|
||||||
|
|
||||||
|
console.log(`@dk: Query String for init: ${queryStringForInit}`);
|
||||||
|
|
||||||
const processMetaData = await qController.loadProcessMetaData(processName);
|
const processMetaData = await qController.loadProcessMetaData(processName);
|
||||||
// console.log(processMetaData);
|
// console.log(processMetaData);
|
||||||
setProcessMetaData(processMetaData);
|
setProcessMetaData(processMetaData);
|
||||||
setSteps(processMetaData.frontendSteps);
|
setSteps(processMetaData.frontendSteps);
|
||||||
|
|
||||||
const processResponse = await qController.processInit(processName);
|
const processResponse = await qController.processInit(processName, queryStringForInit);
|
||||||
setProcessUUID(processResponse.processUUID);
|
setProcessUUID(processResponse.processUUID);
|
||||||
setLastProcessResponse(processResponse);
|
setLastProcessResponse(processResponse);
|
||||||
// console.log(processResponse);
|
// console.log(processResponse);
|
||||||
})();
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// handle the back button - todo - not really done at all //
|
||||||
|
// e.g., qqq needs to say when back is or isn't allowed, and we need to hit the backend upon backs. //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
trace("handleBack");
|
trace("handleBack");
|
||||||
setNewStep(activeStepIndex - 1);
|
setNewStep(activeStepIndex - 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// handle user submitting the form - which in qqq means moving forward from any screen. //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
const handleSubmit = async (values: any, actions: any) => {
|
const handleSubmit = async (values: any, actions: any) => {
|
||||||
trace("handleSubmit");
|
trace("handleSubmit");
|
||||||
// eslint-disable-next-line no-alert
|
|
||||||
// alert(JSON.stringify(values, null, 2));
|
|
||||||
|
|
||||||
|
// todo - post?
|
||||||
let queryString = "";
|
let queryString = "";
|
||||||
Object.keys(values).forEach((key) => {
|
Object.keys(values).forEach((key) => {
|
||||||
queryString += `${key}=${encodeURIComponent(values[key])}&`;
|
queryString += `${key}=${encodeURIComponent(values[key])}&`;
|
||||||
});
|
});
|
||||||
// eslint-disable-next-line no-alert
|
|
||||||
// alert(queryString);
|
|
||||||
|
|
||||||
actions.setSubmitting(false);
|
actions.setSubmitting(false);
|
||||||
actions.resetForm();
|
actions.resetForm();
|
||||||
@ -281,7 +414,9 @@ function ProcessRun(): JSX.Element {
|
|||||||
formFields,
|
formFields,
|
||||||
errors,
|
errors,
|
||||||
},
|
},
|
||||||
processError
|
processError,
|
||||||
|
processValues,
|
||||||
|
recordConfig
|
||||||
)}
|
)}
|
||||||
{/********************************
|
{/********************************
|
||||||
** back &| next/submit buttons **
|
** back &| next/submit buttons **
|
||||||
|
43
src/qqq/utils/QProcessUtils.ts
Normal file
43
src/qqq/utils/QProcessUtils.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* 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 { QProcessMetaData } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QProcessMetaData";
|
||||||
|
import { QInstance } from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance";
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
** Utility class for working with QQQ Processes
|
||||||
|
**
|
||||||
|
*******************************************************************************/
|
||||||
|
class QProcessUtils {
|
||||||
|
public static getProcessesForTable(metaData: QInstance, tableName: string): QProcessMetaData[] {
|
||||||
|
const matchingProcesses: QProcessMetaData[] = [];
|
||||||
|
const processKeys = [...metaData.processes.keys()];
|
||||||
|
processKeys.forEach((key) => {
|
||||||
|
const process = metaData.processes.get(key);
|
||||||
|
if (process.tableName === tableName) {
|
||||||
|
matchingProcesses.push(process);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return matchingProcesses;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default QProcessUtils;
|
Reference in New Issue
Block a user