diff --git a/src/qqq/components/forms/EntityForm.tsx b/src/qqq/components/forms/EntityForm.tsx index bf41afd..6360250 100644 --- a/src/qqq/components/forms/EntityForm.tsx +++ b/src/qqq/components/forms/EntityForm.tsx @@ -66,7 +66,7 @@ interface Props defaultValues: { [key: string]: string }; disabledFields: { [key: string]: boolean } | string[]; isCopy?: boolean; - onSubmitCallback?: (values: any) => void; + onSubmitCallback?: (values: any, tableName: string) => void; overrideHeading?: string; } @@ -173,7 +173,7 @@ function EntityForm(props: Props): JSX.Element *******************************************************************************/ function openAddChildRecord(name: string, widgetData: any) { - let defaultValues = widgetData.defaultValuesForNewChildRecords; + let defaultValues = widgetData.defaultValuesForNewChildRecords || {}; let disabledFields = widgetData.disabledFieldsForNewChildRecords; if (!disabledFields) @@ -181,6 +181,18 @@ function EntityForm(props: Props): JSX.Element disabledFields = widgetData.defaultValuesForNewChildRecords; } + /////////////////////////////////////////////////////////////////////////////////////// + // copy values from specified fields in the parent record down into the child record // + /////////////////////////////////////////////////////////////////////////////////////// + if(widgetData.defaultValuesForNewChildRecordsFromParentFields) + { + for(let childField in widgetData.defaultValuesForNewChildRecordsFromParentFields) + { + const parentField = widgetData.defaultValuesForNewChildRecordsFromParentFields[childField]; + defaultValues[childField] = formValues[parentField]; + } + } + doOpenEditChildForm(name, widgetData.childTableMetaData, null, defaultValues, disabledFields); } @@ -208,7 +220,7 @@ function EntityForm(props: Props): JSX.Element function deleteChildRecord(name: string, widgetData: any, rowIndex: number) { updateChildRecordList(name, "delete", rowIndex); - }; + } /******************************************************************************* @@ -243,16 +255,16 @@ function EntityForm(props: Props): JSX.Element /******************************************************************************* ** *******************************************************************************/ - function submitEditChildForm(values: any) + function submitEditChildForm(values: any, tableName: string) { - updateChildRecordList(showEditChildForm.widgetName, showEditChildForm.rowIndex == null ? "insert" : "edit", showEditChildForm.rowIndex, values); + updateChildRecordList(showEditChildForm.widgetName, showEditChildForm.rowIndex == null ? "insert" : "edit", showEditChildForm.rowIndex, values, tableName); } /******************************************************************************* ** *******************************************************************************/ - async function updateChildRecordList(widgetName: string, action: "insert" | "edit" | "delete", rowIndex?: number, values?: any) + async function updateChildRecordList(widgetName: string, action: "insert" | "edit" | "delete", rowIndex?: number, values?: any, childTableName?: string) { const metaData = await qController.loadMetaData(); const widgetMetaData = metaData.widgets.get(widgetName); @@ -263,13 +275,38 @@ function EntityForm(props: Props): JSX.Element newChildListWidgetData[widgetName].queryOutput.records = []; } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // build a map of display values for the new record, specifically, for any possible-values that need translated. // + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + const displayValues: {[fieldName: string]: string} = {}; + if(childTableName && values) + { + /////////////////////////////////////////////////////////////////////////////////////////////////////// + // this function internally memoizes, so, we could potentially avoid an await here, but, seems ok... // + /////////////////////////////////////////////////////////////////////////////////////////////////////// + const childTableMetaData = await qController.loadTableMetaData(childTableName) + for (let key in values) + { + const value = values[key]; + const field = childTableMetaData.fields.get(key); + if(field.possibleValueSourceName) + { + const possibleValues = await qController.possibleValues(childTableName, null, field.name, null, [value], objectToMap(values), "form") + if(possibleValues && possibleValues.length > 0) + { + displayValues[key] = possibleValues[0].label; + } + } + } + } + switch (action) { case "insert": - newChildListWidgetData[widgetName].queryOutput.records.push({values: values}); + newChildListWidgetData[widgetName].queryOutput.records.push({values: values, displayValues: displayValues}); break; case "edit": - newChildListWidgetData[widgetName].queryOutput.records[rowIndex] = {values: values}; + newChildListWidgetData[widgetName].queryOutput.records[rowIndex] = {values: values, displayValues: displayValues}; break; case "delete": newChildListWidgetData[widgetName].queryOutput.records.splice(rowIndex, 1); @@ -479,6 +516,26 @@ function EntityForm(props: Props): JSX.Element } + + /*************************************************************************** + ** + ***************************************************************************/ + function objectToMap(object: { [key: string]: any }): Map + { + if(object == null) + { + return (null); + } + + const rs = new Map(); + for (let key in object) + { + rs.set(key, object[key]); + } + return rs + } + + ////////////////// // initial load // ////////////////// @@ -596,18 +653,24 @@ function EntityForm(props: Props): JSX.Element if (defaultValue) { initialValues[fieldName] = defaultValue; + } + } - /////////////////////////////////////////////////////////////////////////////////////////// - // 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) + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // do a second loop, this time looking up display-values for any possible-value fields with a default value // + // do it in a second loop, to pass in all the other values (from initialValues), in case there's a PVS filter that needs them. // + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + for (let i = 0; i < fieldArray.length; i++) + { + const fieldMetaData = fieldArray[i]; + const fieldName = fieldMetaData.name; + const defaultValue = (defaultValues && defaultValues[fieldName]) ? defaultValues[fieldName] : fieldMetaData.defaultValue; + if (defaultValue && fieldMetaData.possibleValueSourceName) + { + const results: QPossibleValue[] = await qController.possibleValues(tableName, null, fieldName, null, [initialValues[fieldName]], objectToMap(initialValues), "form"); + if (results && results.length > 0) { - const results: QPossibleValue[] = await qController.possibleValues(tableName, null, fieldName, null, [initialValues[fieldName]], undefined, "form"); - if (results && results.length > 0) - { - defaultDisplayValues.set(fieldName, results[0].label); - } + defaultDisplayValues.set(fieldName, results[0].label); } } } @@ -824,7 +887,7 @@ function EntityForm(props: Props): JSX.Element //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// if (props.onSubmitCallback) { - props.onSubmitCallback(values); + props.onSubmitCallback(values, tableName); return; } diff --git a/src/qqq/components/widgets/DashboardWidgets.tsx b/src/qqq/components/widgets/DashboardWidgets.tsx index b62db37..fbc182b 100644 --- a/src/qqq/components/widgets/DashboardWidgets.tsx +++ b/src/qqq/components/widgets/DashboardWidgets.tsx @@ -368,7 +368,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco /******************************************************************************* ** *******************************************************************************/ - function submitEditChildForm(values: any) + function submitEditChildForm(values: any, tableName: string) { updateChildRecordList(showEditChildForm.widgetName, showEditChildForm.rowIndex == null ? "insert" : "edit", showEditChildForm.rowIndex, values); let widgetIndex = determineChildRecordListIndex(showEditChildForm.widgetName); @@ -718,6 +718,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, reco addNewRecordCallback={widgetData[i]?.isInProcess ? () => openAddChildRecord(widgetMetaData.name, widgetData[i]) : null} widgetMetaData={widgetMetaData} data={widgetData[i]} + parentRecord={record} /> ) diff --git a/src/qqq/components/widgets/misc/RecordGridWidget.tsx b/src/qqq/components/widgets/misc/RecordGridWidget.tsx index 18918c4..f9cd56e 100644 --- a/src/qqq/components/widgets/misc/RecordGridWidget.tsx +++ b/src/qqq/components/widgets/misc/RecordGridWidget.tsx @@ -40,7 +40,7 @@ import {Link, useNavigate} from "react-router-dom"; export interface ChildRecordListData extends WidgetData { title?: string; - queryOutput?: { records: { values: any }[] }; + queryOutput?: { records: { values: any, displayValues?: any } [] }; childTableMetaData?: QTableMetaData; tablePath?: string; viewAllLink?: string; @@ -48,20 +48,22 @@ export interface ChildRecordListData extends WidgetData canAddChildRecord?: boolean; defaultValuesForNewChildRecords?: { [fieldName: string]: any }; disabledFieldsForNewChildRecords?: { [fieldName: string]: any }; + defaultValuesForNewChildRecordsFromParentFields?: { [fieldName: string]: string }; } interface Props { - widgetMetaData: QWidgetMetaData; - data: ChildRecordListData; - addNewRecordCallback?: () => void; - disableRowClick: boolean; - allowRecordEdit: boolean; - editRecordCallback?: (rowIndex: number) => void; - allowRecordDelete: boolean; - deleteRecordCallback?: (rowIndex: number) => void; - gridOnly?: boolean; - gridDensity?: GridDensity; + widgetMetaData: QWidgetMetaData, + data: ChildRecordListData, + addNewRecordCallback?: () => void, + disableRowClick: boolean, + allowRecordEdit: boolean, + editRecordCallback?: (rowIndex: number) => void, + allowRecordDelete: boolean, + deleteRecordCallback?: (rowIndex: number) => void, + gridOnly?: boolean, + gridDensity?: GridDensity, + parentRecord?: QRecord } RecordGridWidget.defaultProps = @@ -74,7 +76,7 @@ RecordGridWidget.defaultProps = const qController = Client.getInstance(); -function RecordGridWidget({widgetMetaData, data, addNewRecordCallback, disableRowClick, allowRecordEdit, editRecordCallback, allowRecordDelete, deleteRecordCallback, gridOnly, gridDensity}: Props): JSX.Element +function RecordGridWidget({widgetMetaData, data, addNewRecordCallback, disableRowClick, allowRecordEdit, editRecordCallback, allowRecordDelete, deleteRecordCallback, gridOnly, gridDensity, parentRecord}: Props): JSX.Element { const instance = useRef({timer: null}); const [rows, setRows] = useState([]); @@ -97,7 +99,7 @@ function RecordGridWidget({widgetMetaData, data, addNewRecordCallback, disableRo { for (let i = 0; i < queryOutputRecords.length; i++) { - if(queryOutputRecords[i] instanceof QRecord) + if (queryOutputRecords[i] instanceof QRecord) { records.push(queryOutputRecords[i] as QRecord); } @@ -252,7 +254,22 @@ function RecordGridWidget({widgetMetaData, data, addNewRecordCallback, disableRo { disabledFields = data.defaultValuesForNewChildRecords; } - labelAdditionalComponentsRight.push(new AddNewRecordButton(data.childTableMetaData, data.defaultValuesForNewChildRecords, "Add new", disabledFields, addNewRecordCallback)); + + const defaultValuesForNewChildRecords = data.defaultValuesForNewChildRecords || {} + + /////////////////////////////////////////////////////////////////////////////////////// + // copy values from specified fields in the parent record down into the child record // + /////////////////////////////////////////////////////////////////////////////////////// + if(data.defaultValuesForNewChildRecordsFromParentFields) + { + for(let childField in data.defaultValuesForNewChildRecordsFromParentFields) + { + const parentField = data.defaultValuesForNewChildRecordsFromParentFields[childField]; + defaultValuesForNewChildRecords[childField] = parentRecord?.values?.get(parentField); + } + } + + labelAdditionalComponentsRight.push(new AddNewRecordButton(data.childTableMetaData, defaultValuesForNewChildRecords, "Add new", disabledFields, addNewRecordCallback)); } @@ -357,7 +374,7 @@ function RecordGridWidget({widgetMetaData, data, addNewRecordCallback, disableRo /> ); - if(gridOnly) + if (gridOnly) { return (grid); } diff --git a/src/qqq/components/widgets/tables/ModalEditForm.tsx b/src/qqq/components/widgets/tables/ModalEditForm.tsx index 69219f9..a53bab4 100644 --- a/src/qqq/components/widgets/tables/ModalEditForm.tsx +++ b/src/qqq/components/widgets/tables/ModalEditForm.tsx @@ -35,7 +35,7 @@ export interface ModalEditFormData defaultValues?: { [key: string]: string }; disabledFields?: { [key: string]: boolean } | string[]; overrideHeading?: string; - onSubmitCallback?: (values: any) => void; + onSubmitCallback?: (values: any, tableName: String) => void; initialShowModalValue?: boolean; }