QQQ-37 checkpoint - cleanup of various kinds on process validation & result

This commit is contained in:
2022-08-30 13:47:26 -05:00
parent 8b2364b596
commit 3eb1cd73a7
5 changed files with 138 additions and 86 deletions

View File

@ -48,15 +48,17 @@ function QProcessSummaryResults({
qInstance, process, table = null, processValues, step,
}: Props): JSX.Element
{
const sourceTable = qInstance.tables.get(processValues.sourceTable);
const resultValidationList = (
<List sx={{mt: 2}}>
{
processValues?.recordCount && table && (
processValues?.recordCount !== undefined && sourceTable && (
<ListItem sx={{my: 2}}>
<ListItemText primaryTypographyProps={{fontSize: 16}}>
{processValues.recordCount.toLocaleString()}
{" "}
{table.label}
{sourceTable.label}
{" "}
records were processed.
</ListItemText>
@ -65,7 +67,7 @@ function QProcessSummaryResults({
}
<List>
{
processValues.processResults && processValues.processResults.map((processSummaryLine: ProcessSummaryLine, i: number) => (new ProcessSummaryLine(processSummaryLine).getProcessSummaryListItem(i, table, qInstance, true)))
processValues.processResults && processValues.processResults.map((processSummaryLine: ProcessSummaryLine, i: number) => (new ProcessSummaryLine(processSummaryLine).getProcessSummaryListItem(i, sourceTable, qInstance, true)))
}
</List>
</List>
@ -79,8 +81,8 @@ function QProcessSummaryResults({
<MDBox border="1px solid rgb(70%, 70%, 70%)" borderRadius="lg" p={2} mt={2}>
<MDBox mt={-5} p={1} sx={{width: "fit-content"}} bgColor="success" borderRadius=".25em" width="initial" color="white">
<MDBox display="flex" alignItems="center" color="white">
<Icon fontSize="medium" sx={{mr: 1}}>{process.iconName}</Icon>
{`${process.label} : ${step.label}`}
{process.iconName && <Icon fontSize="medium" sx={{mr: 1}}>{process.iconName}</Icon>}
Process Summary
</MDBox>
</MDBox>
{resultValidationList}

View File

@ -64,6 +64,7 @@ function QValidationReview({
}: Props): JSX.Element
{
const [previewRecordIndex, setPreviewRecordIndex] = useState(0);
const sourceTable = qInstance.tables.get(processValues.sourceTable);
const updatePreviewRecordIndex = (offset: number) =>
{
@ -89,15 +90,44 @@ function QValidationReview({
},
});
const buildDoFullValidationRadioListItem = (value: "true" | "false", labelText: string, tooltipHTML: JSX.Element): JSX.Element =>
{
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// split up the label into words - then we'll display the last word by itself with a non-breaking space, no-wrap-glued to the button. //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const labelWords = labelText.split(" ");
const lastWord = labelWords[labelWords.length - 1];
labelWords.splice(labelWords.length - 1, 1);
return (
<ListItem sx={{pl: 2}}>
<FormControlLabel
value={value}
control={<Radio />}
label={(
<ListItemText primaryTypographyProps={{fontSize: 16, pt: 0.625}}>
{`${labelWords.join(" ")} `}
<span style={{whiteSpace: "nowrap"}}>
{/* eslint-disable-next-line react/jsx-one-expression-per-line */}
{lastWord}.&nbsp;<CustomWidthTooltip title={tooltipHTML}>
<IconButton sx={{py: 0}}><Icon fontSize="small">info_outlined</Icon></IconButton>
{/* eslint-disable-next-line react/jsx-closing-tag-location */}
</CustomWidthTooltip>
</span>
</ListItemText>
)}
/>
</ListItem>
);
};
const preValidationList = (
<List sx={{mt: 2}}>
{
processValues?.recordCount && table && (
processValues?.recordCount !== undefined && sourceTable && (
<ListItem sx={{my: 2}}>
<ListItemText primaryTypographyProps={{fontSize: 16}}>
You selected
{` ${processValues.recordCount.toLocaleString()} ${table?.label} `}
records.
{`Input: ${processValues.recordCount.toLocaleString()} ${sourceTable?.label} record${processValues.recordCount === 1 ? "" : "s"}.`}
</ListItemText>
</ListItem>
)
@ -108,19 +138,13 @@ function QValidationReview({
<ListItem sx={{mb: 1, mt: 6}}>
<ListItemText primaryTypographyProps={{fontSize: 16}}>How would you like to proceed?</ListItemText>
</ListItem>
<List>
<List className="doFullValidationRadios">
<RadioGroup name="doFullValidation" value={formValues.doFullValidation} onChange={doFullValidationRadioChangedHandler}>
<ListItem sx={{pl: 2}}>
<FormControlLabel
value="true"
control={<Radio />}
label={(
<ListItemText primaryTypographyProps={{fontSize: 16}}>
Perform Validation on all records before processing.
<CustomWidthTooltip
title={(
{buildDoFullValidationRadioListItem(
"true",
"Perform Validation on all records before processing", (
<div>
If you choose this option, a Validation step will run on all of the records that you selected.
If you choose this option, a Validation step will run on all of the input records.
You will then be told how many can process successfully, and how many have issues.
<br />
<br />
@ -129,38 +153,21 @@ function QValidationReview({
<br />
Choose this option if you want more information about what will happen, and you are willing to wait for that information.
</div>
),
)}
>
<IconButton sx={{py: 0}}><Icon fontSize="small">info_outlined</Icon></IconButton>
</CustomWidthTooltip>
</ListItemText>
)}
/>
</ListItem>
<ListItem sx={{pl: 2}}>
<FormControlLabel
value="false"
control={<Radio />}
label={(
<ListItemText primaryTypographyProps={{fontSize: 16}}>
Skip Validation. Submit the records for immediate processing.
<CustomWidthTooltip
title={(
{buildDoFullValidationRadioListItem(
"false",
"Skip Validation. Submit the records for immediate processing", (
<div>
If you choose this option, the records you selected will immediately be processed.
If you choose this option, the records input records will immediately be processed.
You will be told how many records were successfully processed, and which ones had issues after the processing is completed.
<br />
<br />
Choose this option if you feel that you do not need this information, or are not willing to wait for it.
</div>
),
)}
>
<IconButton sx={{py: 0}}><Icon fontSize="small">info_outlined</Icon></IconButton>
</CustomWidthTooltip>
</ListItemText>
)}
/>
</ListItem>
</RadioGroup>
</List>
</>
@ -172,11 +179,11 @@ function QValidationReview({
const postValidationList = (
<List sx={{mt: 2}}>
{
processValues?.recordCount && table && (
processValues?.recordCount !== undefined && sourceTable && (
<ListItem sx={{my: 2}}>
<ListItemText primaryTypographyProps={{fontSize: 16}}>
Validation complete on
{` ${processValues.recordCount.toLocaleString()} ${table?.label} `}
{` ${processValues.recordCount.toLocaleString()} ${sourceTable?.label} `}
records.
</ListItemText>
</ListItem>
@ -184,7 +191,7 @@ function QValidationReview({
}
<List>
{
processValues.validationSummary && processValues.validationSummary.map((processSummaryLine: ProcessSummaryLine, i: number) => (new ProcessSummaryLine(processSummaryLine).getProcessSummaryListItem(i, table, qInstance)))
processValues.validationSummary && processValues.validationSummary.map((processSummaryLine: ProcessSummaryLine, i: number) => (new ProcessSummaryLine(processSummaryLine).getProcessSummaryListItem(i, sourceTable, qInstance)))
}
</List>
</List>
@ -199,9 +206,9 @@ function QValidationReview({
<MDTypography color="body" variant="body2" component="div" mb={2}>
<MDBox display="flex">
{
previewRecords && previewRecords.length > 0 ? (
processValues?.previewMessage && previewRecords && previewRecords.length > 0 ? (
<>
<i>This is a preview of the records that will be created.</i>
<i>{processValues?.previewMessage}</i>
<CustomWidthTooltip
title={(
<div>

View File

@ -21,7 +21,9 @@
import * as Yup from "yup";
import {CircularProgress, TablePagination} from "@mui/material";
import {
Button, CircularProgress, Icon, TablePagination,
} from "@mui/material";
import {DataGridPro, GridColDef} from "@mui/x-data-grid-pro";
// formik components
import {Form, Formik} from "formik";
@ -96,8 +98,13 @@ function ProcessRun({process}: Props): JSX.Element
const [lastProcessResponse, setLastProcessResponse] = useState(
null as QJobStarted | QJobComplete | QJobError | QJobRunning,
);
const [showErrorDetail, setShowErrorDetail] = useState(false);
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// the validation screen - it can change whether next is actually the final step or not... so, use this state field to track that. //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const [overrideOnLastStep, setOverrideOnLastStep] = useState(null as boolean);
const onLastStep = activeStepIndex === steps.length - 2;
const noMoreSteps = activeStepIndex === steps.length - 1;
@ -199,6 +206,11 @@ function ProcessRun({process}: Props): JSX.Element
return (<span>{value}</span>);
};
const toggleShowErrorDetail = () =>
{
setShowErrorDetail(!showErrorDetail);
};
////////////////////////////////////////////////////
// generate the main form body content for a step //
////////////////////////////////////////////////////
@ -216,11 +228,24 @@ function ProcessRun({process}: Props): JSX.Element
{
return (
<>
<MDTypography color="error" variant="h5" component="div">
<MDTypography color="error" variant="h3" component="div">
Error
</MDTypography>
<MDTypography color="body" variant="button">
An error occurred while running the process:
{" "}
{process.label}
<MDBox mt={3} display="flex" justifyContent="center">
<MDBox display="flex" flexDirection="column" alignItems="center">
<Button onClick={toggleShowErrorDetail} startIcon={<Icon>{showErrorDetail ? "expand_less" : "expand_more"}</Icon>}>
{showErrorDetail ? "Hide " : "Show "}
detailed error message
</Button>
<MDBox mt={1} style={{display: showErrorDetail ? "block" : "none"}}>
{processError}
</MDBox>
</MDBox>
</MDBox>
</MDTypography>
</>
);
@ -326,8 +351,7 @@ function ProcessRun({process}: Props): JSX.Element
//////////////////////////////////////////////////////////////
setFieldValue("doFullValidation", value);
// eslint-disable-next-line no-unneeded-ternary
setOverrideOnLastStep(value === "true" ? false : true);
setOverrideOnLastStep(value !== "true");
}}
/>
)
@ -823,6 +847,7 @@ function ProcessRun({process}: Props): JSX.Element
setProcessValues({});
setRecords([]);
setOverrideOnLastStep(null);
setLastProcessResponse(new QJobRunning({message: "Working..."}));
setTimeout(async () =>
@ -848,7 +873,7 @@ function ProcessRun({process}: Props): JSX.Element
const mainCardStyles: any = {};
mainCardStyles.minHeight = "calc(100vh - 400px)";
if (qJobRunning || activeStep === null)
if (!processError && (qJobRunning || activeStep === null))
{
mainCardStyles.background = "none";
mainCardStyles.boxShadow = "none";

View File

@ -59,24 +59,37 @@ export class ProcessSummaryLine
getProcessSummaryListItem(i: number, table: QTableMetaData, qInstance: QInstance, isResultScreen: boolean = false): JSX.Element
{
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// split up the message into words - then we'll display the last word by itself with a non-breaking space, no-wrap-glued to the button. //
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const messageWords = this.message ? this.message.split(" ") : [];
const lastWord = messageWords.length > 1 ? messageWords[messageWords.length - 1] : "";
if (messageWords.length > 1)
{
messageWords.splice(messageWords.length - 1, 1);
}
return (
<ListItem key={i} sx={{pl: 4, my: 2}}>
<MDBox display="flex" alignItems="top">
<Icon fontSize="medium" sx={{mr: 1}} color={this.getColor()}>{this.getIcon(isResultScreen)}</Icon>
<ListItemText primaryTypographyProps={{fontSize: 16}}>
{this.count.toLocaleString()}
{" "}
{this.message}
</ListItemText>
{/* work hard to prevent the icon from falling down to the next line by itself... */}
{`${this.count.toLocaleString()} ${messageWords.join(" ")} `}
{
table && this.primaryKeys && (
<Link target="_blank" to={this.getLinkToRecords(table, qInstance)}>
(table && this.primaryKeys) ? (
<span style={{whiteSpace: "nowrap"}}>
{/* eslint-disable-next-line react/jsx-one-expression-per-line */}
{lastWord}&nbsp;<Link target="_blank" to={this.getLinkToRecords(table, qInstance)}>
<Tooltip title="See these records in a new tab" sx={{py: 0}}>
<IconButton sx={{py: 0}}><Icon fontSize="small">open_in_new</Icon></IconButton>
</Tooltip>
{/* eslint-disable-next-line react/jsx-closing-tag-location */}
</Link>
)
</span>
) : <span>{lastWord}</span>
}
</ListItemText>
</MDBox>
</ListItem>
);
@ -131,8 +144,6 @@ export class ProcessSummaryLine
{
const tablePath = qInstance.getTablePath(table);
const filter = new QQueryFilter([new QFilterCriteria(table.primaryKeyField, QCriteriaOperator.IN, this.primaryKeys)]);
console.log("Link to records:");
console.log(filter);
return (`${tablePath}?filter=${JSON.stringify(filter)}`);
}
}

View File

@ -110,3 +110,10 @@
margin-left: 40px;
font-size: 14px;
}
/* Help make the radio, text, and icon wrap in a good way */
.doFullValidationRadios label
{
display: flex;
align-items: flex-start;
}