mirror of
https://github.com/Kingsrook/qqq-frontend-material-dashboard.git
synced 2025-07-17 21:00:45 +00:00
CE-1946: checkpoint initial commit
This commit is contained in:
8576
package-lock.json
generated
8576
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -18,18 +18,20 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
||||
import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData";
|
||||
import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord";
|
||||
import {Alert, Skeleton} from "@mui/material";
|
||||
import Box from "@mui/material/Box";
|
||||
import Grid from "@mui/material/Grid";
|
||||
import Modal from "@mui/material/Modal";
|
||||
import Tab from "@mui/material/Tab";
|
||||
import Tabs from "@mui/material/Tabs";
|
||||
import parse from "html-react-parser";
|
||||
import QContext from "QContext";
|
||||
import EntityForm from "qqq/components/forms/EntityForm";
|
||||
import MDTypography from "qqq/components/legacy/MDTypography";
|
||||
import TabPanel from "qqq/components/misc/TabPanel";
|
||||
import {BlockData} from "qqq/components/widgets/blocks/BlockModels";
|
||||
import BarChart from "qqq/components/widgets/charts/barchart/BarChart";
|
||||
import HorizontalBarChart from "qqq/components/widgets/charts/barchart/HorizontalBarChart";
|
||||
import DefaultLineChart from "qqq/components/widgets/charts/linechart/DefaultLineChart";
|
||||
@ -44,7 +46,7 @@ import FieldValueListWidget from "qqq/components/widgets/misc/FieldValueListWidg
|
||||
import FilterAndColumnsSetupWidget from "qqq/components/widgets/misc/FilterAndColumnsSetupWidget";
|
||||
import PivotTableSetupWidget from "qqq/components/widgets/misc/PivotTableSetupWidget";
|
||||
import QuickSightChart from "qqq/components/widgets/misc/QuickSightChart";
|
||||
import RecordGridWidget from "qqq/components/widgets/misc/RecordGridWidget";
|
||||
import RecordGridWidget, {ChildRecordListData} from "qqq/components/widgets/misc/RecordGridWidget";
|
||||
import ScriptViewer from "qqq/components/widgets/misc/ScriptViewer";
|
||||
import StepperCard from "qqq/components/widgets/misc/StepperCard";
|
||||
import USMapWidget from "qqq/components/widgets/misc/USMapWidget";
|
||||
@ -72,7 +74,7 @@ interface Props
|
||||
childUrlParams?: string;
|
||||
parentWidgetMetaData?: QWidgetMetaData;
|
||||
wrapWidgetsInTabPanels: boolean;
|
||||
actionCallback?: (blockData: BlockData) => boolean;
|
||||
actionCallback?: (data: any, eventValues?: { [name: string]: any }) => boolean;
|
||||
initialWidgetDataList: any[];
|
||||
values?: { [key: string]: any };
|
||||
}
|
||||
@ -101,6 +103,12 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
||||
const [haveLoadedParams, setHaveLoadedParams] = useState(false);
|
||||
const {accentColor} = useContext(QContext);
|
||||
|
||||
/////////////////////////
|
||||
// modal form controls //
|
||||
/////////////////////////
|
||||
const [showEditChildForm, setShowEditChildForm] = useState(null as any);
|
||||
const [modalTable, setModalTable] = useState(null as QTableMetaData);
|
||||
|
||||
let initialSelectedTab = 0;
|
||||
let selectedTabKey: string = null;
|
||||
if (parentWidgetMetaData && wrapWidgetsInTabPanels)
|
||||
@ -125,7 +133,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
||||
{
|
||||
// todo actually, should this check each element of the array, down in the loop? yeah, when we need to, do it that way.
|
||||
console.log("We already have initial widget data, so not fetching from backend.");
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
setWidgetData([]);
|
||||
@ -166,7 +174,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
||||
|
||||
const reloadWidget = async (index: number, data: string) =>
|
||||
{
|
||||
(async () =>
|
||||
await (async () =>
|
||||
{
|
||||
const urlParams = getQueryParams(widgetMetaDataList[index], data);
|
||||
setCurrentUrlParams(urlParams);
|
||||
@ -285,6 +293,132 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
||||
return (rs);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
const closeEditChildForm = (event: object, reason: string) =>
|
||||
{
|
||||
if (reason === "backdropClick" || reason === "escapeKeyDown")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
setShowEditChildForm(null);
|
||||
};
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
function deleteChildRecord(name: string, widgetIndex: number, rowIndex: number)
|
||||
{
|
||||
updateChildRecordList(name, "delete", rowIndex);
|
||||
actionCallback(widgetData[widgetIndex]);
|
||||
};
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
function openEditChildRecord(name: string, widgetData: any, rowIndex: number)
|
||||
{
|
||||
let defaultValues = widgetData.queryOutput.records[rowIndex].values;
|
||||
|
||||
let disabledFields = widgetData.disabledFieldsForNewChildRecords;
|
||||
if (!disabledFields)
|
||||
{
|
||||
disabledFields = widgetData.defaultValuesForNewChildRecords;
|
||||
}
|
||||
|
||||
doOpenEditChildForm(name, widgetData.childTableMetaData, rowIndex, defaultValues, disabledFields);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
function doOpenEditChildForm(widgetName: string, table: QTableMetaData, rowIndex: number, defaultValues: any, disabledFields: any)
|
||||
{
|
||||
const showEditChildForm: any = {};
|
||||
showEditChildForm.widgetName = widgetName;
|
||||
showEditChildForm.table = table;
|
||||
showEditChildForm.rowIndex = rowIndex;
|
||||
showEditChildForm.defaultValues = defaultValues;
|
||||
showEditChildForm.disabledFields = disabledFields;
|
||||
setShowEditChildForm(showEditChildForm);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
function submitEditChildForm(values: any)
|
||||
{
|
||||
updateChildRecordList(showEditChildForm.widgetName, showEditChildForm.rowIndex == null ? "insert" : "edit", showEditChildForm.rowIndex, values);
|
||||
let widgetIndex = determineChildRecordListIndex(showEditChildForm.widgetName);
|
||||
actionCallback(widgetData[widgetIndex]);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
function determineChildRecordListIndex(widgetName: string): number
|
||||
{
|
||||
let widgetIndex = -1;
|
||||
for (var i = 0; i < widgetMetaDataList.length; i++)
|
||||
{
|
||||
const widgetMetaData = widgetMetaDataList[i];
|
||||
if (widgetMetaData.name == widgetName)
|
||||
{
|
||||
widgetIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (widgetIndex);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
function updateChildRecordList(widgetName: string, action: "insert" | "edit" | "delete", rowIndex?: number, values?: any)
|
||||
{
|
||||
////////////////////////////////////////////////
|
||||
// find the correct child record widget index //
|
||||
////////////////////////////////////////////////
|
||||
let widgetIndex = determineChildRecordListIndex(widgetName);
|
||||
|
||||
if (!widgetData[widgetIndex].queryOutput.records)
|
||||
{
|
||||
widgetData[widgetIndex].queryOutput.records = [];
|
||||
}
|
||||
|
||||
const newChildListWidgetData: ChildRecordListData = widgetData[widgetIndex];
|
||||
if (!newChildListWidgetData.queryOutput.records)
|
||||
{
|
||||
newChildListWidgetData.queryOutput.records = [];
|
||||
}
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case "insert":
|
||||
newChildListWidgetData.queryOutput.records.push({values: values});
|
||||
break;
|
||||
case "edit":
|
||||
newChildListWidgetData.queryOutput.records[rowIndex] = {values: values};
|
||||
break;
|
||||
case "delete":
|
||||
newChildListWidgetData.queryOutput.records.splice(rowIndex, 1);
|
||||
break;
|
||||
}
|
||||
newChildListWidgetData.totalRows = newChildListWidgetData.queryOutput.records.length;
|
||||
widgetData[widgetIndex] = newChildListWidgetData;
|
||||
setWidgetData(widgetData);
|
||||
|
||||
setShowEditChildForm(null);
|
||||
}
|
||||
|
||||
|
||||
const renderWidget = (widgetMetaData: QWidgetMetaData, i: number): JSX.Element =>
|
||||
{
|
||||
const labelAdditionalComponentsRight: LabelComponent[] = [];
|
||||
@ -324,7 +458,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
||||
)
|
||||
}
|
||||
{
|
||||
widgetMetaData.type === "alert" && widgetData[i]?.html && (
|
||||
widgetMetaData.type === "alert" && widgetData[i]?.html && !widgetData[i]?.hideWidget && (
|
||||
<Widget
|
||||
omitPadding={true}
|
||||
widgetMetaData={widgetMetaData}
|
||||
@ -334,7 +468,16 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
||||
labelAdditionalComponentsRight={labelAdditionalComponentsRight}
|
||||
labelAdditionalComponentsLeft={labelAdditionalComponentsLeft}
|
||||
>
|
||||
<Alert severity={widgetData[i]?.alertType?.toLowerCase()}>{parse(widgetData[i]?.html)}</Alert>
|
||||
<Alert severity={widgetData[i]?.alertType?.toLowerCase()}>
|
||||
{parse(widgetData[i]?.html)}
|
||||
{widgetData[i]?.bulletList && (
|
||||
<div style={{fontSize: "14px"}}>
|
||||
{widgetData[i].bulletList.map((bullet: string, index: number) =>
|
||||
<li key={`widget-${i}-${index}`}>{parse(bullet)}</li>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Alert>
|
||||
</Widget>
|
||||
)
|
||||
}
|
||||
@ -516,9 +659,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
||||
}
|
||||
{
|
||||
widgetMetaData.type === "divider" && (
|
||||
<Box>
|
||||
<DividerWidget />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
{
|
||||
@ -552,6 +693,11 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
||||
widgetMetaData.type === "childRecordList" && (
|
||||
widgetData && widgetData[i] &&
|
||||
<RecordGridWidget
|
||||
disableRowClick={true}
|
||||
allowRecordEdit={true}
|
||||
deleteRecordCallback={(rowIndex) => deleteChildRecord(widgetMetaData.name, i, rowIndex)}
|
||||
editRecordCallback={(rowIndex) => openEditChildRecord(widgetMetaData.name, widgetData[i], rowIndex)}
|
||||
allowRecordDelete={true}
|
||||
widgetMetaData={widgetMetaData}
|
||||
data={widgetData[i]}
|
||||
/>
|
||||
@ -657,7 +803,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
||||
|
||||
for (let size of ["xs", "sm", "md", "lg", "xl", "xxl"])
|
||||
{
|
||||
const key = `gridCols:sizeClass:${size}`
|
||||
const key = `gridCols:sizeClass:${size}`;
|
||||
if (widgetMetaData?.defaultValues?.has(key))
|
||||
{
|
||||
gridProps[size] = widgetMetaData?.defaultValues.get(key);
|
||||
@ -725,6 +871,22 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco
|
||||
</Grid>
|
||||
)
|
||||
}
|
||||
{
|
||||
showEditChildForm &&
|
||||
<Modal open={showEditChildForm as boolean} onClose={(event, reason) => closeEditChildForm(event, reason)}>
|
||||
<div className="modalEditForm">
|
||||
<EntityForm
|
||||
isModal={true}
|
||||
closeModalHandler={closeEditChildForm}
|
||||
table={showEditChildForm.table}
|
||||
defaultValues={showEditChildForm.defaultValues}
|
||||
disabledFields={showEditChildForm.disabledFields}
|
||||
onSubmitCallback={submitEditChildForm}
|
||||
overrideHeading={`${showEditChildForm.rowIndex != null ? "Editing" : "Creating New"} ${showEditChildForm.table.label}`}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
}
|
||||
</>
|
||||
) : null
|
||||
);
|
||||
|
@ -19,13 +19,16 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import Box from "@mui/material/Box";
|
||||
import Divider from "@mui/material/Divider";
|
||||
|
||||
|
||||
function DividerWidget(): JSX.Element
|
||||
{
|
||||
return (
|
||||
<Divider sx={{padding: "1px", background: "red"}}/>
|
||||
<Box pl={3} pt={1} width="100%">
|
||||
<Divider sx={{width: "100%", height: "1px", background: "grey"}} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -39,15 +39,15 @@ import {Link, useNavigate} from "react-router-dom";
|
||||
|
||||
export interface ChildRecordListData extends WidgetData
|
||||
{
|
||||
title: string;
|
||||
queryOutput: { records: { values: any }[] };
|
||||
childTableMetaData: QTableMetaData;
|
||||
tablePath: string;
|
||||
viewAllLink: string;
|
||||
totalRows: number;
|
||||
canAddChildRecord: boolean;
|
||||
defaultValuesForNewChildRecords: { [fieldName: string]: any };
|
||||
disabledFieldsForNewChildRecords: { [fieldName: string]: any };
|
||||
title?: string;
|
||||
queryOutput?: { records: { values: any }[] };
|
||||
childTableMetaData?: QTableMetaData;
|
||||
tablePath?: string;
|
||||
viewAllLink?: string;
|
||||
totalRows?: number;
|
||||
canAddChildRecord?: boolean;
|
||||
defaultValuesForNewChildRecords?: { [fieldName: string]: any };
|
||||
disabledFieldsForNewChildRecords?: { [fieldName: string]: any };
|
||||
}
|
||||
|
||||
interface Props
|
||||
@ -176,7 +176,7 @@ function RecordGridWidget({widgetMetaData, data, addNewRecordCallback, disableRo
|
||||
setCsv(csv);
|
||||
setFileName(fileName);
|
||||
}
|
||||
}, [data]);
|
||||
}, [JSON.stringify(data?.queryOutput)]);
|
||||
|
||||
///////////////////
|
||||
// view all link //
|
||||
@ -304,7 +304,7 @@ function RecordGridWidget({widgetMetaData, data, addNewRecordCallback, disableRo
|
||||
labelAdditionalComponentsRight={labelAdditionalComponentsRight}
|
||||
labelBoxAdditionalSx={{position: "relative", top: "-0.375rem"}}
|
||||
>
|
||||
<Box mx={-3} mb={-3}>
|
||||
<Box>
|
||||
<Box>
|
||||
<DataGridPro
|
||||
autoHeight
|
||||
|
96
src/qqq/components/widgets/tables/ModalEditForm.tsx
Normal file
96
src/qqq/components/widgets/tables/ModalEditForm.tsx
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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 {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData";
|
||||
import Modal from "@mui/material/Modal";
|
||||
import EntityForm from "qqq/components/forms/EntityForm";
|
||||
import Client from "qqq/utils/qqq/Client";
|
||||
import React, {useEffect, useReducer, useState} from "react";
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
// structure of expected data //
|
||||
////////////////////////////////
|
||||
export interface ModalEditFormData
|
||||
{
|
||||
tableName: string;
|
||||
defaultValues?: { [key: string]: string };
|
||||
disabledFields?: { [key: string]: boolean } | string[];
|
||||
overrideHeading?: string;
|
||||
onSubmitCallback?: (values: any) => void;
|
||||
initialShowModalValue?: boolean;
|
||||
}
|
||||
|
||||
const qController = Client.getInstance();
|
||||
|
||||
function ModalEditForm({tableName, defaultValues, disabledFields, overrideHeading, onSubmitCallback, initialShowModalValue}: ModalEditFormData,): JSX.Element
|
||||
{
|
||||
const [showModal, setShowModal] = useState(initialShowModalValue);
|
||||
const [table, setTable] = useState(null as QTableMetaData);
|
||||
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if (!tableName)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
(async () =>
|
||||
{
|
||||
const tableMetaData = await qController.loadTableMetaData(tableName);
|
||||
setTable(tableMetaData);
|
||||
forceUpdate();
|
||||
})();
|
||||
}, [tableName]);
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
const closeEditChildForm = (event: object, reason: string) =>
|
||||
{
|
||||
if (reason === "backdropClick" || reason === "escapeKeyDown")
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
setShowModal(null);
|
||||
};
|
||||
|
||||
return (
|
||||
table && showModal &&
|
||||
<Modal open={showModal as boolean} onClose={(event, reason) => closeEditChildForm(event, reason)}>
|
||||
<div className="modalEditForm">
|
||||
<EntityForm
|
||||
isModal={true}
|
||||
closeModalHandler={closeEditChildForm}
|
||||
table={table}
|
||||
defaultValues={defaultValues}
|
||||
disabledFields={disabledFields}
|
||||
onSubmitCallback={onSubmitCallback}
|
||||
overrideHeading={overrideHeading}
|
||||
/>
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default ModalEditForm;
|
@ -66,6 +66,7 @@ import ValidationReview from "qqq/components/processes/ValidationReview";
|
||||
import {BlockData} from "qqq/components/widgets/blocks/BlockModels";
|
||||
import CompositeWidget, {CompositeData} from "qqq/components/widgets/CompositeWidget";
|
||||
import DashboardWidgets from "qqq/components/widgets/DashboardWidgets";
|
||||
import {ChildRecordListData} from "qqq/components/widgets/misc/RecordGridWidget";
|
||||
import BaseLayout from "qqq/layouts/BaseLayout";
|
||||
import ProcessWidgetBlockUtils from "qqq/pages/processes/ProcessWidgetBlockUtils";
|
||||
import {TABLE_VARIANT_LOCAL_STORAGE_KEY_ROOT} from "qqq/pages/records/query/RecordQuery";
|
||||
@ -150,7 +151,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
const [previouslySeenUpdatedFieldMetaDataMap, setPreviouslySeenUpdatedFieldMetaDataMap] = useState(new Map<string, QFieldMetaData>);
|
||||
|
||||
const [renderedWidgets, setRenderedWidgets] = useState({} as { [step: string]: { [widgetName: string]: any } });
|
||||
const [controlCallbacks, setControlCallbacks] = useState({} as {[name: string]: () => void})
|
||||
const [controlCallbacks, setControlCallbacks] = useState({} as { [name: string]: () => void });
|
||||
|
||||
const {pageHeader, recordAnalytics, setPageHeader, helpHelpActive} = useContext(QContext);
|
||||
|
||||
@ -210,7 +211,8 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
const [recordConfig, setRecordConfig] = useState({} as any);
|
||||
const [pageNumber, setPageNumber] = useState(0);
|
||||
const [rowsPerPage, setRowsPerPage] = useState(10);
|
||||
const [records, setRecords] = useState([] as QRecord[]);
|
||||
const [records, setRecords] = useState([] as any);
|
||||
const [childRecordData, setChildRecordData] = useState(null as ChildRecordListData);
|
||||
|
||||
//////////////////////////////
|
||||
// state for bulk edit form //
|
||||
@ -329,23 +331,24 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
*******************************************************************************/
|
||||
function renderWidget(widgetName: string)
|
||||
{
|
||||
const widgetMetaData = qInstance.widgets.get(widgetName);
|
||||
if (!widgetMetaData)
|
||||
{
|
||||
return (<Alert color="error">Unrecognized widget name: {widgetName}</Alert>);
|
||||
}
|
||||
|
||||
if (!renderedWidgets[activeStep.name])
|
||||
{
|
||||
renderedWidgets[activeStep.name] = {};
|
||||
setRenderedWidgets(renderedWidgets);
|
||||
}
|
||||
|
||||
if (renderedWidgets[activeStep.name][widgetName])
|
||||
let isChildRecordWidget = widgetMetaData.type == "childRecordList";
|
||||
if (!isChildRecordWidget && renderedWidgets[activeStep.name][widgetName])
|
||||
{
|
||||
return renderedWidgets[activeStep.name][widgetName];
|
||||
}
|
||||
|
||||
const widgetMetaData = qInstance.widgets.get(widgetName);
|
||||
if (!widgetMetaData)
|
||||
{
|
||||
return (<Alert color="error">Unrecognized widget name: {widgetName}</Alert>);
|
||||
}
|
||||
|
||||
const queryStringParts: string[] = [];
|
||||
for (let name in processValues)
|
||||
{
|
||||
@ -355,12 +358,23 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
let initialWidgetDataList = null;
|
||||
if (processValues[widgetName])
|
||||
{
|
||||
processValues[widgetName].hasPermission = true
|
||||
initialWidgetDataList = [processValues[widgetName]]
|
||||
processValues[widgetName].hasPermission = true;
|
||||
initialWidgetDataList = [processValues[widgetName]];
|
||||
}
|
||||
|
||||
let actionCallback = blockWidgetActionCallback;
|
||||
if (isChildRecordWidget)
|
||||
{
|
||||
actionCallback = childRecordListWidgetActionCallBack;
|
||||
|
||||
if (childRecordData)
|
||||
{
|
||||
initialWidgetDataList = [childRecordData];
|
||||
}
|
||||
}
|
||||
|
||||
const renderedWidget = (<Box m={-2}>
|
||||
<DashboardWidgets widgetMetaDataList={[widgetMetaData]} omitWrappingGridContainer={true} childUrlParams={queryStringParts.join("&")} initialWidgetDataList={initialWidgetDataList} values={processValues} actionCallback={blockWidgetActionCallback} />
|
||||
<DashboardWidgets widgetMetaDataList={[widgetMetaData]} omitWrappingGridContainer={true} childUrlParams={queryStringParts.join("&")} initialWidgetDataList={initialWidgetDataList} values={processValues} actionCallback={actionCallback} />
|
||||
</Box>);
|
||||
renderedWidgets[activeStep.name][widgetName] = renderedWidget;
|
||||
return renderedWidget;
|
||||
@ -374,46 +388,57 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
{
|
||||
const split = controlCode.split(":", 2);
|
||||
let controlCallbackName: string;
|
||||
let controlCallbackValue: any
|
||||
let controlCallbackValue: any;
|
||||
if (split.length == 2)
|
||||
{
|
||||
if (split[0] == "showModal")
|
||||
{
|
||||
processValues[split[1]] = true
|
||||
controlCallbackName = split[1]
|
||||
controlCallbackValue = true
|
||||
processValues[split[1]] = true;
|
||||
controlCallbackName = split[1];
|
||||
controlCallbackValue = true;
|
||||
}
|
||||
else if (split[0] == "hideModal")
|
||||
{
|
||||
processValues[split[1]] = false
|
||||
controlCallbackName = split[1]
|
||||
controlCallbackValue = false
|
||||
processValues[split[1]] = false;
|
||||
controlCallbackName = split[1];
|
||||
controlCallbackValue = false;
|
||||
}
|
||||
else if (split[0] == "toggleModal")
|
||||
{
|
||||
const currentValue = processValues[split[1]]
|
||||
const currentValue = processValues[split[1]];
|
||||
processValues[split[1]] = !!!currentValue;
|
||||
controlCallbackName = split[1]
|
||||
controlCallbackValue = processValues[split[1]]
|
||||
controlCallbackName = split[1];
|
||||
controlCallbackValue = processValues[split[1]];
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log(`Unexpected part[0] (before colon) in controlCode: [${controlCode}]`)
|
||||
console.log(`Unexpected part[0] (before colon) in controlCode: [${controlCode}]`);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
console.log(`Expected controlCode to have 2 colon-delimited parts, but was: [${controlCode}]`)
|
||||
console.log(`Expected controlCode to have 2 colon-delimited parts, but was: [${controlCode}]`);
|
||||
}
|
||||
|
||||
if (controlCallbackName && controlCallbacks[controlCallbackName])
|
||||
{
|
||||
// @ts-ignore ... args are hard
|
||||
controlCallbacks[controlCallbackName](controlCallbackValue)
|
||||
controlCallbacks[controlCallbackName](controlCallbackValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** callback used by child list widget
|
||||
***************************************************************************/
|
||||
function childRecordListWidgetActionCallBack(data: any): boolean
|
||||
{
|
||||
console.log(`in childRecordListWidgetActionCallBack: ${JSON.stringify(data)}`);
|
||||
setChildRecordData(data as ChildRecordListData);
|
||||
return (true);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** callback used by widget blocks, e.g., for input-text-enter-on-submit,
|
||||
** and action buttons.
|
||||
@ -425,8 +450,8 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
if (eventValues?.registerControlCallbackName && eventValues?.registerControlCallbackFunction)
|
||||
{
|
||||
controlCallbacks[eventValues.registerControlCallbackName] = eventValues.registerControlCallbackFunction;
|
||||
setControlCallbacks(controlCallbacks)
|
||||
return (true)
|
||||
setControlCallbacks(controlCallbacks);
|
||||
return (true);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -451,19 +476,19 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
let doSubmit = false;
|
||||
if (blockData?.blockTypeName == "BUTTON" && eventValues?.actionCode)
|
||||
{
|
||||
doSubmit = true
|
||||
doSubmit = true;
|
||||
}
|
||||
else if (blockData?.blockTypeName == "BUTTON" && eventValues?.controlCode)
|
||||
{
|
||||
handleControlCode(eventValues.controlCode);
|
||||
doSubmit = false
|
||||
doSubmit = false;
|
||||
}
|
||||
else if (blockData?.blockTypeName == "INPUT_FIELD")
|
||||
{
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// if action callback was fired from an input field, assume that means we're good to submit. //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
doSubmit = true
|
||||
doSubmit = true;
|
||||
}
|
||||
|
||||
//////////////////
|
||||
@ -471,7 +496,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
//////////////////
|
||||
if (doSubmit)
|
||||
{
|
||||
handleSubmit(eventValues);
|
||||
handleFormSubmit(eventValues);
|
||||
return (true);
|
||||
}
|
||||
}
|
||||
@ -658,7 +683,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
let helpRoles = ["PROCESS_SCREEN", "ALL_SCREENS"];
|
||||
const showHelp = helpHelpActive || hasHelpContent(step.helpContents, helpRoles);
|
||||
const formattedHelpContent = <HelpContent helpContents={step.helpContents} roles={helpRoles} helpContentKey={`process:${processName};step:${step?.name}`} />;
|
||||
const isFormatScanner = step?.format?.toLowerCase() == "scanner"
|
||||
const isFormatScanner = step?.format?.toLowerCase() == "scanner";
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -1133,7 +1158,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
{
|
||||
const dynamicField = DynamicFormUtils.getDynamicField(fieldMetaData);
|
||||
const validation = DynamicFormUtils.getValidationForField(fieldMetaData);
|
||||
addField(fieldMetaData.name, dynamicField, processValues[fieldMetaData.name], validation)
|
||||
addField(fieldMetaData.name, dynamicField, processValues[fieldMetaData.name], validation);
|
||||
});
|
||||
}
|
||||
|
||||
@ -1295,6 +1320,11 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
const {records} = response;
|
||||
setRecords(records);
|
||||
|
||||
if (!childRecordData || childRecordData.length == 0)
|
||||
{
|
||||
setChildRecordData(convertRecordsToChildRecordData(records));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
// re-construct the recordConfig object, so the setState call triggers a new rendering //
|
||||
/////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -1317,6 +1347,30 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
}, [needRecords]);
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
function convertRecordsToChildRecordData(records: QRecord[])
|
||||
{
|
||||
const frontendRecords = [] as any[];
|
||||
records.forEach((record: QRecord) =>
|
||||
{
|
||||
const object = {
|
||||
"tableName": record.tableName,
|
||||
"recordLabel": record.recordLabel,
|
||||
"errors": record.errors,
|
||||
"warnings": record.warnings,
|
||||
"values": Object.fromEntries(record.values),
|
||||
"displayValues": Object.fromEntries(record.displayValues),
|
||||
};
|
||||
frontendRecords.push(object);
|
||||
});
|
||||
const newChildListData = {} as ChildRecordListData;
|
||||
newChildListData.queryOutput = {records: frontendRecords};
|
||||
return (newChildListData);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
**
|
||||
***************************************************************************/
|
||||
@ -1690,11 +1744,35 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
setNewStep(activeStepIndex - 1);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////
|
||||
// handle user submitting changed records //
|
||||
////////////////////////////////////////////
|
||||
const doSubmit = async (formData: FormData) =>
|
||||
{
|
||||
const formDataHeaders = {
|
||||
"content-type": "multipart/form-data; boundary=--------------------------320289315924586491558366",
|
||||
};
|
||||
|
||||
setTimeout(async () =>
|
||||
{
|
||||
recordAnalytics({category: "processEvents", action: "processStep", label: activeStep.label});
|
||||
|
||||
const processResponse = await Client.getInstance().processStep(
|
||||
processName,
|
||||
processUUID,
|
||||
activeStep.name,
|
||||
formData,
|
||||
formDataHeaders
|
||||
);
|
||||
setLastProcessResponse(processResponse);
|
||||
});
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
// handle user submitting the form - which in qqq means moving forward from any screen. //
|
||||
// caller can pass in a map of values to be added to the form data too //
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
const handleSubmit = async (values: any) =>
|
||||
const handleFormSubmit = async (values: any) =>
|
||||
{
|
||||
setFormError(null);
|
||||
|
||||
@ -1733,28 +1811,20 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
formData.append("bulkEditEnabledFields", bulkEditEnabledFields.join(","));
|
||||
}
|
||||
|
||||
const formDataHeaders = {
|
||||
"content-type": "multipart/form-data; boundary=--------------------------320289315924586491558366",
|
||||
};
|
||||
/////////////////////////////////////////////////////////////
|
||||
// convert to regular objects so that they can be jsonized //
|
||||
/////////////////////////////////////////////////////////////
|
||||
if (childRecordData)
|
||||
{
|
||||
formData.append("frontendRecords", JSON.stringify(childRecordData.queryOutput.records));
|
||||
}
|
||||
|
||||
setProcessValues({});
|
||||
setRecords([]);
|
||||
setOverrideOnLastStep(null);
|
||||
setLastProcessResponse(new QJobRunning({message: "Working..."}));
|
||||
|
||||
setTimeout(async () =>
|
||||
{
|
||||
recordAnalytics({category: "processEvents", action: "processStep", label: activeStep.label});
|
||||
|
||||
const processResponse = await Client.getInstance().processStep(
|
||||
processName,
|
||||
processUUID,
|
||||
activeStep.name,
|
||||
formData,
|
||||
formDataHeaders,
|
||||
);
|
||||
setLastProcessResponse(processResponse);
|
||||
});
|
||||
doSubmit(formData);
|
||||
};
|
||||
|
||||
|
||||
@ -1829,7 +1899,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
mainCardStyles.display = "flex";
|
||||
}
|
||||
|
||||
return mainCardStyles
|
||||
return mainCardStyles;
|
||||
}
|
||||
|
||||
let nextButtonLabel = "Next";
|
||||
@ -1854,7 +1924,7 @@ function ProcessRun({process, table, defaultProcessValues, isModal, isWidget, is
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationScheme}
|
||||
validation={validationFunction}
|
||||
onSubmit={handleSubmit}
|
||||
onSubmit={handleFormSubmit}
|
||||
>
|
||||
{({
|
||||
values, errors, touched, isSubmitting, setFieldValue, setTouched
|
||||
|
Reference in New Issue
Block a user