From 18c15543f9787d8e655a791c87205cb1dea0df3f Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Mon, 5 Dec 2022 16:08:50 -0600 Subject: [PATCH] Add add-child capability to recordGridWidget; making new standard Widget that others can(should) use --- cypress/e2e/entity-list.spec.cy.ts | 33 +- cypress/e2e/lib/qLib.ts | 86 +++++ src/qqq/components/DashboardWidgets.tsx | 16 +- src/qqq/components/EntityForm/index.tsx | 321 ++++++++++++------ src/qqq/components/QDynamicForm/index.tsx | 1 + .../pages/dashboards/CarrierPerformance.tsx | 8 +- src/qqq/pages/dashboards/Overview.tsx | 6 +- .../dashboards/Widgets/RecordGridWidget.tsx | 54 ++- src/qqq/pages/dashboards/Widgets/Widget.tsx | 194 +++++++++++ src/qqq/pages/entity-view/EntityView.tsx | 8 +- src/qqq/pages/process-run/index.tsx | 2 +- 11 files changed, 564 insertions(+), 165 deletions(-) create mode 100644 cypress/e2e/lib/qLib.ts create mode 100644 src/qqq/pages/dashboards/Widgets/Widget.tsx diff --git a/cypress/e2e/entity-list.spec.cy.ts b/cypress/e2e/entity-list.spec.cy.ts index 886f20c..c1dc525 100644 --- a/cypress/e2e/entity-list.spec.cy.ts +++ b/cypress/e2e/entity-list.spec.cy.ts @@ -1,10 +1,13 @@ /// +import QLib from "./lib/qLib"; + describe("table query screen", () => { - before(() => { + QLib.init(cy); + cy.intercept("GET", "/metaData/authentication", {fixture: "metaData/authentication.json"}).as("authenticationMetaData"); cy.intercept("GET", "/metaData", {fixture: "metaData/index.json"}).as("metaData"); cy.intercept("GET", "/metaData/table/person", {fixture: "metaData/table/person.json"}).as("personMetaData"); @@ -29,14 +32,13 @@ describe("table query screen", () => }); }); - it.only("can add query filters", () => + it("can add query filters", () => { ///////////////////////////////////////////////////////////// // go to table, wait for filter to run, and rows to appear // ///////////////////////////////////////////////////////////// cy.visit("https://localhost:3000/peopleApp/greetingsApp/person"); - cy.wait(["@personQuery", "@personCount"]); - cy.get(".MuiDataGrid-virtualScrollerRenderZone").children().should("have.length.greaterThan", 3); + QLib.waitForQueryScreen(); ///////////////////////////////////////////////////////////////////// // open the filter window, enter a value, wait for query to re-run // @@ -72,6 +74,29 @@ describe("table query screen", () => cy.contains(".MuiDataGrid-toolbarContainer .MuiBadge-root", "1").should("not.exist"); }); + it.only("can do a boolean or query", () => + { + ///////////////////////////////////////// + // go to table, wait for filter to run // + ///////////////////////////////////////// + cy.visit("https://localhost:3000/peopleApp/greetingsApp/person"); + QLib.waitForQueryScreen(); + + QLib.buildEntityListQueryFilter([ + {fieldLabel: "First Name", operator: "contains", textValue: "Dar"}, + {fieldLabel: "First Name", operator: "contains", textValue: "Jam"} + ], "or"); + + let expectedFilterContents0 = JSON.stringify({fieldName: "firstName", operator: "CONTAINS", values: ["Dar"]}); + let expectedFilterContents1 = JSON.stringify({fieldName: "firstName", operator: "CONTAINS", values: ["Jam"]}); + cy.wait("@personQuery").its("request.body").should((body) => + { + expect(body).to.contain(expectedFilterContents0); + expect(body).to.contain(expectedFilterContents1); + expect(body).to.contain("asdf"); + }); + }); + // tests to add: // - filter boolean OR // - sort column diff --git a/cypress/e2e/lib/qLib.ts b/cypress/e2e/lib/qLib.ts new file mode 100644 index 0000000..ccac102 --- /dev/null +++ b/cypress/e2e/lib/qLib.ts @@ -0,0 +1,86 @@ +/* + * 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 . + */ + +export default class QLib +{ + // @ts-ignore + private static cy: Cypress.cy; + + // @ts-ignore + public static init(cy: Cypress.cy) + { + QLib.cy = cy; + } + + /******************************************************************************* + ** Wait for a query to finish on the entity-list screen. specifically, wait for + ** personQuery & personCount requests, and wait for the data grid to have rows. + *******************************************************************************/ + public static waitForQueryScreen() + { + QLib.cy.wait(["@personQuery", "@personCount"]); + QLib.cy.get(".MuiDataGrid-virtualScrollerRenderZone").children().should("have.length.greaterThan", 3); + } + + /******************************************************************************* + ** Open the Filters drop down, and build a query + *******************************************************************************/ + public static buildEntityListQueryFilter(input: QueryFilterInput | QueryFilterInput[], booleanOperator: ("and" | "or") = "and") + { + QLib.cy.contains("Filters").click(); + + if ((input as QueryFilterInput).fieldLabel) + { + const queryFilterInput = input as QueryFilterInput; + QLib.addSingleQueryFilterInput(queryFilterInput, 0, booleanOperator); + } + else + { + const inputArray = input as QueryFilterInput[]; + inputArray.forEach((qfi, index) => QLib.addSingleQueryFilterInput(qfi, index, booleanOperator)); + } + } + + /******************************************************************************* + ** private helper - adds 1 query filter input. + *******************************************************************************/ + private static addSingleQueryFilterInput(queryFilterInput: QueryFilterInput, index: number, booleanOperator: ("and" | "or")) + { + if (index > 0) + { + QLib.cy.contains("Add filter").click(); + QLib.cy.get(".MuiDataGrid-filterForm").eq(index).find(".MuiDataGrid-filterFormLinkOperatorInput SELECT").select(booleanOperator); + } + + QLib.cy.get(".MuiDataGrid-filterForm").eq(index).find(".MuiDataGrid-filterFormColumnInput SELECT").select(queryFilterInput.fieldLabel); + QLib.cy.get(".MuiDataGrid-filterForm").eq(index).find(".MuiDataGrid-filterFormOperatorInput SELECT").select(queryFilterInput.operator); + QLib.cy.get(".MuiDataGrid-filterForm").eq(index).find(".MuiDataGrid-filterFormValueInput INPUT").type(queryFilterInput.textValue); + } + +} + +interface QueryFilterInput +{ + fieldLabel?: string; + fieldName?: string; + operator?: string; + textValue?: string; +} diff --git a/src/qqq/components/DashboardWidgets.tsx b/src/qqq/components/DashboardWidgets.tsx index 8259195..c4a81a5 100644 --- a/src/qqq/components/DashboardWidgets.tsx +++ b/src/qqq/components/DashboardWidgets.tsx @@ -21,6 +21,7 @@ import {QInstance} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QInstance"; import {QWidgetMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QWidgetMetaData"; import {Skeleton} from "@mui/material"; +import Box from "@mui/material/Box"; import Card from "@mui/material/Card"; import Grid from "@mui/material/Grid"; import parse from "html-react-parser"; @@ -37,6 +38,7 @@ import QuickSightChart from "qqq/pages/dashboards/Widgets/QuickSightChart"; import RecordGridWidget from "qqq/pages/dashboards/Widgets/RecordGridWidget"; import StepperCard from "qqq/pages/dashboards/Widgets/StepperCard"; import TableCard from "qqq/pages/dashboards/Widgets/TableCard"; +import Widget from "qqq/pages/dashboards/Widgets/Widget"; import ProcessRun from "qqq/pages/process-run"; import QClient from "qqq/utils/QClient"; @@ -116,7 +118,7 @@ function DashboardWidgets({widgetMetaDataList, entityPrimaryKey, omitWrappingGri const renderWidget = (widgetMetaData: QWidgetMetaData, i: number): JSX.Element => { return ( - + { widgetMetaData.type === "parentWidget" && ( - - - {widgetMetaData.label} - + + { widgetData && widgetData[i] && widgetData[i].html ? ( @@ -177,8 +176,8 @@ function DashboardWidgets({widgetMetaDataList, entityPrimaryKey, omitWrappingGri ) : } - - + + ) } { @@ -233,6 +232,7 @@ function DashboardWidgets({widgetMetaDataList, entityPrimaryKey, omitWrappingGri ) } diff --git a/src/qqq/components/EntityForm/index.tsx b/src/qqq/components/EntityForm/index.tsx index 722e81e..49ab1ed 100644 --- a/src/qqq/components/EntityForm/index.tsx +++ b/src/qqq/components/EntityForm/index.tsx @@ -24,9 +24,11 @@ import {QFieldMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QF import {QFieldType} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QFieldType"; import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData"; import {QTableSection} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableSection"; +import {QPossibleValue} from "@kingsrook/qqq-frontend-core/lib/model/QPossibleValue"; import {QRecord} from "@kingsrook/qqq-frontend-core/lib/model/QRecord"; import {Alert} from "@mui/material"; import Avatar from "@mui/material/Avatar"; +import Box from "@mui/material/Box"; import Card from "@mui/material/Card"; import Grid from "@mui/material/Grid"; import Icon from "@mui/material/Icon"; @@ -49,10 +51,23 @@ import QValueUtils from "qqq/utils/QValueUtils"; interface Props { id?: string; + isModal: boolean; table?: QTableMetaData; + closeModalHandler?: (event: object, reason: string) => void; + defaultValues: { [key: string]: string }; + disabledFields: { [key: string]: boolean }; } -function EntityForm({table, id}: Props): JSX.Element +EntityForm.defaultProps = { + id: null, + isModal: false, + table: null, + closeModalHandler: null, + defaultValues: {}, + disabledFields: {}, +}; + +function EntityForm({table, isModal, id, closeModalHandler, defaultValues, disabledFields}: Props): JSX.Element { const qController = QClient.getInstance(); const tableNameParam = useParams().tableName; @@ -126,39 +141,89 @@ function EntityForm({table, id}: Props): JSX.Element // if doing an edit, fetch the record and pre-populate the form values from it // ///////////////////////////////////////////////////////////////////////////////// let record: QRecord = null; + let defaultDisplayValues = new Map(); if (id !== null) { record = await qController.get(tableName, id); setRecord(record); setFormTitle(`Edit ${tableMetaData?.label}: ${record?.recordLabel}`); - setPageHeader(`Edit ${tableMetaData?.label}: ${record?.recordLabel}`); + + if (!isModal) + { + setPageHeader(`Edit ${tableMetaData?.label}: ${record?.recordLabel}`); + } tableMetaData.fields.forEach((fieldMetaData, key) => { initialValues[key] = record.values.get(key); - if(fieldMetaData.type == QFieldType.DATE_TIME) - { - initialValues[key] = QValueUtils.formatDateTimeValueForForm(record.values.get(key)); - } }); - setFormValues(formValues); + //? safe to delete? setFormValues(formValues); - if(!tableMetaData.capabilities.has(Capability.TABLE_UPDATE)) + if (!tableMetaData.capabilities.has(Capability.TABLE_UPDATE)) { setNoCapabilityError("You may not edit records in this table"); } } else { + /////////////////////////////////////////// + // else handle preparing to do an insert // + /////////////////////////////////////////// setFormTitle(`Creating New ${tableMetaData?.label}`); - setPageHeader(`Creating New ${tableMetaData?.label}`); - if(!tableMetaData.capabilities.has(Capability.TABLE_INSERT)) + if (!isModal) + { + setPageHeader(`Creating New ${tableMetaData?.label}`); + } + + if (!tableMetaData.capabilities.has(Capability.TABLE_INSERT)) { setNoCapabilityError("You may not create records in this table"); } + + //////////////////////////////////////////////////////////////////////////////////////////////// + // if default values were supplied for a new record, then populate initialValues, for formik. // + //////////////////////////////////////////////////////////////////////////////////////////////// + if(defaultValues) + { + for (let i = 0; i < fieldArray.length; i++) + { + const fieldMetaData = fieldArray[i]; + const fieldName = fieldMetaData.name; + if (defaultValues[fieldName]) + { + initialValues[fieldName] = defaultValues[fieldName]; + + /////////////////////////////////////////////////////////////////////////////////////////// + // we need to set the initialDisplayValue for possible value fields with a default value // + // so, look them up here now if needed // + /////////////////////////////////////////////////////////////////////////////////////////// + if (fieldMetaData.possibleValueSourceName) + { + const results: QPossibleValue[] = await qController.possibleValues(tableName, fieldName, null, [initialValues[fieldName]]); + if (results && results.length > 0) + { + defaultDisplayValues.set(fieldName, results[0].label); + } + } + } + } + } } + + ///////////////////////////////////////////////////////////////////// + // make sure all initialValues are properly formatted for the form // + ///////////////////////////////////////////////////////////////////// + for (let i = 0; i < fieldArray.length; i++) + { + const fieldMetaData = fieldArray[i]; + if (fieldMetaData.type == QFieldType.DATE_TIME && initialValues[fieldMetaData.name]) + { + initialValues[fieldMetaData.name] = QValueUtils.formatDateTimeValueForForm(initialValues[fieldMetaData.name]); + } + } + setInitialValues(initialValues); ///////////////////////////////////////////////////////// @@ -168,7 +233,15 @@ function EntityForm({table, id}: Props): JSX.Element dynamicFormFields, formValidations, } = DynamicFormUtils.getFormData(fieldArray); - DynamicFormUtils.addPossibleValueProps(dynamicFormFields, fieldArray, tableName, record?.displayValues); + DynamicFormUtils.addPossibleValueProps(dynamicFormFields, fieldArray, tableName, record ? record.displayValues : defaultDisplayValues); + + if(disabledFields) + { + for (let fieldName in disabledFields) + { + dynamicFormFields[fieldName].isEditable = false; + } + } ///////////////////////////////////// // group the formFields by section // @@ -181,12 +254,7 @@ function EntityForm({table, id}: Props): JSX.Element const section = tableSections[i]; const sectionDynamicFormFields: any[] = []; - if(section.isHidden) - { - continue; - } - - if(!section.fieldNames) + if (section.isHidden || !section.fieldNames) { continue; } @@ -271,8 +339,15 @@ function EntityForm({table, id}: Props): JSX.Element .update(tableName, id, values) .then((record) => { - const path = `${location.pathname.replace(/\/edit$/, "")}?updateSuccess=true`; - navigate(path); + if (isModal) + { + closeModalHandler(null, "recordUpdated"); + } + else + { + const path = `${location.pathname.replace(/\/edit$/, "")}?updateSuccess=true`; + navigate(path); + } }) .catch((error) => { @@ -287,8 +362,15 @@ function EntityForm({table, id}: Props): JSX.Element .create(tableName, values) .then((record) => { - const path = `${location.pathname.replace(/create$/, record.values.get(tableMetaData.primaryKeyField))}?createSuccess=true`; - navigate(path); + if (isModal) + { + closeModalHandler(null, "recordCreated"); + } + else + { + const path = `${location.pathname.replace(/create$/, record.values.get(tableMetaData.primaryKeyField))}?createSuccess=true`; + navigate(path); + } }) .catch((error) => { @@ -300,111 +382,128 @@ function EntityForm({table, id}: Props): JSX.Element const formId = id != null ? `edit-${tableMetaData?.name}-form` : `create-${tableMetaData?.name}-form`; - if(noCapabilityError) + let body; + if (noCapabilityError) { - return - - - - {noCapabilityError} - - - - ; - } - - return ( - - - - {alertContent ? ( + body = ( + + + - {alertContent} + {noCapabilityError} - ) : ("")} + - - - - + + ); + } + else + { + const cardElevation = isModal ? 3 : 1; + body = ( + + + + {alertContent ? ( + + {alertContent} + + ) : ("")} + - + + { + !isModal && + + + + } + - - {({ - values, - errors, - touched, - isSubmitting, - }) => ( -
+ + {({ + values, + errors, + touched, + isSubmitting, + }) => ( + - - - - - - - {tableMetaData?.iconName} - - + + + + + + + {tableMetaData?.iconName} + + + + + {formTitle} + - - {formTitle} - - - { - t1sectionName && formFields ? ( - - - {getFormSection(values, touched, formFields.get(t1sectionName), errors)} + { + t1sectionName && formFields ? ( + + + {getFormSection(values, touched, formFields.get(t1sectionName), errors)} + - - ) : null - } - - - {formFields && nonT1Sections.length ? nonT1Sections.map((section: QTableSection) => ( - - - - {section.label} - - - - { - getFormSection(values, touched, formFields.get(section.name), errors) - } - - + ) : null + } - )) : null} + {formFields && nonT1Sections.length ? nonT1Sections.map((section: QTableSection) => ( + + + + {section.label} + + + + {getFormSection(values, touched, formFields.get(section.name), errors)} + + + + + )) : null} - - - - - - + + + + + + - - )} -
+ + )} +
+
-
-
- ); +
+ ); + } + + if (isModal) + { + return ( + + + {body} + + + ); + } + else + { + return (body); + } } -EntityForm.defaultProps = { - id: null, - table: null, -}; - export default EntityForm; diff --git a/src/qqq/components/QDynamicForm/index.tsx b/src/qqq/components/QDynamicForm/index.tsx index 82f2998..14c4371 100644 --- a/src/qqq/components/QDynamicForm/index.tsx +++ b/src/qqq/components/QDynamicForm/index.tsx @@ -133,6 +133,7 @@ function QDynamicForm(props: Props): JSX.Element diff --git a/src/qqq/pages/dashboards/Overview.tsx b/src/qqq/pages/dashboards/Overview.tsx index 041eef4..6f69b20 100644 --- a/src/qqq/pages/dashboards/Overview.tsx +++ b/src/qqq/pages/dashboards/Overview.tsx @@ -265,7 +265,7 @@ function Overview(): JSX.Element @@ -285,7 +285,7 @@ function Overview(): JSX.Element void; } -RecordGridWidget.defaultProps = { -}; +RecordGridWidget.defaultProps = {}; -function RecordGridWidget({title, data}: Props): JSX.Element +function RecordGridWidget({title, data, reloadWidgetCallback}: Props): JSX.Element { const [rows, setRows] = useState([]); - const [columns, setColumns] = useState([]) + const [columns, setColumns] = useState([]); useEffect(() => { - if(data && data.childTableMetaData && data.queryOutput) + if (data && data.childTableMetaData && data.queryOutput) { const records: QRecord[] = []; const queryOutputRecords = data.queryOutput.records; @@ -60,28 +56,26 @@ function RecordGridWidget({title, data}: Props): JSX.Element const tableMetaData = new QTableMetaData(data.childTableMetaData); const {rows, columnsToRender} = DataGridUtils.makeRows(records, tableMetaData); - const columns = DataGridUtils.setupGridColumns(tableMetaData, columnsToRender, data.tablePath); + + const childTablePath = data.tablePath + (data.tablePath.endsWith("/") ? "" : "/") + const columns = DataGridUtils.setupGridColumns(tableMetaData, columnsToRender, childTablePath); setRows(rows); setColumns(columns); } - }, [data]) + }, [data]); return ( - - - - {title} - - { - data.viewAllLink && - - - View All - - - } - + - - ) + + ); } export default RecordGridWidget; diff --git a/src/qqq/pages/dashboards/Widgets/Widget.tsx b/src/qqq/pages/dashboards/Widgets/Widget.tsx new file mode 100644 index 0000000..ed84665 --- /dev/null +++ b/src/qqq/pages/dashboards/Widgets/Widget.tsx @@ -0,0 +1,194 @@ +/* + * 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 . + */ + +import {QTableMetaData} from "@kingsrook/qqq-frontend-core/lib/model/metaData/QTableMetaData"; +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import Card from "@mui/material/Card"; +import Modal from "@mui/material/Modal"; +import Typography from "@mui/material/Typography"; +import React, {useState} from "react"; +import {Link} from "react-router-dom"; +import EntityForm from "qqq/components/EntityForm"; + +interface Props +{ + label: string; + labelAdditionalComponentsLeft: [LabelComponent]; + labelAdditionalComponentsRight: [LabelComponent]; + children: JSX.Element; + reloadWidgetCallback?: (widgetIndex: number, params: string) => void; +} + +Widget.defaultProps = { + label: null, + labelAdditionalComponentsLeft: [], + labelAdditionalComponentsRight: [], +}; + + + +class LabelComponent +{ + +} + + + +export class HeaderLink extends LabelComponent +{ + label: string; + to: string + + constructor(label: string, to: string) + { + super(); + this.label = label; + this.to = to; + } +} + + + +export class AddNewRecordButton extends LabelComponent +{ + table: QTableMetaData; + label:string; + defaultValues: any; + disabledFields: any; + + constructor(table: QTableMetaData, defaultValues: any, label: string = "Add new", disabledFields: any = defaultValues) + { + super(); + this.table = table; + this.label = label; + this.defaultValues = defaultValues; + this.disabledFields = disabledFields; + } +} + + + +function Widget(props: React.PropsWithChildren): JSX.Element +{ + const [showEditForm, setShowEditForm] = useState(null as any); + + function openEditForm(table: QTableMetaData, id: any = null, defaultValues: any, disabledFields: any) + { + const showEditForm: any = {}; + showEditForm.table = table; + showEditForm.id = id; + showEditForm.defaultValues = defaultValues; + showEditForm.disabledFields = disabledFields; + setShowEditForm(showEditForm); + } + + const closeEditForm = (event: object, reason: string) => + { + if (reason === "backdropClick") + { + return; + } + + if (reason === "recordUpdated" || reason === "recordCreated") + { + if(props.reloadWidgetCallback) + { + props.reloadWidgetCallback(0, "ok"); + } + else + { + window.location.reload() + } + } + + setShowEditForm(null); + }; + + function renderComponent(component: LabelComponent) + { + if(component instanceof HeaderLink) + { + const link = component as HeaderLink + return ( + + {link.to ? {link.label} : null} + + ); + } + + if (component instanceof AddNewRecordButton) + { + const addNewRecordButton = component as AddNewRecordButton + return ( + + + + ); + } + + } + + return ( + <> + + + + + {props.label} + + { + props.labelAdditionalComponentsLeft.map((component, i) => + { + return ({renderComponent(component)}); + }) + } + + + { + props.labelAdditionalComponentsRight.map((component, i) => + { + return ({renderComponent(component)}); + }) + } + + + {props.children} + + { + showEditForm && + closeEditForm(event, reason)}> +
+ +
+
+ } + + ); +} + +export default Widget; diff --git a/src/qqq/pages/entity-view/EntityView.tsx b/src/qqq/pages/entity-view/EntityView.tsx index 4e8a546..a7225eb 100644 --- a/src/qqq/pages/entity-view/EntityView.tsx +++ b/src/qqq/pages/entity-view/EntityView.tsx @@ -273,9 +273,9 @@ function EntityView({table, launchProcess}: Props): JSX.Element { sectionFieldElements.set(section.name, - + - + {section.label} @@ -466,9 +466,9 @@ function EntityView({table, launchProcess}: Props): JSX.Element {nonT1TableSections.length > 0 ? nonT1TableSections.map(({ iconName, label, name, fieldNames, tier, }: any) => ( - <> + {sectionFieldElements.get(name)} - + )) : null} diff --git a/src/qqq/pages/process-run/index.tsx b/src/qqq/pages/process-run/index.tsx index 62cc234..f85cf79 100644 --- a/src/qqq/pages/process-run/index.tsx +++ b/src/qqq/pages/process-run/index.tsx @@ -275,7 +275,7 @@ function ProcessRun({process, defaultProcessValues, isModal, isWidget, recordIds - + Working