diff --git a/spiffworkflow-frontend/src/components/ReactDiagramEditor.tsx b/spiffworkflow-frontend/src/components/ReactDiagramEditor.tsx index eefaff829..82dddd4ad 100644 --- a/spiffworkflow-frontend/src/components/ReactDiagramEditor.tsx +++ b/spiffworkflow-frontend/src/components/ReactDiagramEditor.tsx @@ -68,6 +68,7 @@ type OwnProps = { diagramType: string; readyOrWaitingProcessInstanceTasks?: Task[] | null; completedProcessInstanceTasks?: Task[] | null; + cancelledProcessInstanceTasks?: Task[] | null; saveDiagram?: (..._args: any[]) => any; onDeleteFile?: (..._args: any[]) => any; isPrimaryFile?: boolean; @@ -94,6 +95,7 @@ export default function ReactDiagramEditor({ diagramType, readyOrWaitingProcessInstanceTasks, completedProcessInstanceTasks, + cancelledProcessInstanceTasks, saveDiagram, onDeleteFile, isPrimaryFile, @@ -358,7 +360,8 @@ export default function ReactDiagramEditor({ function checkTaskCanBeHighlighted(taskBpmnId: string) { return ( !taskSpecsThatCannotBeHighlighted.includes(taskBpmnId) && - !taskBpmnId.match(/EndJoin/) + !taskBpmnId.match(/EndJoin/) && + !taskBpmnId.match(/BoundaryEventParent/) ); } @@ -441,6 +444,19 @@ export default function ReactDiagramEditor({ ); }); } + if (cancelledProcessInstanceTasks) { + const bpmnProcessIdentifiers = getBpmnProcessIdentifiers( + canvas.getRootElement() + ); + cancelledProcessInstanceTasks.forEach((cancelledTask) => { + highlightBpmnIoElement( + canvas, + cancelledTask, + 'cancelled-task-highlight', + bpmnProcessIdentifiers + ); + }); + } } function displayDiagram( @@ -518,6 +534,7 @@ export default function ReactDiagramEditor({ diagramXMLString, readyOrWaitingProcessInstanceTasks, completedProcessInstanceTasks, + cancelledProcessInstanceTasks, fileName, performingXmlUpdates, processModelId, diff --git a/spiffworkflow-frontend/src/index.css b/spiffworkflow-frontend/src/index.css index 077040363..e0b4336cd 100644 --- a/spiffworkflow-frontend/src/index.css +++ b/spiffworkflow-frontend/src/index.css @@ -142,6 +142,10 @@ code { fill: grey !important; opacity: .4; } +.cancelled-task-highlight:not(.djs-connection) .djs-visual > :nth-child(1) { + fill: blue !important; + opacity: .2; +} .accordion-item-label { vertical-align: middle; diff --git a/spiffworkflow-frontend/src/interfaces.ts b/spiffworkflow-frontend/src/interfaces.ts index 1d34054db..802c48c7d 100644 --- a/spiffworkflow-frontend/src/interfaces.ts +++ b/spiffworkflow-frontend/src/interfaces.ts @@ -58,6 +58,7 @@ export interface Task { export interface TaskIds { completed: Task[]; readyOrWaiting: Task[]; + cancelled: Task[]; } export interface ProcessInstanceTask { diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index 29d4bedcb..c294ae486 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -231,13 +231,19 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { }; const getTaskIds = () => { - const taskIds: TaskIds = { completed: [], readyOrWaiting: [] }; + const taskIds: TaskIds = { + completed: [], + readyOrWaiting: [], + cancelled: [], + }; if (tasks) { tasks.forEach(function getUserTasksElement(task: Task) { if (task.state === 'COMPLETED') { taskIds.completed.push(task); } else if (task.state === 'READY' || task.state === 'WAITING') { taskIds.readyOrWaiting.push(task); + } else if (task.state === 'CANCELLED') { + taskIds.cancelled.push(task); } return null; }); @@ -1152,6 +1158,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { fileName={processInstance.bpmn_xml_file_contents || ''} readyOrWaitingProcessInstanceTasks={taskIds.readyOrWaiting} completedProcessInstanceTasks={taskIds.completed} + cancelledProcessInstanceTasks={taskIds.cancelled} diagramType="readonly" onElementClick={handleClickedDiagramTask} />