diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/api.yml b/spiffworkflow-backend/src/spiffworkflow_backend/api.yml index 764ba543..84ada234 100755 --- a/spiffworkflow-backend/src/spiffworkflow_backend/api.yml +++ b/spiffworkflow-backend/src/spiffworkflow_backend/api.yml @@ -699,6 +699,12 @@ paths: description: The unique id of an existing process instance. schema: type: integer + - name: process_identifier + in: query + required: false + description: The identifier of the process to use for the diagram. Useful for displaying the diagram for a call activity. + schema: + type: string get: tags: - Process Instances diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance_metadata.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance_metadata.py index c9003594..f2e4c222 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance_metadata.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance_metadata.py @@ -1,4 +1,4 @@ -"""Spiff_step_details.""" +"""Process_instance_metadata.""" from dataclasses import dataclass from flask_bpmn.models.db import db diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/spec_reference.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/spec_reference.py index 1e85f722..50b73fba 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/spec_reference.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/spec_reference.py @@ -8,6 +8,10 @@ from marshmallow import INCLUDE from sqlalchemy import UniqueConstraint +class SpecReferenceNotFoundError(Exception): + """SpecReferenceNotFoundError.""" + + @dataclass() class SpecReference: """File Reference Information. diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py index 91d70116..9afb5d07 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py @@ -21,7 +21,7 @@ class SpiffStepDetailsModel(SpiffworkflowBaseDBModel): ForeignKey(ProcessInstanceModel.id), nullable=False # type: ignore ) spiff_step: int = db.Column(db.Integer, nullable=False) - task_json: str = deferred(db.Column(db.JSON, nullable=False)) # type: ignore + task_json: dict = deferred(db.Column(db.JSON, nullable=False)) # type: ignore timestamp: float = db.Column(db.DECIMAL(17, 6), nullable=False) completed_by_user_id: int = db.Column(db.Integer, nullable=True) lane_assignment_id: Optional[int] = db.Column( diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py index 52bb1171..60deda84 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/task.py @@ -108,7 +108,7 @@ class Task: multi_instance_type: Union[MultiInstanceType, None] = None, multi_instance_count: str = "", multi_instance_index: str = "", - process_name: str = "", + process_identifier: str = "", properties: Union[dict, None] = None, process_instance_id: Union[int, None] = None, process_instance_status: Union[str, None] = None, @@ -118,6 +118,7 @@ class Task: form_schema: Union[str, None] = None, form_ui_schema: Union[str, None] = None, parent: Optional[str] = None, + call_activity_process_identifier: Optional[str] = None, ): """__init__.""" self.id = id @@ -129,6 +130,7 @@ class Task: self.documentation = documentation self.lane = lane self.parent = parent + self.call_activity_process_identifier = call_activity_process_identifier self.data = data if self.data is None: @@ -151,7 +153,7 @@ class Task: self.multi_instance_index = ( 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. if self.properties is None: @@ -177,7 +179,7 @@ class Task: "multi_instance_type": multi_instance_type, "multi_instance_count": self.multi_instance_count, "multi_instance_index": self.multi_instance_index, - "process_name": self.process_name, + "process_identifier": self.process_identifier, "properties": self.properties, "process_instance_id": self.process_instance_id, "process_instance_status": self.process_instance_status, @@ -187,6 +189,7 @@ class Task: "form_schema": self.form_schema, "form_ui_schema": self.form_ui_schema, "parent": self.parent, + "call_activity_process_identifier": self.call_activity_process_identifier, } @classmethod @@ -282,7 +285,7 @@ class TaskSchema(Schema): "multi_instance_type", "multi_instance_count", "multi_instance_index", - "process_name", + "process_identifier", "properties", "process_instance_id", "form_schema", @@ -293,7 +296,7 @@ class TaskSchema(Schema): documentation = marshmallow.fields.String(required=False, allow_none=True) # form = marshmallow.fields.Nested(FormSchema, 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) @marshmallow.post_load diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py index c29cf214..026ed35d 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -66,6 +66,7 @@ from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema from spiffworkflow_backend.models.secret_model import SecretModel from spiffworkflow_backend.models.secret_model import SecretModelSchema from spiffworkflow_backend.models.spec_reference import SpecReferenceCache +from spiffworkflow_backend.models.spec_reference import SpecReferenceNotFoundError from spiffworkflow_backend.models.spec_reference import SpecReferenceSchema from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel from spiffworkflow_backend.models.spiff_step_details import SpiffStepDetailsModel @@ -1073,25 +1074,48 @@ def process_instance_report_column_list() -> flask.wrappers.Response: def process_instance_show( - modified_process_model_identifier: str, process_instance_id: int + modified_process_model_identifier: str, + process_instance_id: int, + process_identifier: Optional[str] = None, ) -> flask.wrappers.Response: """Create_process_instance.""" process_model_identifier = modified_process_model_identifier.replace(":", "/") process_instance = find_process_instance_by_id_or_raise(process_instance_id) current_version_control_revision = GitService.get_current_revision() - process_model = get_process_model(process_model_identifier) - if process_model.primary_file_name: + process_model_with_diagram = None + name_of_file_with_diagram = None + if process_identifier: + spec_reference = SpecReferenceCache.query.filter_by( + identifier=process_identifier + ).first() + if spec_reference is None: + raise SpecReferenceNotFoundError( + f"Could not find given process identifier in the cache: {process_identifier}" + ) + + process_model_with_diagram = ProcessModelService.get_process_model( + spec_reference.process_model_id + ) + name_of_file_with_diagram = spec_reference.file_name + else: + process_model_with_diagram = get_process_model(process_model_identifier) + if process_model_with_diagram.primary_file_name: + name_of_file_with_diagram = process_model_with_diagram.primary_file_name + + if process_model_with_diagram and name_of_file_with_diagram: if ( process_instance.bpmn_version_control_identifier == current_version_control_revision ): bpmn_xml_file_contents = SpecFileService.get_data( - process_model, process_model.primary_file_name + process_model_with_diagram, name_of_file_with_diagram ).decode("utf-8") else: bpmn_xml_file_contents = GitService.get_instance_file_contents_for_revision( - process_model, process_instance.bpmn_version_control_identifier + process_model_with_diagram, + process_instance.bpmn_version_control_identifier, + file_name=name_of_file_with_diagram, ) process_instance.bpmn_xml_file_contents = bpmn_xml_file_contents @@ -1409,7 +1433,8 @@ def process_instance_task_list( ) if step_detail is not None and process_instance.bpmn_json is not None: bpmn_json = json.loads(process_instance.bpmn_json) - bpmn_json["tasks"] = step_detail.task_json + bpmn_json["tasks"] = step_detail.task_json["tasks"] + bpmn_json["subprocesses"] = step_detail.task_json["subprocesses"] process_instance.bpmn_json = json.dumps(bpmn_json) processor = ProcessInstanceProcessor(process_instance) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py index f972b672..152aab1c 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/git_service.py @@ -46,18 +46,24 @@ class GitService: @classmethod def get_instance_file_contents_for_revision( - cls, process_model: ProcessModelInfo, revision: str + cls, + process_model: ProcessModelInfo, + revision: str, + file_name: Optional[str] = None, ) -> str: """Get_instance_file_contents_for_revision.""" bpmn_spec_absolute_dir = current_app.config["BPMN_SPEC_ABSOLUTE_DIR"] process_model_relative_path = FileSystemService.process_model_relative_path( process_model ) + file_name_to_use = file_name + if file_name_to_use is None: + file_name_to_use = process_model.primary_file_name with FileSystemService.cd(bpmn_spec_absolute_dir): shell_command = [ "git", "show", - f"{revision}:{process_model_relative_path}/{process_model.primary_file_name}", + f"{revision}:{process_model_relative_path}/{file_name_to_use}", ] return cls.run_shell_command_to_get_stdout(shell_command) 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 ffe69fd7..5edc526c 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -551,7 +551,7 @@ class ProcessInstanceProcessor: """SaveSpiffStepDetails.""" bpmn_json = self.serialize() wf_json = json.loads(bpmn_json) - task_json = wf_json["tasks"] + task_json = {"tasks": wf_json["tasks"], "subprocesses": wf_json["subprocesses"]} return { "process_instance_id": self.process_instance_model.id, 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 46bd252b..5b2781a2 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py @@ -302,6 +302,11 @@ class ProcessInstanceService: else: lane = None + if hasattr(spiff_task.task_spec, "spec"): + call_activity_process_identifier = spiff_task.task_spec.spec + else: + call_activity_process_identifier = None + parent_id = None if spiff_task.parent: parent_id = spiff_task.parent.id @@ -316,9 +321,10 @@ class ProcessInstanceService: multi_instance_type=mi_type, multi_instance_count=info["mi_count"], 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, parent=parent_id, + call_activity_process_identifier=call_activity_process_identifier, ) return task diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/spec_file_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/spec_file_service.py index c69f41c3..72f59d1f 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/spec_file_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/spec_file_service.py @@ -171,13 +171,18 @@ class SpecFileService(FileSystemService): ref.is_primary = True if ref.is_primary: - ProcessModelService.update_process_model( - process_model_info, - { - "primary_process_id": ref.identifier, - "primary_file_name": file_name, - }, - ) + update_hash = {} + if not process_model_info.primary_file_name: + update_hash["primary_process_id"] = ref.identifier + update_hash["primary_file_name"] = file_name + elif file_name == process_model_info.primary_file_name: + update_hash["primary_process_id"] = ref.identifier + + if len(update_hash) > 0: + ProcessModelService.update_process_model( + process_model_info, + update_hash, + ) SpecFileService.update_caches(ref) return file diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py index 0070c5c9..4a0100d3 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py @@ -1167,6 +1167,60 @@ class TestProcessApi(BaseTest): xml_file_contents = f_open.read() assert show_response.json["bpmn_xml_file_contents"] == xml_file_contents + def test_process_instance_show_with_specified_process_identifier( + self, + app: Flask, + client: FlaskClient, + with_db_and_bpmn_file_cleanup: None, + with_super_admin_user: UserModel, + ) -> None: + """Test_process_instance_show_with_specified_process_identifier.""" + process_model_id = "call_activity_nested" + process_model_identifier = self.create_group_and_model_with_bpmn( + client=client, + user=with_super_admin_user, + process_group_id="test_group_two", + process_model_id=process_model_id, + bpmn_file_location="call_activity_nested", + ) + spec_reference = SpecReferenceCache.query.filter_by( + identifier="Level2b" + ).first() + assert spec_reference + modified_process_model_identifier = ( + self.modify_process_identifier_for_path_param(process_model_identifier) + ) + headers = self.logged_in_headers(with_super_admin_user) + create_response = self.create_process_instance_from_process_model_id( + client, process_model_identifier, headers + ) + assert create_response.json is not None + assert create_response.status_code == 201 + process_instance_id = create_response.json["id"] + client.post( + f"/v1.0/process-instances/{modified_process_model_identifier}/{process_instance_id}/run", + headers=self.logged_in_headers(with_super_admin_user), + ) + show_response = client.get( + f"/v1.0/process-instances/{modified_process_model_identifier}/{process_instance_id}?process_identifier={spec_reference.identifier}", + headers=self.logged_in_headers(with_super_admin_user), + ) + assert show_response.json is not None + assert show_response.status_code == 200 + file_system_root = FileSystemService.root_path() + process_instance_file_path = ( + f"{file_system_root}/{process_model_identifier}/{process_model_id}.bpmn" + ) + with open(process_instance_file_path) as f_open: + xml_file_contents = f_open.read() + assert show_response.json["bpmn_xml_file_contents"] != xml_file_contents + spec_reference_file_path = os.path.join( + file_system_root, spec_reference.relative_path + ) + with open(spec_reference_file_path) as f_open: + xml_file_contents = f_open.read() + assert show_response.json["bpmn_xml_file_contents"] == xml_file_contents + def test_message_start_when_starting_process_instance( self, app: Flask, diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index 98b76df3..64b0a7e9 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -300,8 +300,13 @@ export default function ProcessInstanceListTable({ checkFiltersAndRun(); if (autoReload) { - refreshAtInterval(REFRESH_INTERVAL, REFRESH_TIMEOUT, checkFiltersAndRun); + return refreshAtInterval( + REFRESH_INTERVAL, + REFRESH_TIMEOUT, + checkFiltersAndRun + ); } + return undefined; }, [ autoReload, searchParams, diff --git a/spiffworkflow-frontend/src/components/ReactDiagramEditor.tsx b/spiffworkflow-frontend/src/components/ReactDiagramEditor.tsx index 11839e9c..a1be5efa 100644 --- a/spiffworkflow-frontend/src/components/ReactDiagramEditor.tsx +++ b/spiffworkflow-frontend/src/components/ReactDiagramEditor.tsx @@ -58,14 +58,14 @@ import HttpService from '../services/HttpService'; import ButtonWithConfirmation from './ButtonWithConfirmation'; import { makeid } from '../helpers'; import { useUriListForPermissions } from '../hooks/UriListForPermissions'; -import { PermissionsToCheck } from '../interfaces'; +import { PermissionsToCheck, ProcessInstanceTask } from '../interfaces'; import { usePermissionFetcher } from '../hooks/PermissionService'; type OwnProps = { processModelId: string; diagramType: string; - readyOrWaitingBpmnTaskIds?: string[] | null; - completedTasksBpmnIds?: string[] | null; + readyOrWaitingProcessInstanceTasks?: ProcessInstanceTask[] | null; + completedProcessInstanceTasks?: ProcessInstanceTask[] | null; saveDiagram?: (..._args: any[]) => any; onDeleteFile?: (..._args: any[]) => any; onSetPrimaryFile?: (..._args: any[]) => any; @@ -88,8 +88,8 @@ type OwnProps = { export default function ReactDiagramEditor({ processModelId, diagramType, - readyOrWaitingBpmnTaskIds, - completedTasksBpmnIds, + readyOrWaitingProcessInstanceTasks, + completedProcessInstanceTasks, saveDiagram, onDeleteFile, onSetPrimaryFile, @@ -227,7 +227,9 @@ export default function ReactDiagramEditor({ function handleElementClick(event: any) { 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( canvas: any, - taskBpmnId: string, - bpmnIoClassName: string + processInstanceTask: ProcessInstanceTask, + bpmnIoClassName: string, + bpmnRootElementId: string ) { - if (checkTaskCanBeHighlighted(taskBpmnId)) { + if (checkTaskCanBeHighlighted(processInstanceTask.name)) { try { - canvas.addMarker(taskBpmnId, bpmnIoClassName); + if (bpmnRootElementId === processInstanceTask.process_identifier) { + canvas.addMarker(processInstanceTask.name, bpmnIoClassName); + } } catch (bpmnIoError: any) { // 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. @@ -394,21 +399,25 @@ export default function ReactDiagramEditor({ // highlighting a field // Option 3 at: // https://github.com/bpmn-io/bpmn-js-examples/tree/master/colors - if (readyOrWaitingBpmnTaskIds) { - readyOrWaitingBpmnTaskIds.forEach((readyOrWaitingBpmnTaskId) => { + if (readyOrWaitingProcessInstanceTasks) { + const rootElement = canvas.getRootElement(); + readyOrWaitingProcessInstanceTasks.forEach((readyOrWaitingBpmnTask) => { highlightBpmnIoElement( canvas, - readyOrWaitingBpmnTaskId, - 'active-task-highlight' + readyOrWaitingBpmnTask, + 'active-task-highlight', + rootElement.id ); }); } - if (completedTasksBpmnIds) { - completedTasksBpmnIds.forEach((completedTaskBpmnId) => { + if (completedProcessInstanceTasks) { + const rootElement = canvas.getRootElement(); + completedProcessInstanceTasks.forEach((completedTask) => { highlightBpmnIoElement( canvas, - completedTaskBpmnId, - 'completed-task-highlight' + completedTask, + 'completed-task-highlight', + rootElement.id ); }); } @@ -484,8 +493,8 @@ export default function ReactDiagramEditor({ diagramType, diagramXML, diagramXMLString, - readyOrWaitingBpmnTaskIds, - completedTasksBpmnIds, + readyOrWaitingProcessInstanceTasks, + completedProcessInstanceTasks, fileName, performingXmlUpdates, processModelId, diff --git a/spiffworkflow-frontend/src/components/TasksForMyOpenProcesses.tsx b/spiffworkflow-frontend/src/components/TasksForMyOpenProcesses.tsx index deb2030e..297f2071 100644 --- a/spiffworkflow-frontend/src/components/TasksForMyOpenProcesses.tsx +++ b/spiffworkflow-frontend/src/components/TasksForMyOpenProcesses.tsx @@ -41,7 +41,7 @@ export default function MyOpenProcesses() { }); }; getTasks(); - refreshAtInterval(REFRESH_INTERVAL, REFRESH_TIMEOUT, getTasks); + return refreshAtInterval(REFRESH_INTERVAL, REFRESH_TIMEOUT, getTasks); }, [searchParams]); const buildTable = () => { diff --git a/spiffworkflow-frontend/src/components/TasksWaitingForMyGroups.tsx b/spiffworkflow-frontend/src/components/TasksWaitingForMyGroups.tsx index 565cd4a5..5b05dcd0 100644 --- a/spiffworkflow-frontend/src/components/TasksWaitingForMyGroups.tsx +++ b/spiffworkflow-frontend/src/components/TasksWaitingForMyGroups.tsx @@ -41,7 +41,7 @@ export default function TasksWaitingForMyGroups() { }); }; getTasks(); - refreshAtInterval(REFRESH_INTERVAL, REFRESH_TIMEOUT, getTasks); + return refreshAtInterval(REFRESH_INTERVAL, REFRESH_TIMEOUT, getTasks); }, [searchParams]); const buildTable = () => { diff --git a/spiffworkflow-frontend/src/helpers.tsx b/spiffworkflow-frontend/src/helpers.tsx index 6781ada9..0b73e517 100644 --- a/spiffworkflow-frontend/src/helpers.tsx +++ b/spiffworkflow-frontend/src/helpers.tsx @@ -208,5 +208,8 @@ export const refreshAtInterval = ( () => clearInterval(intervalRef), timeout * 1000 ); - return [intervalRef, timeoutRef]; + return () => { + clearInterval(intervalRef); + clearTimeout(timeoutRef); + }; }; diff --git a/spiffworkflow-frontend/src/interfaces.ts b/spiffworkflow-frontend/src/interfaces.ts index 079e4cdc..6afb1144 100644 --- a/spiffworkflow-frontend/src/interfaces.ts +++ b/spiffworkflow-frontend/src/interfaces.ts @@ -11,6 +11,13 @@ export interface RecentProcessModel { processModelDisplayName: string; } +export interface ProcessInstanceTask { + id: string; + state: string; + process_identifier: string; + name: string; +} + export interface ProcessReference { name: string; // The process or decision Display name. identifier: string; // The unique id of the process @@ -39,6 +46,7 @@ export interface ProcessInstance { id: number; process_model_identifier: string; process_model_display_name: string; + spiff_step?: number; } export interface MessageCorrelationProperties { diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index 9a0495d1..3e0c2094 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -1,6 +1,11 @@ import { useContext, useEffect, useState } from 'react'; import Editor from '@monaco-editor/react'; -import { useParams, useNavigate, Link } from 'react-router-dom'; +import { + useParams, + useNavigate, + Link, + useSearchParams, +} from 'react-router-dom'; import { TrashCan, StopOutline, @@ -34,15 +39,21 @@ import { import ButtonWithConfirmation from '../components/ButtonWithConfirmation'; import ErrorContext from '../contexts/ErrorContext'; import { useUriListForPermissions } from '../hooks/UriListForPermissions'; -import { PermissionsToCheck } from '../interfaces'; +import { + PermissionsToCheck, + ProcessInstance, + ProcessInstanceTask, +} from '../interfaces'; import { usePermissionFetcher } from '../hooks/PermissionService'; export default function ProcessInstanceShow() { const navigate = useNavigate(); const params = useParams(); + const [searchParams] = useSearchParams(); - const [processInstance, setProcessInstance] = useState(null); - const [tasks, setTasks] = useState | null>(null); + const [processInstance, setProcessInstance] = + useState(null); + const [tasks, setTasks] = useState(null); const [tasksCallHadError, setTasksCallHadError] = useState(false); const [taskToDisplay, setTaskToDisplay] = useState(null); const [taskDataToDisplay, setTaskDataToDisplay] = useState(''); @@ -80,8 +91,13 @@ export default function ProcessInstanceShow() { const processTaskFailure = () => { setTasksCallHadError(true); }; + let queryParams = ''; + const processIdentifier = searchParams.get('process_identifier'); + if (processIdentifier) { + queryParams = `?process_identifier=${processIdentifier}`; + } HttpService.makeCallToBackend({ - path: `/process-instances/${modifiedProcessModelId}/${params.process_instance_id}`, + path: `/process-instances/${modifiedProcessModelId}/${params.process_instance_id}${queryParams}`, successCallback: setProcessInstance, }); let taskParams = '?all_tasks=true'; @@ -98,7 +114,14 @@ export default function ProcessInstanceShow() { setTasksCallHadError(true); } } - }, [params, modifiedProcessModelId, permissionsLoaded, ability, targetUris]); + }, [ + params, + modifiedProcessModelId, + permissionsLoaded, + ability, + targetUris, + searchParams, + ]); const deleteProcessInstance = () => { HttpService.makeCallToBackend({ @@ -140,12 +163,12 @@ export default function ProcessInstanceShow() { const getTaskIds = () => { const taskIds = { completed: [], readyOrWaiting: [] }; if (tasks) { - tasks.forEach(function getUserTasksElement(task: any) { + tasks.forEach(function getUserTasksElement(task: ProcessInstanceTask) { if (task.state === 'COMPLETED') { - (taskIds.completed as any).push(task.name); + (taskIds.completed as any).push(task); } if (task.state === 'READY' || task.state === 'WAITING') { - (taskIds.readyOrWaiting as any).push(task.name); + (taskIds.readyOrWaiting as any).push(task); } }); } @@ -175,15 +198,18 @@ export default function ProcessInstanceShow() { label: any, distance: number ) => { + const processIdentifier = searchParams.get('process_identifier'); + let queryParams = ''; + if (processIdentifier) { + queryParams = `?process_identifier=${processIdentifier}`; + } return ( {label} @@ -364,10 +390,15 @@ export default function ProcessInstanceShow() { } }; - const handleClickedDiagramTask = (shapeElement: any) => { + const handleClickedDiagramTask = ( + shapeElement: any, + bpmnRootElement: any + ) => { if (tasks) { const matchingTask: any = tasks.find( - (task: any) => task.name === shapeElement.id + (task: any) => + task.name === shapeElement.id && + task.process_identifier === bpmnRootElement.id ); if (matchingTask) { setTaskToDisplay(matchingTask); @@ -471,19 +502,28 @@ export default function ProcessInstanceShow() { ); } + if (task.type === 'Call Activity') { + buttons.push( + + View Call Activity Diagram + + ); + } + if (canEditTaskData(task)) { if (editingTaskData) { buttons.push( - ); buttons.push(