some fixes to ensure we display the correct task data for the diagram elements w/ burnettk

This commit is contained in:
jasquat 2022-12-13 14:16:28 -05:00
parent f6462d83af
commit 620d054586
10 changed files with 77 additions and 43 deletions

View File

@ -1,4 +1,3 @@
"""Spiff_step_details."""
from dataclasses import dataclass from dataclasses import dataclass
from flask_bpmn.models.db import db from flask_bpmn.models.db import db

View File

@ -108,7 +108,7 @@ class Task:
multi_instance_type: Union[MultiInstanceType, None] = None, multi_instance_type: Union[MultiInstanceType, None] = None,
multi_instance_count: str = "", multi_instance_count: str = "",
multi_instance_index: str = "", multi_instance_index: str = "",
process_name: str = "", process_identifier: str = "",
properties: Union[dict, None] = None, properties: Union[dict, None] = None,
process_instance_id: Union[int, None] = None, process_instance_id: Union[int, None] = None,
process_instance_status: Union[str, None] = None, process_instance_status: Union[str, None] = None,
@ -153,7 +153,7 @@ class Task:
self.multi_instance_index = ( self.multi_instance_index = (
multi_instance_index # And the index of the currently repeating task. multi_instance_index # And the index of the currently repeating task.
) )
self.process_name = process_name self.process_identifier = process_identifier
self.properties = properties # Arbitrary extension properties from BPMN editor. self.properties = properties # Arbitrary extension properties from BPMN editor.
if self.properties is None: if self.properties is None:
@ -179,7 +179,7 @@ class Task:
"multi_instance_type": multi_instance_type, "multi_instance_type": multi_instance_type,
"multi_instance_count": self.multi_instance_count, "multi_instance_count": self.multi_instance_count,
"multi_instance_index": self.multi_instance_index, "multi_instance_index": self.multi_instance_index,
"process_name": self.process_name, "process_identifier": self.process_identifier,
"properties": self.properties, "properties": self.properties,
"process_instance_id": self.process_instance_id, "process_instance_id": self.process_instance_id,
"process_instance_status": self.process_instance_status, "process_instance_status": self.process_instance_status,
@ -285,7 +285,7 @@ class TaskSchema(Schema):
"multi_instance_type", "multi_instance_type",
"multi_instance_count", "multi_instance_count",
"multi_instance_index", "multi_instance_index",
"process_name", "process_identifier",
"properties", "properties",
"process_instance_id", "process_instance_id",
"form_schema", "form_schema",
@ -296,7 +296,7 @@ class TaskSchema(Schema):
documentation = marshmallow.fields.String(required=False, allow_none=True) documentation = marshmallow.fields.String(required=False, allow_none=True)
# form = marshmallow.fields.Nested(FormSchema, required=False, allow_none=True) # form = marshmallow.fields.Nested(FormSchema, required=False, allow_none=True)
title = marshmallow.fields.String(required=False, allow_none=True) title = marshmallow.fields.String(required=False, allow_none=True)
process_name = marshmallow.fields.String(required=False, allow_none=True) process_identifier = marshmallow.fields.String(required=False, allow_none=True)
lane = marshmallow.fields.String(required=False, allow_none=True) lane = marshmallow.fields.String(required=False, allow_none=True)
@marshmallow.post_load @marshmallow.post_load

View File

@ -321,7 +321,7 @@ class ProcessInstanceService:
multi_instance_type=mi_type, multi_instance_type=mi_type,
multi_instance_count=info["mi_count"], multi_instance_count=info["mi_count"],
multi_instance_index=info["mi_index"], multi_instance_index=info["mi_index"],
process_name=spiff_task.task_spec._wf_spec.description, process_identifier=spiff_task.task_spec._wf_spec.name,
properties=props, properties=props,
parent=parent_id, parent=parent_id,
call_activity_process_identifier=call_activity_process_identifier, call_activity_process_identifier=call_activity_process_identifier,

View File

@ -300,7 +300,7 @@ export default function ProcessInstanceListTable({
checkFiltersAndRun(); checkFiltersAndRun();
if (autoReload) { if (autoReload) {
refreshAtInterval(REFRESH_INTERVAL, REFRESH_TIMEOUT, checkFiltersAndRun); return refreshAtInterval(REFRESH_INTERVAL, REFRESH_TIMEOUT, checkFiltersAndRun);
} }
}, [ }, [
autoReload, autoReload,

View File

@ -58,14 +58,14 @@ import HttpService from '../services/HttpService';
import ButtonWithConfirmation from './ButtonWithConfirmation'; import ButtonWithConfirmation from './ButtonWithConfirmation';
import { makeid } from '../helpers'; import { makeid } from '../helpers';
import { useUriListForPermissions } from '../hooks/UriListForPermissions'; import { useUriListForPermissions } from '../hooks/UriListForPermissions';
import { PermissionsToCheck } from '../interfaces'; import { PermissionsToCheck, ProcessInstanceTask } from '../interfaces';
import { usePermissionFetcher } from '../hooks/PermissionService'; import { usePermissionFetcher } from '../hooks/PermissionService';
type OwnProps = { type OwnProps = {
processModelId: string; processModelId: string;
diagramType: string; diagramType: string;
readyOrWaitingBpmnTaskIds?: string[] | null; readyOrWaitingProcessInstanceTasks?: ProcessInstanceTask[] | null;
completedTasksBpmnIds?: string[] | null; completedProcessInstanceTasks?: ProcessInstanceTask[] | null;
saveDiagram?: (..._args: any[]) => any; saveDiagram?: (..._args: any[]) => any;
onDeleteFile?: (..._args: any[]) => any; onDeleteFile?: (..._args: any[]) => any;
onSetPrimaryFile?: (..._args: any[]) => any; onSetPrimaryFile?: (..._args: any[]) => any;
@ -88,8 +88,8 @@ type OwnProps = {
export default function ReactDiagramEditor({ export default function ReactDiagramEditor({
processModelId, processModelId,
diagramType, diagramType,
readyOrWaitingBpmnTaskIds, readyOrWaitingProcessInstanceTasks,
completedTasksBpmnIds, completedProcessInstanceTasks,
saveDiagram, saveDiagram,
onDeleteFile, onDeleteFile,
onSetPrimaryFile, onSetPrimaryFile,
@ -227,7 +227,9 @@ export default function ReactDiagramEditor({
function handleElementClick(event: any) { function handleElementClick(event: any) {
if (onElementClick) { if (onElementClick) {
onElementClick(event.element); const canvas = diagramModeler.get('canvas');
const rootElement = canvas.getRootElement();
onElementClick(event.element, rootElement);
} }
} }
@ -350,12 +352,15 @@ export default function ReactDiagramEditor({
function highlightBpmnIoElement( function highlightBpmnIoElement(
canvas: any, canvas: any,
taskBpmnId: string, processInstanceTask: ProcessInstanceTask,
bpmnIoClassName: string bpmnIoClassName: string,
bpmnRootElementId: string
) { ) {
if (checkTaskCanBeHighlighted(taskBpmnId)) { if (checkTaskCanBeHighlighted(processInstanceTask.name)) {
try { try {
canvas.addMarker(taskBpmnId, bpmnIoClassName); if (bpmnRootElementId === processInstanceTask.process_identifier) {
canvas.addMarker(processInstanceTask.name, bpmnIoClassName);
}
} catch (bpmnIoError: any) { } catch (bpmnIoError: any) {
// the task list also contains task for processes called from call activities which will // the task list also contains task for processes called from call activities which will
// not exist in this diagram so just ignore them for now. // not exist in this diagram so just ignore them for now.
@ -394,21 +399,25 @@ export default function ReactDiagramEditor({
// highlighting a field // highlighting a field
// Option 3 at: // Option 3 at:
// https://github.com/bpmn-io/bpmn-js-examples/tree/master/colors // https://github.com/bpmn-io/bpmn-js-examples/tree/master/colors
if (readyOrWaitingBpmnTaskIds) { if (readyOrWaitingProcessInstanceTasks) {
readyOrWaitingBpmnTaskIds.forEach((readyOrWaitingBpmnTaskId) => { const rootElement = canvas.getRootElement();
readyOrWaitingProcessInstanceTasks.forEach((readyOrWaitingBpmnTask) => {
highlightBpmnIoElement( highlightBpmnIoElement(
canvas, canvas,
readyOrWaitingBpmnTaskId, readyOrWaitingBpmnTask,
'active-task-highlight' 'active-task-highlight',
rootElement.id
); );
}); });
} }
if (completedTasksBpmnIds) { if (completedProcessInstanceTasks) {
completedTasksBpmnIds.forEach((completedTaskBpmnId) => { const rootElement = canvas.getRootElement();
completedProcessInstanceTasks.forEach((completedTask) => {
highlightBpmnIoElement( highlightBpmnIoElement(
canvas, canvas,
completedTaskBpmnId, completedTask,
'completed-task-highlight' 'completed-task-highlight',
rootElement.id
); );
}); });
} }
@ -484,8 +493,8 @@ export default function ReactDiagramEditor({
diagramType, diagramType,
diagramXML, diagramXML,
diagramXMLString, diagramXMLString,
readyOrWaitingBpmnTaskIds, readyOrWaitingProcessInstanceTasks,
completedTasksBpmnIds, completedProcessInstanceTasks,
fileName, fileName,
performingXmlUpdates, performingXmlUpdates,
processModelId, processModelId,

View File

@ -41,7 +41,7 @@ export default function MyOpenProcesses() {
}); });
}; };
getTasks(); getTasks();
refreshAtInterval(REFRESH_INTERVAL, REFRESH_TIMEOUT, getTasks); return refreshAtInterval(REFRESH_INTERVAL, REFRESH_TIMEOUT, getTasks);
}, [searchParams]); }, [searchParams]);
const buildTable = () => { const buildTable = () => {

View File

@ -41,7 +41,7 @@ export default function TasksWaitingForMyGroups() {
}); });
}; };
getTasks(); getTasks();
refreshAtInterval(REFRESH_INTERVAL, REFRESH_TIMEOUT, getTasks); return refreshAtInterval(REFRESH_INTERVAL, REFRESH_TIMEOUT, getTasks);
}, [searchParams]); }, [searchParams]);
const buildTable = () => { const buildTable = () => {

View File

@ -208,5 +208,8 @@ export const refreshAtInterval = (
() => clearInterval(intervalRef), () => clearInterval(intervalRef),
timeout * 1000 timeout * 1000
); );
return [intervalRef, timeoutRef]; return () => {
clearInterval(intervalRef);
clearTimeout(timeoutRef);
};
}; };

View File

@ -11,6 +11,13 @@ export interface RecentProcessModel {
processModelDisplayName: string; processModelDisplayName: string;
} }
export interface ProcessInstanceTask {
id: string;
state: string;
process_identifier: string;
name: string;
}
export interface ProcessReference { export interface ProcessReference {
name: string; // The process or decision Display name. name: string; // The process or decision Display name.
identifier: string; // The unique id of the process identifier: string; // The unique id of the process
@ -39,6 +46,7 @@ export interface ProcessInstance {
id: number; id: number;
process_model_identifier: string; process_model_identifier: string;
process_model_display_name: string; process_model_display_name: string;
spiff_step?: number;
} }
export interface MessageCorrelationProperties { export interface MessageCorrelationProperties {

View File

@ -39,7 +39,11 @@ import {
import ButtonWithConfirmation from '../components/ButtonWithConfirmation'; import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
import ErrorContext from '../contexts/ErrorContext'; import ErrorContext from '../contexts/ErrorContext';
import { useUriListForPermissions } from '../hooks/UriListForPermissions'; import { useUriListForPermissions } from '../hooks/UriListForPermissions';
import { PermissionsToCheck } from '../interfaces'; import {
PermissionsToCheck,
ProcessInstance,
ProcessInstanceTask,
} from '../interfaces';
import { usePermissionFetcher } from '../hooks/PermissionService'; import { usePermissionFetcher } from '../hooks/PermissionService';
export default function ProcessInstanceShow() { export default function ProcessInstanceShow() {
@ -47,8 +51,9 @@ export default function ProcessInstanceShow() {
const params = useParams(); const params = useParams();
const [searchParams] = useSearchParams(); const [searchParams] = useSearchParams();
const [processInstance, setProcessInstance] = useState(null); const [processInstance, setProcessInstance] =
const [tasks, setTasks] = useState<Array<object> | null>(null); useState<ProcessInstance | null>(null);
const [tasks, setTasks] = useState<ProcessInstanceTask[] | null>(null);
const [tasksCallHadError, setTasksCallHadError] = useState<boolean>(false); const [tasksCallHadError, setTasksCallHadError] = useState<boolean>(false);
const [taskToDisplay, setTaskToDisplay] = useState<object | null>(null); const [taskToDisplay, setTaskToDisplay] = useState<object | null>(null);
const [taskDataToDisplay, setTaskDataToDisplay] = useState<string>(''); const [taskDataToDisplay, setTaskDataToDisplay] = useState<string>('');
@ -158,12 +163,12 @@ export default function ProcessInstanceShow() {
const getTaskIds = () => { const getTaskIds = () => {
const taskIds = { completed: [], readyOrWaiting: [] }; const taskIds = { completed: [], readyOrWaiting: [] };
if (tasks) { if (tasks) {
tasks.forEach(function getUserTasksElement(task: any) { tasks.forEach(function getUserTasksElement(task: ProcessInstanceTask) {
if (task.state === 'COMPLETED') { if (task.state === 'COMPLETED') {
(taskIds.completed as any).push(task.name); (taskIds.completed as any).push(task);
} }
if (task.state === 'READY' || task.state === 'WAITING') { if (task.state === 'READY' || task.state === 'WAITING') {
(taskIds.readyOrWaiting as any).push(task.name); (taskIds.readyOrWaiting as any).push(task);
} }
}); });
} }
@ -193,13 +198,18 @@ export default function ProcessInstanceShow() {
label: any, label: any,
distance: number distance: number
) => { ) => {
const processIdentifier = searchParams.get('process_identifier');
let queryParams = '';
if (processIdentifier) {
queryParams = `?process_identifier=${processIdentifier}`;
}
return ( return (
<Link <Link
reloadDocument reloadDocument
data-qa="process-instance-step-link" data-qa="process-instance-step-link"
to={`/admin/process-instances/${params.process_model_id}/${ to={`/admin/process-instances/${params.process_model_id}/${
params.process_instance_id params.process_instance_id
}/${currentSpiffStep(processInstanceToUse) + distance}`} }/${currentSpiffStep(processInstanceToUse) + distance}${queryParams}`}
> >
{label} {label}
</Link> </Link>
@ -380,10 +390,15 @@ export default function ProcessInstanceShow() {
} }
}; };
const handleClickedDiagramTask = (shapeElement: any) => { const handleClickedDiagramTask = (
shapeElement: any,
bpmnRootElement: any
) => {
if (tasks) { if (tasks) {
const matchingTask: any = tasks.find( const matchingTask: any = tasks.find(
(task: any) => task.name === shapeElement.id (task: any) =>
task.name === shapeElement.id &&
task.process_identifier === bpmnRootElement.id
); );
if (matchingTask) { if (matchingTask) {
setTaskToDisplay(matchingTask); setTaskToDisplay(matchingTask);
@ -491,7 +506,7 @@ export default function ProcessInstanceShow() {
buttons.push( buttons.push(
<Link <Link
data-qa="go-to-call-activity-result" data-qa="go-to-call-activity-result"
to={`/admin/process-instances/${params.process_model_id}/${params.process_instance_id}?process_identifier=${task.call_activity_process_identifier}`} to={`${window.location.pathname}?process_identifier=${task.call_activity_process_identifier}`}
target="_blank" target="_blank"
> >
View Call Activity Diagram View Call Activity Diagram
@ -647,8 +662,8 @@ export default function ProcessInstanceShow() {
processModelId={processModelId || ''} processModelId={processModelId || ''}
diagramXML={processInstanceToUse.bpmn_xml_file_contents || ''} diagramXML={processInstanceToUse.bpmn_xml_file_contents || ''}
fileName={processInstanceToUse.bpmn_xml_file_contents || ''} fileName={processInstanceToUse.bpmn_xml_file_contents || ''}
readyOrWaitingBpmnTaskIds={taskIds.readyOrWaiting} readyOrWaitingProcessInstanceTasks={taskIds.readyOrWaiting}
completedTasksBpmnIds={taskIds.completed} completedProcessInstanceTasks={taskIds.completed}
diagramType="readonly" diagramType="readonly"
onElementClick={handleClickedDiagramTask} onElementClick={handleClickedDiagramTask}
/> />