add html (process) component type and make PVS's work in processes; fix some nav-back-and-forth wierdness on query screen

This commit is contained in:
2023-02-22 17:58:13 -06:00
parent 07b71afa83
commit bf0fc495bf
10 changed files with 103 additions and 54 deletions

View File

@ -6,7 +6,7 @@
"@auth0/auth0-react": "1.10.2", "@auth0/auth0-react": "1.10.2",
"@emotion/react": "11.7.1", "@emotion/react": "11.7.1",
"@emotion/styled": "11.6.0", "@emotion/styled": "11.6.0",
"@kingsrook/qqq-frontend-core": "1.0.52", "@kingsrook/qqq-frontend-core": "1.0.53",
"@mui/icons-material": "5.4.1", "@mui/icons-material": "5.4.1",
"@mui/material": "5.11.1", "@mui/material": "5.11.1",
"@mui/styles": "5.11.1", "@mui/styles": "5.11.1",

View File

@ -131,6 +131,7 @@ function QDynamicForm(props: Props): JSX.Element
<Grid item xs={12} sm={6} key={fieldName}> <Grid item xs={12} sm={6} key={fieldName}>
<DynamicSelect <DynamicSelect
tableName={field.possibleValueProps.tableName} tableName={field.possibleValueProps.tableName}
processName={field.possibleValueProps.processName}
fieldName={fieldName} fieldName={fieldName}
isEditable={field.isEditable} isEditable={field.isEditable}
fieldLabel={field.label} fieldLabel={field.label}

View File

@ -109,7 +109,7 @@ class DynamicFormUtils
return (null); return (null);
} }
public static addPossibleValueProps(dynamicFormFields: any, qFields: QFieldMetaData[], tableName: string, displayValues: Map<string, string>) public static addPossibleValueProps(dynamicFormFields: any, qFields: QFieldMetaData[], tableName: string, processName: string, displayValues: Map<string, string>)
{ {
for (let i = 0; i < qFields.length; i++) for (let i = 0; i < qFields.length; i++)
{ {
@ -126,6 +126,8 @@ class DynamicFormUtils
initialDisplayValue = displayValues.get(field.name); initialDisplayValue = displayValues.get(field.name);
} }
if (tableName)
{
dynamicFormFields[field.name].possibleValueProps = dynamicFormFields[field.name].possibleValueProps =
{ {
isPossibleValue: true, isPossibleValue: true,
@ -133,6 +135,16 @@ class DynamicFormUtils
initialDisplayValue: initialDisplayValue, initialDisplayValue: initialDisplayValue,
}; };
} }
else
{
dynamicFormFields[field.name].possibleValueProps =
{
isPossibleValue: true,
processName: processName,
initialDisplayValue: initialDisplayValue,
};
}
}
} }
} }
} }

View File

@ -35,7 +35,8 @@ import Client from "qqq/utils/qqq/Client";
interface Props interface Props
{ {
tableName: string; tableName?: string;
processName?: string;
fieldName: string; fieldName: string;
fieldLabel: string; fieldLabel: string;
inForm: boolean; inForm: boolean;
@ -50,6 +51,8 @@ interface Props
} }
DynamicSelect.defaultProps = { DynamicSelect.defaultProps = {
tableName: null,
processName: null,
inForm: true, inForm: true,
initialValue: null, initialValue: null,
initialDisplayValue: null, initialDisplayValue: null,
@ -65,7 +68,7 @@ DynamicSelect.defaultProps = {
const qController = Client.getInstance(); const qController = Client.getInstance();
function DynamicSelect({tableName, fieldName, fieldLabel, inForm, initialValue, initialDisplayValue, initialValues, onChange, isEditable, isMultiple, bulkEditMode, bulkEditSwitchChangeHandler}: Props) function DynamicSelect({tableName, processName, fieldName, fieldLabel, inForm, initialValue, initialDisplayValue, initialValues, onChange, isEditable, isMultiple, bulkEditMode, bulkEditSwitchChangeHandler}: Props)
{ {
const [ open, setOpen ] = useState(false); const [ open, setOpen ] = useState(false);
const [ options, setOptions ] = useState<readonly QPossibleValue[]>([]); const [ options, setOptions ] = useState<readonly QPossibleValue[]>([]);
@ -109,9 +112,9 @@ function DynamicSelect({tableName, fieldName, fieldLabel, inForm, initialValue,
(async () => (async () =>
{ {
// console.log(`doing a search with ${searchTerm}`); // console.log(`doing a search with ${searchTerm}`);
const results: QPossibleValue[] = await qController.possibleValues(tableName, fieldName, searchTerm ?? ""); const results: QPossibleValue[] = await qController.possibleValues(tableName, processName, fieldName, searchTerm ?? "");
if(tableMetaData == null) if(tableMetaData == null && tableName)
{ {
let tableMetaData: QTableMetaData = await qController.loadTableMetaData(tableName); let tableMetaData: QTableMetaData = await qController.loadTableMetaData(tableName);
setTableMetaData(tableMetaData); setTableMetaData(tableMetaData);
@ -134,7 +137,7 @@ function DynamicSelect({tableName, fieldName, fieldLabel, inForm, initialValue,
const inputChanged = (event: React.SyntheticEvent, value: string, reason: string) => const inputChanged = (event: React.SyntheticEvent, value: string, reason: string) =>
{ {
console.log(`input changed. Reason: ${reason}, setting search term to ${value}`); // console.log(`input changed. Reason: ${reason}, setting search term to ${value}`);
if(reason !== "reset") if(reason !== "reset")
{ {
// console.log(` -> setting search term to ${value}`); // console.log(` -> setting search term to ${value}`);
@ -186,7 +189,7 @@ function DynamicSelect({tableName, fieldName, fieldLabel, inForm, initialValue,
try try
{ {
const field = tableMetaData.fields.get(fieldName) const field = tableMetaData?.fields.get(fieldName)
if(field) if(field)
{ {
const adornment = field.getAdornment(AdornmentType.CHIP); const adornment = field.getAdornment(AdornmentType.CHIP);

View File

@ -236,7 +236,7 @@ function EntityForm(props: Props): JSX.Element
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////
if (fieldMetaData.possibleValueSourceName) if (fieldMetaData.possibleValueSourceName)
{ {
const results: QPossibleValue[] = await qController.possibleValues(tableName, fieldName, null, [initialValues[fieldName]]); const results: QPossibleValue[] = await qController.possibleValues(tableName, null, fieldName, null, [initialValues[fieldName]]);
if (results && results.length > 0) if (results && results.length > 0)
{ {
defaultDisplayValues.set(fieldName, results[0].label); defaultDisplayValues.set(fieldName, results[0].label);
@ -268,7 +268,7 @@ function EntityForm(props: Props): JSX.Element
dynamicFormFields, dynamicFormFields,
formValidations, formValidations,
} = DynamicFormUtils.getFormData(fieldArray); } = DynamicFormUtils.getFormData(fieldArray);
DynamicFormUtils.addPossibleValueProps(dynamicFormFields, fieldArray, tableName, record ? record.displayValues : defaultDisplayValues); DynamicFormUtils.addPossibleValueProps(dynamicFormFields, fieldArray, tableName, null, record ? record.displayValues : defaultDisplayValues);
if(disabledFields) if(disabledFields)
{ {

View File

@ -225,7 +225,7 @@ function DashboardWidgets({widgetMetaDataList, tableName, entityPrimaryKey, omit
widgetMetaData={widgetMetaData} widgetMetaData={widgetMetaData}
widgetData={widgetData[i]} widgetData={widgetData[i]}
reloadWidgetCallback={(data) => reloadWidget(i, data)}> reloadWidgetCallback={(data) => reloadWidget(i, data)}>
<div> <div className="widgetProcessMidDiv" style={{height: "100%"}}>
<ProcessRun process={widgetData[i]?.processMetaData} defaultProcessValues={widgetData[i]?.defaultValues} isWidget={true} forceReInit={widgetCounter} /> <ProcessRun process={widgetData[i]?.processMetaData} defaultProcessValues={widgetData[i]?.defaultValues} isWidget={true} forceReInit={widgetCounter} />
</div> </div>
</Widget> </Widget>

View File

@ -285,7 +285,7 @@ function Widget(props: React.PropsWithChildren<Props>): JSX.Element
const hasPermission = props.widgetData?.hasPermission === undefined || props.widgetData?.hasPermission === true; const hasPermission = props.widgetData?.hasPermission === undefined || props.widgetData?.hasPermission === true;
const widgetContent = const widgetContent =
<Box sx={{width: "100%"}}> <Box sx={{width: "100%", height: "100%"}}>
<Box pr={3} display="flex" justifyContent="space-between" alignItems="flex-start" sx={{width: "100%"}}> <Box pr={3} display="flex" justifyContent="space-between" alignItems="flex-start" sx={{width: "100%"}}>
<Box pt={2}> <Box pt={2}>
{ {

View File

@ -38,7 +38,6 @@ import {Alert, Button, CircularProgress, Icon, TablePagination} from "@mui/mater
import Box from "@mui/material/Box"; import Box from "@mui/material/Box";
import Card from "@mui/material/Card"; import Card from "@mui/material/Card";
import Grid from "@mui/material/Grid"; import Grid from "@mui/material/Grid";
import Link from "@mui/material/Link";
import Step from "@mui/material/Step"; import Step from "@mui/material/Step";
import StepLabel from "@mui/material/StepLabel"; import StepLabel from "@mui/material/StepLabel";
import Stepper from "@mui/material/Stepper"; import Stepper from "@mui/material/Stepper";
@ -46,6 +45,7 @@ import Typography from "@mui/material/Typography";
import {DataGridPro, GridColDef} from "@mui/x-data-grid-pro"; import {DataGridPro, GridColDef} from "@mui/x-data-grid-pro";
import FormData from "form-data"; import FormData from "form-data";
import {Form, Formik} from "formik"; import {Form, Formik} from "formik";
import parse from "html-react-parser";
import React, {useContext, useEffect, useState} from "react"; import React, {useContext, useEffect, useState} from "react";
import {useLocation, useNavigate, useParams} from "react-router-dom"; import {useLocation, useNavigate, useParams} from "react-router-dom";
import * as Yup from "yup"; import * as Yup from "yup";
@ -75,7 +75,7 @@ interface Props
recordIds?: string | QQueryFilter; recordIds?: string | QQueryFilter;
closeModalHandler?: (event: object, reason: string) => void; closeModalHandler?: (event: object, reason: string) => void;
forceReInit?: number; forceReInit?: number;
overrideLabel?: string overrideLabel?: string;
} }
const INITIAL_RETRY_MILLIS = 1_500; const INITIAL_RETRY_MILLIS = 1_500;
@ -225,7 +225,7 @@ function ProcessRun({process, defaultProcessValues, isModal, isWidget, isReport,
xhr.open("POST", url); xhr.open("POST", url);
xhr.responseType = "blob"; xhr.responseType = "blob";
let formData = new FormData(); let formData = new FormData();
formData.append("Authorization", qController.getAuthorizationHeaderValue()) formData.append("Authorization", qController.getAuthorizationHeaderValue());
// @ts-ignore // @ts-ignore
xhr.send(formData); xhr.send(formData);
@ -247,7 +247,7 @@ function ProcessRun({process, defaultProcessValues, isModal, isWidget, isReport,
} }
else else
{ {
setProcessError("Error downloading file", true) setProcessError("Error downloading file", true);
} }
}; };
}; };
@ -299,7 +299,7 @@ function ProcessRun({process, defaultProcessValues, isModal, isWidget, isReport,
<Box component="div" py={3}> <Box component="div" py={3}>
<Grid container justifyContent="flex-end" spacing={3}> <Grid container justifyContent="flex-end" spacing={3}>
{isModal ? <QCancelButton onClickHandler={handleCancelClicked} disabled={false} label="Close" /> {isModal ? <QCancelButton onClickHandler={handleCancelClicked} disabled={false} label="Close" />
: <QCancelButton onClickHandler={handleCancelClicked} disabled={false} /> : !isWidget && <QCancelButton onClickHandler={handleCancelClicked} disabled={false} />
} }
</Grid> </Grid>
</Box> </Box>
@ -359,6 +359,23 @@ function ProcessRun({process, defaultProcessValues, isModal, isWidget, isReport,
setTableSections(localTableSections); setTableSections(localTableSections);
} }
////////////////////////////////////////////////////////////////////////////////////
// if there are any fields that are possible values, they need to know what their //
// initial value to display should be. //
// this **needs to be** the actual PVS LABEL - not the raw value (e.g, PVS ID) //
// but our first use case, they're the same, so... this needs fixed. //
////////////////////////////////////////////////////////////////////////////////////
if(formFields && processValues)
{
Object.keys(formFields).forEach((key) =>
{
if(formFields[key].possibleValueProps && processValues[key])
{
formFields[key].possibleValueProps.initialDisplayValue = processValues[key]
}
})
}
return ( return (
<> <>
{ {
@ -420,7 +437,7 @@ function ProcessRun({process, defaultProcessValues, isModal, isWidget, isReport,
{localTableSections.map((section: QTableSection, index: number) => {localTableSections.map((section: QTableSection, index: number) =>
{ {
const name = section.name const name = section.name;
if (section.isHidden) if (section.isHidden)
{ {
@ -589,6 +606,14 @@ function ProcessRun({process, defaultProcessValues, isModal, isWidget, isReport,
</div> </div>
) )
} }
{
component.type === QComponentType.HTML && (
processValues[`${step.name}.html`] &&
<Box fontSize="1rem">
{parse(processValues[`${step.name}.html`])}
</Box>
)
}
</div> </div>
)))} )))}
</> </>
@ -701,10 +726,9 @@ function ProcessRun({process, defaultProcessValues, isModal, isWidget, isReport,
{ {
let fullFieldList = getFullFieldList(activeStep, processValues); let fullFieldList = getFullFieldList(activeStep, processValues);
const formData = DynamicFormUtils.getFormData(fullFieldList); const formData = DynamicFormUtils.getFormData(fullFieldList);
if(tableMetaData)
{ const possibleValueDisplayValues = new Map<string, string>();
DynamicFormUtils.addPossibleValueProps(formData.dynamicFormFields, fullFieldList, tableMetaData.name, null); DynamicFormUtils.addPossibleValueProps(formData.dynamicFormFields, fullFieldList, tableMetaData?.name, processName, possibleValueDisplayValues);
}
dynamicFormFields = formData.dynamicFormFields; dynamicFormFields = formData.dynamicFormFields;
formValidations = formData.formValidations; formValidations = formData.formValidations;
@ -819,7 +843,7 @@ function ProcessRun({process, defaultProcessValues, isModal, isWidget, isReport,
} }
}); });
DynamicFormUtils.addPossibleValueProps(newDynamicFormFields, fullFieldList, tableMetaData.name, null); DynamicFormUtils.addPossibleValueProps(newDynamicFormFields, fullFieldList, tableMetaData.name, null, null);
setFormFields(newDynamicFormFields); setFormFields(newDynamicFormFields);
setValidationScheme(Yup.object().shape(newFormValidations)); setValidationScheme(Yup.object().shape(newFormValidations));
@ -981,11 +1005,11 @@ function ProcessRun({process, defaultProcessValues, isModal, isWidget, isReport,
{ {
if ((e as QException).status === "403") if ((e as QException).status === "403")
{ {
setProcessError(`You do not have permission to run this ${isReport ? "report" : "process"}.`, true) setProcessError(`You do not have permission to run this ${isReport ? "report" : "process"}.`, true);
return (true); return (true);
} }
return (false); return (false);
} };
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
@ -1231,7 +1255,7 @@ function ProcessRun({process, defaultProcessValues, isModal, isWidget, isReport,
} }
<Box p={3}> <Box p={3}>
<Box> <Box pb={isWidget ? 6 : "initial"}>
{/*************************************************************************** {/***************************************************************************
** step content - e.g., the appropriate form or other screen for the step ** ** step content - e.g., the appropriate form or other screen for the step **
***************************************************************************/} ***************************************************************************/}
@ -1252,7 +1276,7 @@ function ProcessRun({process, defaultProcessValues, isModal, isWidget, isReport,
{/******************************** {/********************************
** back &| next/submit buttons ** ** back &| next/submit buttons **
********************************/} ********************************/}
<Box mt={6} width="100%" display="flex" justifyContent="space-between"> <Box mt={6} width="100%" display="flex" justifyContent="space-between" position={isWidget ? "absolute" : "initial"} bottom={isWidget ? "3rem" : "initial"} right={isWidget ? "1.5rem" : "initial"}>
{true || activeStepIndex === 0 ? ( {true || activeStepIndex === 0 ? (
<Box /> <Box />
) : ( ) : (
@ -1320,7 +1344,7 @@ function ProcessRun({process, defaultProcessValues, isModal, isWidget, isReport,
else if (isWidget) else if (isWidget)
{ {
return ( return (
<Box sx={{alignItems: "stretch", flexGrow: 1, display: "flex", marginTop: "0px", paddingTop: "0px"}}> <Box sx={{alignItems: "stretch", flexGrow: 1, display: "flex", marginTop: "0px", paddingTop: "0px", height: "100%"}}>
{form} {form}
</Box> </Box>
); );

View File

@ -221,7 +221,7 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
const parts = location.pathname.split("/"); const parts = location.pathname.split("/");
currentSavedFilterId = Number.parseInt(parts[parts.length - 1]); currentSavedFilterId = Number.parseInt(parts[parts.length - 1]);
} }
else else if(!searchParams.has("filter"))
{ {
if (localStorage.getItem(currentSavedFilterLocalStorageKey)) if (localStorage.getItem(currentSavedFilterLocalStorageKey))
{ {
@ -573,10 +573,7 @@ function RecordQuery({table, launchProcess}: Props): JSX.Element
setFilterModel(filterModel); setFilterModel(filterModel);
if (filterLocalStorageKey) if (filterLocalStorageKey)
{ {
localStorage.setItem( localStorage.setItem(filterLocalStorageKey, JSON.stringify(filterModel));
filterLocalStorageKey,
JSON.stringify(filterModel),
);
} }
}; };

View File

@ -30,6 +30,8 @@ import {QQueryFilter} from "@kingsrook/qqq-frontend-core/lib/model/query/QQueryF
import {GridFilterModel, GridLinkOperator, GridSortItem} from "@mui/x-data-grid-pro"; import {GridFilterModel, GridLinkOperator, GridSortItem} from "@mui/x-data-grid-pro";
import ValueUtils from "qqq/utils/qqq/ValueUtils"; import ValueUtils from "qqq/utils/qqq/ValueUtils";
const CURRENT_SAVED_FILTER_ID_LOCAL_STORAGE_KEY_ROOT = "qqq.currentSavedFilterId";
/******************************************************************************* /*******************************************************************************
** Utility class for working with QQQ Filters ** Utility class for working with QQQ Filters
** **
@ -366,7 +368,7 @@ class FilterUtils
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
if (values && values.length > 0) if (values && values.length > 0)
{ {
values = await qController.possibleValues(tableMetaData.name, field.name, "", values); values = await qController.possibleValues(tableMetaData.name, null, field.name, "", values);
} }
//////////////////////////////////////////// ////////////////////////////////////////////
@ -454,6 +456,16 @@ class FilterUtils
} }
} }
if (searchParams && searchParams.has("filter"))
{
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// if we're setting the filter based on a filter query-string param, then make sure we don't have a currentSavedFilter in local storage. //
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
localStorage.removeItem(`${CURRENT_SAVED_FILTER_ID_LOCAL_STORAGE_KEY_ROOT}.${tableMetaData.name}`);
localStorage.setItem(filterLocalStorageKey, JSON.stringify(defaultFilter));
localStorage.setItem(sortLocalStorageKey, JSON.stringify(defaultSort));
}
return ({filter: defaultFilter, sort: defaultSort}); return ({filter: defaultFilter, sort: defaultSort});
} }
catch (e) catch (e)