From d6e658ab070c1dc2de83d81e77f1be021aad44fd Mon Sep 17 00:00:00 2001 From: Elizabeth Esswein Date: Mon, 9 Jan 2023 23:09:49 -0500 Subject: [PATCH] handle subprocesses in navigation --- .../services/process_instance_processor.py | 39 +++++++++++++++---- .../src/routes/ProcessInstanceShow.tsx | 17 +++++++- 2 files changed, 47 insertions(+), 9 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py index 9c30e1c8b..5115107bf 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -34,6 +34,8 @@ from SpiffWorkflow.bpmn.serializer.workflow import BpmnWorkflowSerializer # typ from SpiffWorkflow.bpmn.specs.BpmnProcessSpec import BpmnProcessSpec # type: ignore from SpiffWorkflow.bpmn.specs.events.EndEvent import EndEvent # type: ignore from SpiffWorkflow.bpmn.specs.events.event_definitions import CancelEventDefinition # type: ignore +from SpiffWorkflow.bpmn.specs.events.StartEvent import StartEvent # type: ignore +from SpiffWorkflow.bpmn.specs.SubWorkflowTask import SubWorkflowTask # type: ignore from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore from SpiffWorkflow.dmn.parser.BpmnDmnParser import BpmnDmnParser # type: ignore from SpiffWorkflow.dmn.serializer.task_spec_converters import BusinessRuleTaskConverter # type: ignore @@ -68,7 +70,6 @@ from SpiffWorkflow.spiff.serializer.task_spec_converters import UserTaskConverte from SpiffWorkflow.task import Task as SpiffTask # type: ignore from SpiffWorkflow.task import TaskState from SpiffWorkflow.util.deep_merge import DeepMerge # type: ignore - from spiffworkflow_backend.models.file import File from spiffworkflow_backend.models.file import FileType from spiffworkflow_backend.models.group import GroupModel @@ -301,7 +302,9 @@ class ProcessInstanceProcessor: tld.spiff_step = process_instance_model.spiff_step # we want this to be the fully qualified path to the process model including all group subcomponents - current_app.config["THREAD_LOCAL_DATA"].process_model_identifier = ( + current_app.config[ + "THREAD_LOCAL_DATA" + ].process_model_identifier = ( f"{process_instance_model.process_model_identifier}" ) @@ -655,9 +658,9 @@ class ProcessInstanceProcessor: """ for task_id, subprocess_id in subprocesses_by_child_task_ids.items(): if subprocess_id in subprocesses_by_child_task_ids: - subprocesses_by_child_task_ids[task_id] = ( - subprocesses_by_child_task_ids[subprocess_id] - ) + subprocesses_by_child_task_ids[ + task_id + ] = subprocesses_by_child_task_ids[subprocess_id] self.get_highest_level_subprocesses_by_child_task_ids( subprocesses_by_child_task_ids ) @@ -787,7 +790,16 @@ class ProcessInstanceProcessor: f"Manually executing Task {spiff_task.task_spec.name} of process" f" instance {self.process_instance_model.id}" ) - spiff_task.complete() + # Executing a subworkflow manually will restart its subprocess and allow stepping through it + if isinstance(spiff_task.task_spec, SubWorkflowTask): + subprocess = self.bpmn_process_instance.get_subprocess(spiff_task) + # We have to get to the actual start event + for task in self.bpmn_process_instance.get_tasks(workflow=subprocess): + task.complete() + if isinstance(task.task_spec, StartEvent): + break + else: + spiff_task.complete() else: spiff_logger = logging.getLogger("spiff") spiff_logger.info( @@ -796,7 +808,20 @@ class ProcessInstanceProcessor: spiff_task._set_state(TaskState.COMPLETED) for child in spiff_task.children: child.task_spec._update(child) - self.bpmn_process_instance.last_task = spiff_task + spiff_task.workflow.last_task = spiff_task + + if isinstance(spiff_task.task_spec, EndEvent): + for task in self.bpmn_process_instance.get_tasks( + TaskState.DEFINITE_MASK, workflow=spiff_task.workflow + ): + task.complete() + + # A subworkflow task will become ready when its workflow is complete. Engine steps would normally + # then complete it, but we have to do it ourselves here. + for task in self.bpmn_process_instance.get_tasks(TaskState.READY): + if isinstance(task.task_spec, SubWorkflowTask): + task.complete() + self.increment_spiff_step() self.add_step() self.save() diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index 2d0f52910..b32e16fc5 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -528,11 +528,24 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { } }; + const isCurrentTask = (task: any) => { + const subprocessTypes = [ + 'Subprocess', + 'Call Activity', + 'Transactional Subprocess', + ]; + return ( + (task.state === 'WAITING' && + subprocessTypes.filter((t) => t === task.type).length > 0) || + task.state === 'READY' + ); + }; + const canEditTaskData = (task: any) => { return ( processInstance && ability.can('PUT', targetUris.processInstanceTaskListDataPath) && - task.state === 'READY' && + isCurrentTask(task) && processInstance.status === 'suspended' && showingLastSpiffStep() ); @@ -556,7 +569,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { processInstance && processInstance.status === 'suspended' && ability.can('POST', targetUris.processInstanceCompleteTaskPath) && - task.state === 'READY' && + isCurrentTask(task) && showingLastSpiffStep() ); };