From 5114e99f997462e6f99d010881aa120dc2799c80 Mon Sep 17 00:00:00 2001 From: jasquat <2487833+jasquat@users.noreply.github.com> Date: Thu, 7 Mar 2024 13:31:58 -0500 Subject: [PATCH] added keys to components when added to an array so react knows what was added and removed correctly w/ burnettk (#1180) Co-authored-by: jasquat --- spiffworkflow-frontend/src/helpers.tsx | 12 ++++- spiffworkflow-frontend/src/interfaces.ts | 7 +++ .../src/routes/TaskShow.tsx | 46 ++++++++++++------- 3 files changed, 47 insertions(+), 18 deletions(-) diff --git a/spiffworkflow-frontend/src/helpers.tsx b/spiffworkflow-frontend/src/helpers.tsx index 783cdfbb..be507684 100644 --- a/spiffworkflow-frontend/src/helpers.tsx +++ b/spiffworkflow-frontend/src/helpers.tsx @@ -1,6 +1,6 @@ import { Buffer } from 'buffer'; -import { ProcessInstance } from './interfaces'; +import { ElementForArray, ProcessInstance } from './interfaces'; export const DEFAULT_PER_PAGE = 50; export const DEFAULT_PAGE = 1; @@ -300,3 +300,13 @@ export const isURL = (str: string) => { /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i; return urlRegex.test(str); }; + +// this will help maintain order when using an array of elements. +// React needs to have a key for each component to ensure correct elements are added +// and removed when that array is changed. +// https://stackoverflow.com/questions/46735483/error-do-not-use-array-index-in-keys/46735689#46735689 +export const renderElementsForArray = (elements: ElementForArray[]) => { + return elements.map((element: any) => ( +
{element.component}
+ )); +}; diff --git a/spiffworkflow-frontend/src/interfaces.ts b/spiffworkflow-frontend/src/interfaces.ts index 5834ca28..0b239b4b 100644 --- a/spiffworkflow-frontend/src/interfaces.ts +++ b/spiffworkflow-frontend/src/interfaces.ts @@ -1,3 +1,5 @@ +import { ReactElement } from 'react'; + export interface User { id: number; username: string; @@ -496,3 +498,8 @@ export interface SpiffTableHeader { tooltip_text?: string; text: string; } + +export interface ElementForArray { + key: string; + component: ReactElement | null; +} diff --git a/spiffworkflow-frontend/src/routes/TaskShow.tsx b/spiffworkflow-frontend/src/routes/TaskShow.tsx index daabc2a0..9c5088dd 100644 --- a/spiffworkflow-frontend/src/routes/TaskShow.tsx +++ b/spiffworkflow-frontend/src/routes/TaskShow.tsx @@ -10,10 +10,12 @@ import { doNothing, modifyProcessIdentifierForPathParam, recursivelyChangeNullAndUndefined, + renderElementsForArray, setPageTitle, } from '../helpers'; import { BasicTask, + ElementForArray, ErrorForDisplay, EventDefinition, HotCrumbItem, @@ -446,7 +448,7 @@ export default function TaskShow() { ); }; - const pageElements = []; + const pageElements: ElementForArray[] = []; if (basicTask) { let statusString = ''; if (basicTask.state !== 'READY') { @@ -457,28 +459,38 @@ export default function TaskShow() { !('allowGuest' in basicTask.extensions) || basicTask.extensions.allowGuest !== 'true' ) { - pageElements.push(); - pageElements.push( -

- Task: {basicTask.name_for_display} ( - {basicTask.process_model_display_name}){statusString} -

- ); + pageElements.push({ + key: 'process-breadcrumb', + component: , + }); + pageElements.push({ + key: 'task-name', + component: ( +

+ Task: {basicTask.name_for_display} ( + {basicTask.process_model_display_name}){statusString} +

+ ), + }); } } if (guestConfirmationText) { - pageElements.push( - - ); + pageElements.push({ + key: 'guest-confirmation-text', + component: ( + + ), + }); } else if (basicTask && taskData) { - pageElements.push(); - pageElements.push(formElement()); + pageElements.push({ + key: 'instructions-for-end-user', + component: , + }); + pageElements.push({ key: 'main-form', component: formElement() }); } else if (!atLeastOneTaskFetchHasError) { - pageElements.push(getLoadingIcon()); + pageElements.push({ key: 'loading-icon', component: getLoadingIcon() }); } - // typescript gets angry if we return an array of elements not in a tag - // eslint-disable-next-line react/jsx-no-useless-fragment - return <>{pageElements}; + return <>{renderElementsForArray(pageElements)}; }