From 4b64c46c577e23c1d20b6982b81ab237515e689d Mon Sep 17 00:00:00 2001 From: Darin Kelkhoff Date: Tue, 3 Dec 2024 09:15:31 -0600 Subject: [PATCH] CE-1955 Add value-mapping details to diff --- .../processes/BulkLoadValueMappingForm.tsx | 15 ++- .../utils/qqq/SavedBulkLoadProfileUtils.ts | 93 +++++++++++++++++-- 2 files changed, 98 insertions(+), 10 deletions(-) diff --git a/src/qqq/components/processes/BulkLoadValueMappingForm.tsx b/src/qqq/components/processes/BulkLoadValueMappingForm.tsx index 2c45315..b785c25 100644 --- a/src/qqq/components/processes/BulkLoadValueMappingForm.tsx +++ b/src/qqq/components/processes/BulkLoadValueMappingForm.tsx @@ -30,7 +30,7 @@ import QDynamicFormField from "qqq/components/forms/DynamicFormField"; import SavedBulkLoadProfiles from "qqq/components/misc/SavedBulkLoadProfiles"; import {BulkLoadMapping, BulkLoadProfile, BulkLoadTableStructure, FileDescription, Wrapper} from "qqq/models/processes/BulkLoadModels"; import {SubFormPreSubmitCallbackResultType} from "qqq/pages/processes/ProcessRun"; -import React, {forwardRef, useEffect, useImperativeHandle, useState} from "react"; +import React, {forwardRef, useEffect, useImperativeHandle, useReducer, useState} from "react"; interface BulkLoadValueMappingFormProps { @@ -67,6 +67,9 @@ const BulkLoadValueMappingForm = forwardRef(({processValues, setActiveStepLabel, const [fileDescription] = useState(new FileDescription(processValues.headerValues, processValues.headerLetters, processValues.bodyValuesPreview)); fileDescription.setHasHeaderRow(currentMapping.hasHeaderRow); + const [, forceUpdate] = useReducer((x) => x + 1, 0); + + /******************************************************************************* ** *******************************************************************************/ @@ -152,7 +155,15 @@ const BulkLoadValueMappingForm = forwardRef(({processValues, setActiveStepLabel, function mappedValueChanged(fileValue: string, newValue: any) { valueErrors[fileValue] = null; - currentMapping.valueMappings[fieldFullName][fileValue] = newValue; + if(newValue == null) + { + delete currentMapping.valueMappings[fieldFullName][fileValue]; + } + else + { + currentMapping.valueMappings[fieldFullName][fileValue] = newValue; + } + forceUpdate(); } diff --git a/src/qqq/utils/qqq/SavedBulkLoadProfileUtils.ts b/src/qqq/utils/qqq/SavedBulkLoadProfileUtils.ts index 5dd0e29..5596762 100644 --- a/src/qqq/utils/qqq/SavedBulkLoadProfileUtils.ts +++ b/src/qqq/utils/qqq/SavedBulkLoadProfileUtils.ts @@ -28,7 +28,6 @@ type FieldMapping = { [name: string]: BulkLoadField } ***************************************************************************/ export class SavedBulkLoadProfileUtils { - /*************************************************************************** ** ***************************************************************************/ @@ -172,6 +171,88 @@ export class SavedBulkLoadProfileUtils } + /*************************************************************************** + ** + ***************************************************************************/ + private static joinUpToN(values: string[], n: number) + { + if(values.length <= n) + { + return (values.join(", ")); + } + + const others = values.length - n; + return (values.slice(0, n-1).join(", ") + ` and ${others} other${others == 1 ? "" : "s"}`); + } + + + /*************************************************************************** + ** + ***************************************************************************/ + private static diffFieldValueMappings(bulkLoadField: BulkLoadField, baseMapping: { [p: string]: any }, activeMapping: { [p: string]: any }): string + { + const addedMappings: string[] = []; + const removedMappings: string[] = []; + const changedMappings: string[] = []; + + ///////////////////////////// + // look for added mappings // + ///////////////////////////// + for (let value of Object.keys(activeMapping)) + { + if(!baseMapping[value]) + { + addedMappings.push(value); + } + } + + /////////////////////////////// + // look for removed mappings // + /////////////////////////////// + for (let value of Object.keys(baseMapping)) + { + if(!activeMapping[value]) + { + removedMappings.push(value); + } + } + + /////////////////////////////// + // look for changed mappings // + /////////////////////////////// + for (let value of Object.keys(activeMapping)) + { + if(baseMapping[value] && activeMapping[value] != baseMapping[value]) + { + changedMappings.push(value); + } + } + + if(addedMappings.length || removedMappings.length || changedMappings.length) + { + let rs = `Updated value mapping for ${bulkLoadField.getQualifiedLabel()}: ` + const parts: string[] = []; + + if(addedMappings.length) + { + parts.push(`Added value${addedMappings.length == 1 ? "" : "s"} for: ${this.joinUpToN(addedMappings, 5)}`); + } + if(removedMappings.length) + { + parts.push(`Removed value${removedMappings.length == 1 ? "" : "s"} for: ${this.joinUpToN(removedMappings, 5)}`); + } + if(changedMappings.length) + { + parts.push(`Changed value${changedMappings.length == 1 ? "" : "s"} for: ${this.joinUpToN(changedMappings, 5)}`); + } + + return rs + parts.join("; "); + } + + return null; + } + + /*************************************************************************** ** ***************************************************************************/ @@ -213,14 +294,10 @@ export class SavedBulkLoadProfileUtils { const fieldName = bulkLoadField.field.name; - if (JSON.stringify(baseMapping.valueMappings[fieldName] ?? []) != JSON.stringify(activeMapping.valueMappings[fieldName] ?? [])) + const valueMappingDiff = this.diffFieldValueMappings(bulkLoadField, baseMapping.valueMappings[fieldName] ?? {}, activeMapping.valueMappings[fieldName] ?? {}); + if(valueMappingDiff) { - diffs.push(`Changed value mapping for ${bulkLoadField.getQualifiedLabel()}`) - } - - if (baseMapping.valueMappings[fieldName] && activeMapping.valueMappings[fieldName]) - { - // todo - finish this - better version than just the JSON diff! + diffs.push(valueMappingDiff); } } catch(e)