diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py index 79814c1d5..5c924196a 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py @@ -120,6 +120,7 @@ class Task: parent: Optional[str] = None, event_definition: Union[dict[str, Any], None] = None, call_activity_process_identifier: Optional[str] = None, + calling_subprocess_task_id: Optional[str] = None, ): """__init__.""" self.id = id @@ -133,6 +134,7 @@ class Task: self.parent = parent self.event_definition = event_definition self.call_activity_process_identifier = call_activity_process_identifier + self.calling_subprocess_task_id = calling_subprocess_task_id self.data = data if self.data is None: @@ -193,6 +195,7 @@ class Task: "parent": self.parent, "event_definition": self.event_definition, "call_activity_process_identifier": self.call_activity_process_identifier, + "calling_subprocess_task_id": self.calling_subprocess_task_id, } @classmethod diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py index d22b61677..ed27f2b24 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py @@ -553,9 +553,15 @@ def process_instance_task_list( else: spiff_tasks = processor.get_all_user_tasks() + subprocesses_by_child_task_ids = processor.get_subprocesses_by_child_task_ids() tasks = [] for spiff_task in spiff_tasks: - task = ProcessInstanceService.spiff_task_to_api_task(processor, spiff_task) + calling_subprocess_task_id = subprocesses_by_child_task_ids.get( + str(spiff_task.id), None + ) + task = ProcessInstanceService.spiff_task_to_api_task( + processor, spiff_task, calling_subprocess_task_id=calling_subprocess_task_id + ) if get_task_data: task.data = spiff_task.data tasks.append(task) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/authentication_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/authentication_service.py index d9ab15464..f697904ea 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/authentication_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/authentication_service.py @@ -57,7 +57,10 @@ class AuthenticationService: response = requests.get(openid_config_url) AuthenticationService.ENDPOINT_CACHE = response.json() if name not in AuthenticationService.ENDPOINT_CACHE: - raise Exception(f"Unknown OpenID Endpoint: {name}. Tried to get from {openid_config_url}") + raise Exception( + f"Unknown OpenID Endpoint: {name}. Tried to get from" + f" {openid_config_url}" + ) return AuthenticationService.ENDPOINT_CACHE.get(name, "") @staticmethod 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 eec9b7cac..fe0d22770 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -625,6 +625,29 @@ class ProcessInstanceProcessor: db.session.add(pim) db.session.commit() + def get_subprocesses_by_child_task_ids(self) -> dict: + """Get all subprocess ids based on the child task ids. + + This is useful when trying to link the child task of a call activity back to + the call activity that called it to get the appropriate data. For example, if you + have a call activity "Log" that you call twice within the same process, the Hammer log file + activity within the Log process will get called twice. They will potentially have different + task data. We want to be able to differentiate those two activities. + + subprocess structure in the json: + "subprocesses": { [subprocess_task_id]: "tasks" : { [task_id]: [bpmn_task_details] }} + + Also note that subprocess_task_id might in fact be a call activity, because spiff treats + call activities like subprocesses in terms of the serialization. + """ + bpmn_json = json.loads(self.serialize()) + subprocesses_by_child_task_ids = {} + if "subprocesses" in bpmn_json: + for subprocess_id, subprocess_details in bpmn_json["subprocesses"].items(): + for task_id in subprocess_details["tasks"]: + subprocesses_by_child_task_ids[task_id] = subprocess_id + return subprocesses_by_child_task_ids + def save(self) -> None: """Saves the current state of this processor to the database.""" self.process_instance_model.bpmn_json = self.serialize() diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py index c6e3db42e..9812609fe 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py @@ -2,6 +2,7 @@ import time from typing import Any from typing import List +from typing import Optional from flask import current_app from flask_bpmn.api.api_error import ApiError @@ -288,6 +289,7 @@ class ProcessInstanceService: processor: ProcessInstanceProcessor, spiff_task: SpiffTask, add_docs_and_forms: bool = False, + calling_subprocess_task_id: Optional[str] = None, ) -> Task: """Spiff_task_to_api_task.""" task_type = spiff_task.task_spec.spec_type @@ -338,6 +340,7 @@ class ProcessInstanceService: parent=parent_id, event_definition=serialized_task_spec.get("event_definition"), call_activity_process_identifier=call_activity_process_identifier, + calling_subprocess_task_id=calling_subprocess_task_id, ) return task diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index e89c355ba..51e8c2d6a 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -1050,8 +1050,8 @@ export default function ProcessInstanceListTable({ } return null; }} - placeholder="Process Initiator" - titleText="PROC" + placeholder="Starting typing username" + titleText="Process Initiator" selectedItem={processInitiatorSelection} /> diff --git a/spiffworkflow-frontend/src/interfaces.ts b/spiffworkflow-frontend/src/interfaces.ts index 630db8da1..97ef763c1 100644 --- a/spiffworkflow-frontend/src/interfaces.ts +++ b/spiffworkflow-frontend/src/interfaces.ts @@ -39,6 +39,7 @@ export interface ProcessInstanceTask { updated_at_in_seconds: number; current_user_is_potential_owner: number; potential_owner_usernames: string; + calling_subprocess_task_id: string; } export interface ProcessReference { diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index b40781558..dc0e761f9 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -200,11 +200,18 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { const taskIds = { completed: [], readyOrWaiting: [] }; if (tasks) { tasks.forEach(function getUserTasksElement(task: ProcessInstanceTask) { - if (task.state === 'COMPLETED') { - (taskIds.completed as any).push(task); - } - if (task.state === 'READY' || task.state === 'WAITING') { - (taskIds.readyOrWaiting as any).push(task); + const callingSubprocessId = searchParams.get('call_activity_task_id'); + if ( + !callingSubprocessId || + callingSubprocessId === task.calling_subprocess_task_id + ) { + console.log('callingSubprocessId', callingSubprocessId); + if (task.state === 'COMPLETED') { + (taskIds.completed as any).push(task); + } + if (task.state === 'READY' || task.state === 'WAITING') { + (taskIds.readyOrWaiting as any).push(task); + } } }); } @@ -474,7 +481,10 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { }); } else if (tasks) { const matchingTask: any = tasks.find((task: any) => { + const callingSubprocessId = searchParams.get('call_activity_task_id'); return ( + (!callingSubprocessId || + callingSubprocessId === task.calling_subprocess_task_id) && task.name === shapeElement.id && bpmnProcessIdentifiers.includes(task.process_identifier) ); @@ -667,7 +677,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { buttons.push( View Call Activity Diagram