From 189dbc27123bc9df8a88dbad8591df15cb53039a Mon Sep 17 00:00:00 2001 From: jasquat Date: Fri, 13 Jan 2023 10:43:25 -0500 Subject: [PATCH 1/2] stop at call activity as well when getting calling subprocesses by child id w/ burnettk --- .../routes/process_instances_controller.py | 8 +-- .../services/process_instance_processor.py | 52 ++++++++++++++++--- .../src/routes/ProcessInstanceShow.tsx | 28 ++++++---- 3 files changed, 67 insertions(+), 21 deletions(-) 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 f99ce0b0..0a218e0e 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py @@ -556,9 +556,11 @@ 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() - processor.get_highest_level_subprocesses_by_child_task_ids( - subprocesses_by_child_task_ids + subprocesses_by_child_task_ids, task_typename_by_task_id = ( + processor.get_subprocesses_by_child_task_ids() + ) + processor.get_highest_level_calling_subprocesses_by_child_task_ids( + subprocesses_by_child_task_ids, task_typename_by_task_id ) tasks = [] 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 3631f0b7..86a84be1 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -625,7 +625,25 @@ class ProcessInstanceProcessor: db.session.add(pim) db.session.commit() - def get_subprocesses_by_child_task_ids(self) -> dict: + def get_all_task_specs(self) -> dict[str, dict]: + """This looks both at top level task_specs and subprocess_specs in the serialized data. + + It returns a dict of all task specs based on the task name like it is in the serialized form. + + NOTE: this may not fully work for tasks that are NOT call activities since their task_name may no be unique + but in our current use case we only care about the call activities here. + """ + serialized_data = json.loads(self.serialize()) + spiff_task_json = serialized_data["spec"]["task_specs"] or {} + if "subprocess_specs" in serialized_data: + for _subprocess_task_name, subprocess_details in serialized_data[ + "subprocess_specs" + ].items(): + if "task_specs" in subprocess_details: + spiff_task_json = spiff_task_json | subprocess_details["task_specs"] + return spiff_task_json + + def get_subprocesses_by_child_task_ids(self) -> Tuple[dict, 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 @@ -641,27 +659,45 @@ class ProcessInstanceProcessor: call activities like subprocesses in terms of the serialization. """ bpmn_json = json.loads(self.serialize()) + spiff_task_json = self.get_all_task_specs() + subprocesses_by_child_task_ids = {} + task_typename_by_task_id = {} if "subprocesses" in bpmn_json: for subprocess_id, subprocess_details in bpmn_json["subprocesses"].items(): - for task_id in subprocess_details["tasks"]: + for task_id, task_details in subprocess_details["tasks"].items(): subprocesses_by_child_task_ids[task_id] = subprocess_id - return subprocesses_by_child_task_ids + task_name = task_details["task_spec"] + if task_name in spiff_task_json: + task_typename_by_task_id[task_id] = spiff_task_json[task_name][ + "typename" + ] + return (subprocesses_by_child_task_ids, task_typename_by_task_id) - def get_highest_level_subprocesses_by_child_task_ids( - self, subprocesses_by_child_task_ids: dict + def get_highest_level_calling_subprocesses_by_child_task_ids( + self, subprocesses_by_child_task_ids: dict, task_typename_by_task_id: dict ) -> dict: """Ensure task ids point to the top level subprocess id. - This is done by checking if a subprocess is also a task until the subprocess is no longer a task. + This is done by checking if a subprocess is also a task until the subprocess is no longer a task or a Call Activity. """ for task_id, subprocess_id in subprocesses_by_child_task_ids.items(): if subprocess_id in subprocesses_by_child_task_ids: + current_subprocess_id_for_task = subprocesses_by_child_task_ids[task_id] + if current_subprocess_id_for_task in task_typename_by_task_id: + # a call activity is like the top-level subprocess since it is the calling subprocess + # according to spiff and the top-level calling subprocess is really what we care about + if ( + task_typename_by_task_id[current_subprocess_id_for_task] + == "CallActivity" + ): + continue + 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 + self.get_highest_level_calling_subprocesses_by_child_task_ids( + subprocesses_by_child_task_ids, task_typename_by_task_id ) return subprocesses_by_child_task_ids diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index a812248a..6e73463e 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -200,19 +200,21 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { const getTaskIds = () => { const taskIds = { completed: [], readyOrWaiting: [] }; if (tasks) { + const callingSubprocessId = searchParams.get('call_activity_task_id'); tasks.forEach(function getUserTasksElement(task: ProcessInstanceTask) { - const callingSubprocessId = searchParams.get('call_activity_task_id'); if ( - !callingSubprocessId || - callingSubprocessId === task.calling_subprocess_task_id + callingSubprocessId && + callingSubprocessId !== task.calling_subprocess_task_id ) { - if (task.state === 'COMPLETED') { - (taskIds.completed as any).push(task); - } - if (task.state === 'READY' || task.state === 'WAITING') { - (taskIds.readyOrWaiting as any).push(task); - } + return null; } + if (task.state === 'COMPLETED') { + (taskIds.completed as any).push(task); + } + if (task.state === 'READY' || task.state === 'WAITING') { + (taskIds.readyOrWaiting as any).push(task); + } + return null; }); } return taskIds; @@ -904,6 +906,10 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { const taskToUse: any = { ...taskToDisplay, data: taskDataToDisplay }; const candidateEvents: any = getEvents(taskToUse); if (taskToDisplay) { + let taskTitleText = taskToUse.id; + if (taskToUse.title) { + taskTitleText += ` (${taskToUse.title})`; + } return ( - {taskToUse.name} ({taskToUse.type}): {taskToUse.state} + {taskToUse.name} ( + {taskToUse.type} + ): {taskToUse.state} {taskDisplayButtons(taskToUse)} {selectingEvent From a2bb41301a9ade0ec95e7788f5b2b8989079bd7d Mon Sep 17 00:00:00 2001 From: jasquat Date: Fri, 13 Jan 2023 11:29:45 -0500 Subject: [PATCH 2/2] added tabs to find by id page and install pre commit libraries if they fail to run help w/ burnettk --- bin/run_pyl | 11 +++- .../components/ProcessInstanceListTabs.tsx | 63 +++++++++++++++++++ .../src/routes/ProcessInstanceFindById.tsx | 17 +++-- .../src/routes/ProcessInstanceList.tsx | 54 +--------------- 4 files changed, 86 insertions(+), 59 deletions(-) create mode 100644 spiffworkflow-frontend/src/components/ProcessInstanceListTabs.tsx diff --git a/bin/run_pyl b/bin/run_pyl index 64446662..bceba187 100755 --- a/bin/run_pyl +++ b/bin/run_pyl @@ -38,12 +38,19 @@ function run_fix_docstrings() { } function run_autoflake() { - if ! command -v autoflake8 >/dev/null ; then + # checking command -v autoflake8 is not good enough, since the asdf shim may be installed, which will make command -v succeed, + # but autoflake8 may not have been pip installed inside the correct version of python. + if ! autoflake8 --help >/dev/null ; then pip install autoflake8 asdf reshim python fi - if ! command -v autopep8 >/dev/null ; then + if ! autoflake --help >/dev/null ; then + pip install autoflake + asdf reshim python + fi + + if ! autopep8 --help >/dev/null ; then pip install autopep8 asdf reshim python fi diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTabs.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTabs.tsx new file mode 100644 index 00000000..8da9d8c1 --- /dev/null +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTabs.tsx @@ -0,0 +1,63 @@ +// @ts-ignore +import { Tabs, TabList, Tab } from '@carbon/react'; +import { Can } from '@casl/react'; +import { useNavigate } from 'react-router-dom'; +import { usePermissionFetcher } from '../hooks/PermissionService'; +import { useUriListForPermissions } from '../hooks/UriListForPermissions'; +import { PermissionsToCheck } from '../interfaces'; + +type OwnProps = { + variant: string; +}; + +export default function ProcessInstanceListTabs({ variant }: OwnProps) { + const navigate = useNavigate(); + const { targetUris } = useUriListForPermissions(); + const permissionRequestData: PermissionsToCheck = { + [targetUris.processInstanceListPath]: ['GET'], + }; + const { ability } = usePermissionFetcher(permissionRequestData); + + let selectedTabIndex = 0; + if (variant === 'all') { + selectedTabIndex = 1; + } else if (variant === 'find-by-id') { + selectedTabIndex = 2; + } + + return ( + + + { + navigate('/admin/process-instances/for-me'); + }} + > + For Me + + + { + navigate('/admin/process-instances/all'); + }} + > + All + + + { + navigate('/admin/process-instances/find-by-id'); + }} + > + Find By Id + + + + ); +} diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceFindById.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceFindById.tsx index e55520ef..0c0c1974 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceFindById.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceFindById.tsx @@ -4,6 +4,7 @@ import { useNavigate } from 'react-router-dom'; import { Button, ButtonSet, Form, Stack, TextInput } from '@carbon/react'; import { isInteger, modifyProcessIdentifierForPathParam } from '../helpers'; import HttpService from '../services/HttpService'; +import ProcessInstanceListTabs from '../components/ProcessInstanceListTabs'; import { ProcessInstance } from '../interfaces'; export default function ProcessInstanceFindById() { @@ -69,11 +70,15 @@ export default function ProcessInstanceFindById() { }; return ( -
- - {formElements()} - {formButtons()} - -
+ <> + +
+
+ + {formElements()} + {formButtons()} + +
+ ); } diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceList.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceList.tsx index 33af0c1f..ca69eb7d 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceList.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceList.tsx @@ -1,18 +1,13 @@ -import { useNavigate, useSearchParams } from 'react-router-dom'; +import { useSearchParams } from 'react-router-dom'; import 'react-datepicker/dist/react-datepicker.css'; import 'react-bootstrap-typeahead/css/Typeahead.css'; import 'react-bootstrap-typeahead/css/Typeahead.bs5.css'; -// @ts-ignore -import { Tabs, TabList, Tab } from '@carbon/react'; -import { Can } from '@casl/react'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import ProcessInstanceListTable from '../components/ProcessInstanceListTable'; import { getProcessModelFullIdentifierFromSearchParams } from '../helpers'; -import { useUriListForPermissions } from '../hooks/UriListForPermissions'; -import { PermissionsToCheck } from '../interfaces'; -import { usePermissionFetcher } from '../hooks/PermissionService'; +import ProcessInstanceListTabs from '../components/ProcessInstanceListTabs'; type OwnProps = { variant: string; @@ -20,13 +15,6 @@ type OwnProps = { export default function ProcessInstanceList({ variant }: OwnProps) { const [searchParams] = useSearchParams(); - const navigate = useNavigate(); - - const { targetUris } = useUriListForPermissions(); - const permissionRequestData: PermissionsToCheck = { - [targetUris.processInstanceListPath]: ['GET'], - }; - const { ability } = usePermissionFetcher(permissionRequestData); const processInstanceBreadcrumbElement = () => { const processModelFullIdentifier = @@ -57,45 +45,9 @@ export default function ProcessInstanceList({ variant }: OwnProps) { return

My Process Instances

; }; - let selectedTabIndex = 0; - if (variant === 'all') { - selectedTabIndex = 1; - } return ( <> - - - { - navigate('/admin/process-instances/for-me'); - }} - > - For Me - - - { - navigate('/admin/process-instances/all'); - }} - > - All - - - { - navigate('/admin/process-instances/find-by-id'); - }} - > - Find By Id - - - +
{processInstanceBreadcrumbElement()} {processInstanceTitleElement()}