From 2624ff9d981cea72834e542e85b0981f1fa72609 Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 3 May 2023 10:17:31 -0400 Subject: [PATCH 1/9] updated column names for system report filters --- .../process_instance_report_service.py | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py index 91f359384..c9617ce65 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py @@ -53,15 +53,15 @@ class ProcessInstanceReportService: } system_report_completed_instances_initiated_by_me: ReportMetadata = { "columns": [ - {"Header": "id", "accessor": "id", "filterable": False}, + {"Header": "Id", "accessor": "id", "filterable": False}, { - "Header": "process_model_display_name", + "Header": "Process", "accessor": "process_model_display_name", "filterable": False, }, - {"Header": "start_in_seconds", "accessor": "start_in_seconds", "filterable": False}, - {"Header": "end_in_seconds", "accessor": "end_in_seconds", "filterable": False}, - {"Header": "status", "accessor": "status", "filterable": False}, + {"Header": "Start Time", "accessor": "start_in_seconds", "filterable": False}, + {"Header": "End Time", "accessor": "end_in_seconds", "filterable": False}, + {"Header": "Status", "accessor": "status", "filterable": False}, ], "filter_by": [ {"field_name": "initiated_by_me", "field_value": True, "operator": "equals"}, @@ -86,9 +86,9 @@ class ProcessInstanceReportService: } system_report_in_progress_instances_initiated_by_me: ReportMetadata = { "columns": [ - {"Header": "id", "accessor": "id", "filterable": False}, + {"Header": "Id", "accessor": "id", "filterable": False}, { - "Header": "process_model_display_name", + "Header": "Process", "accessor": "process_model_display_name", "filterable": False, }, @@ -111,9 +111,9 @@ class ProcessInstanceReportService: } system_report_in_progress_instances_with_tasks_for_me: ReportMetadata = { "columns": [ - {"Header": "id", "accessor": "id", "filterable": False}, + {"Header": "Id", "accessor": "id", "filterable": False}, { - "Header": "process_model_display_name", + "Header": "Process", "accessor": "process_model_display_name", "filterable": False, }, @@ -135,9 +135,9 @@ class ProcessInstanceReportService: } system_report_in_progress_instances_with_tasks: ReportMetadata = { "columns": [ - {"Header": "id", "accessor": "id", "filterable": False}, + {"Header": "Id", "accessor": "id", "filterable": False}, { - "Header": "process_model_display_name", + "Header": "Process", "accessor": "process_model_display_name", "filterable": False, }, From da8206f9f9c662a7b3a95a024d8372aa779e4238 Mon Sep 17 00:00:00 2001 From: burnettk Date: Wed, 3 May 2023 10:49:32 -0400 Subject: [PATCH 2/9] ignore issue for which ticket has been filed --- spiffworkflow-backend/.snyk | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 spiffworkflow-backend/.snyk diff --git a/spiffworkflow-backend/.snyk b/spiffworkflow-backend/.snyk new file mode 100644 index 000000000..680689106 --- /dev/null +++ b/spiffworkflow-backend/.snyk @@ -0,0 +1,10 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.25.0 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + SNYK-PYTHON-FLASK-5490129: + - '*': + reason: Filed ticket to upgrade flask + expires: 2024-06-02T14:48:14.372Z + created: 2023-05-03T14:48:14.379Z +patch: {} From cd5c4f26f0ccf5644d17aad121b49b7bfe9c6110 Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 3 May 2023 10:52:39 -0400 Subject: [PATCH 3/9] cleaned up using system filters with user_group_identifier so the query no longer raises w/ burnettk --- .../spiffworkflow_backend/config/__init__.py | 12 ++-- .../models/process_instance.py | 6 +- .../services/process_instance_processor.py | 12 ++-- .../process_instance_report_service.py | 20 +++++- .../test_process_instance_report_service.py | 63 ++++++++++++++++++- 5 files changed, 93 insertions(+), 20 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/config/__init__.py b/spiffworkflow-backend/src/spiffworkflow_backend/config/__init__.py index eaf67f6c9..7711c36f9 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/config/__init__.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/config/__init__.py @@ -18,13 +18,13 @@ def setup_database_uri(app: Flask) -> None: if app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_URI") is None: database_name = f"spiffworkflow_backend_{app.config['ENV_IDENTIFIER']}" if app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_TYPE") == "sqlite": - app.config[ - "SQLALCHEMY_DATABASE_URI" - ] = f"sqlite:///{app.instance_path}/db_{app.config['ENV_IDENTIFIER']}.sqlite3" + app.config["SQLALCHEMY_DATABASE_URI"] = ( + f"sqlite:///{app.instance_path}/db_{app.config['ENV_IDENTIFIER']}.sqlite3" + ) elif app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_TYPE") == "postgres": - app.config[ - "SQLALCHEMY_DATABASE_URI" - ] = f"postgresql://spiffworkflow_backend:spiffworkflow_backend@localhost:5432/{database_name}" + app.config["SQLALCHEMY_DATABASE_URI"] = ( + f"postgresql://spiffworkflow_backend:spiffworkflow_backend@localhost:5432/{database_name}" + ) else: # use pswd to trick flake8 with hardcoded passwords db_pswd = app.config.get("SPIFFWORKFLOW_BACKEND_DATABASE_PASSWORD") diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py index 303532af5..b3ab709df 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/process_instance.py @@ -129,9 +129,9 @@ class ProcessInstanceModel(SpiffworkflowBaseDBModel): def serialized_with_metadata(self) -> dict[str, Any]: process_instance_attributes = self.serialized process_instance_attributes["process_metadata"] = self.process_metadata - process_instance_attributes[ - "process_model_with_diagram_identifier" - ] = self.process_model_with_diagram_identifier + process_instance_attributes["process_model_with_diagram_identifier"] = ( + self.process_model_with_diagram_identifier + ) return process_instance_attributes @property 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 2ff469b3f..39d37c2c7 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -423,9 +423,9 @@ class ProcessInstanceProcessor: tld.process_instance_id = process_instance_model.id # 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 = f"{process_instance_model.process_model_identifier}" + current_app.config["THREAD_LOCAL_DATA"].process_model_identifier = ( + f"{process_instance_model.process_model_identifier}" + ) self.process_instance_model = process_instance_model self.process_model_service = ProcessModelService() @@ -585,9 +585,9 @@ class ProcessInstanceProcessor: bpmn_subprocess_definition.bpmn_identifier ] = bpmn_process_definition_dict spiff_bpmn_process_dict["subprocess_specs"][bpmn_subprocess_definition.bpmn_identifier]["task_specs"] = {} - bpmn_subprocess_definition_bpmn_identifiers[ - bpmn_subprocess_definition.id - ] = bpmn_subprocess_definition.bpmn_identifier + bpmn_subprocess_definition_bpmn_identifiers[bpmn_subprocess_definition.id] = ( + bpmn_subprocess_definition.bpmn_identifier + ) task_definitions = TaskDefinitionModel.query.filter( TaskDefinitionModel.bpmn_process_definition_id.in_( # type: ignore diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py index c9617ce65..fc7b9d434 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py @@ -34,7 +34,11 @@ from spiffworkflow_backend.services.process_model_service import ProcessModelSer class ProcessInstanceReportNotFoundError(Exception): - """ProcessInstanceReportNotFoundError.""" + pass + + +class ProcessInstanceReportMetadataInvalidError(Exception): + pass class ProcessInstanceReportService: @@ -441,6 +445,15 @@ class ProcessInstanceReportService: ) ) + if with_tasks_completed_by_me is True and with_tasks_i_can_complete is True: + raise ProcessInstanceReportMetadataInvalidError( + "Cannot set both 'with_tasks_completed_by_me' and 'with_tasks_i_can_complete' to true. You must choose" + " one." + ) + + # ensure we only join with HumanTaskModel once + human_task_already_joined = False + if with_tasks_completed_by_me is True: process_instance_query = process_instance_query.filter( ProcessInstanceModel.process_initiator_id != user.id @@ -452,6 +465,7 @@ class ProcessInstanceReportService: HumanTaskModel.completed_by_user_id == user.id, ), ) + human_task_already_joined = True # this excludes some tasks you can complete, because that's the way the requirements were described. # if it's assigned to one of your groups, it does not get returned by this query. @@ -470,13 +484,15 @@ class ProcessInstanceReportService: HumanTaskUserModel, and_(HumanTaskUserModel.human_task_id == HumanTaskModel.id, HumanTaskUserModel.user_id == user.id), ) + human_task_already_joined = True if user_group_identifier is not None: group_model_join_conditions = [GroupModel.id == HumanTaskModel.lane_assignment_id] if user_group_identifier: group_model_join_conditions.append(GroupModel.identifier == user_group_identifier) - process_instance_query = process_instance_query.join(HumanTaskModel) + if human_task_already_joined is False: + process_instance_query = process_instance_query.join(HumanTaskModel) if process_status is not None: non_active_statuses = [ s for s in process_status.split(",") if s not in ProcessInstanceModel.active_statuses() diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_report_service.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_report_service.py index 95eab41e8..9c36de92b 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_report_service.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_report_service.py @@ -1,4 +1,5 @@ """Test_process_instance_report_service.""" +import pytest from flask import Flask from flask.testing import FlaskClient from tests.spiffworkflow_backend.helpers.base_test import BaseTest @@ -7,9 +8,9 @@ from tests.spiffworkflow_backend.helpers.test_data import load_test_spec from spiffworkflow_backend.models.db import db from spiffworkflow_backend.models.group import GroupModel from spiffworkflow_backend.models.human_task import HumanTaskModel -from spiffworkflow_backend.services.process_instance_report_service import ( - ProcessInstanceReportService, -) +from spiffworkflow_backend.models.process_instance_report import ReportMetadata +from spiffworkflow_backend.services.process_instance_report_service import ProcessInstanceReportMetadataInvalidError +from spiffworkflow_backend.services.process_instance_report_service import ProcessInstanceReportService from spiffworkflow_backend.services.user_service import UserService @@ -52,6 +53,62 @@ class TestProcessInstanceReportService(BaseTest): assert response_json["results"][0]["status"] == "complete" assert response_json["results"][1]["status"] == "complete" + def test_raises_if_filtering_with_both_task_i_can_complete_and_tasks_completed_by_me( + self, + app: Flask, + client: FlaskClient, + with_db_and_bpmn_file_cleanup: None, + ) -> None: + user_one = self.find_or_create_user(username="user_one") + report_metadata: ReportMetadata = { + "columns": [], + "filter_by": [ + {"field_name": "with_tasks_i_can_complete", "field_value": True, "operator": "equals"}, + {"field_name": "with_tasks_completed_by_me", "field_value": True, "operator": "equals"}, + ], + "order_by": [], + } + with pytest.raises(ProcessInstanceReportMetadataInvalidError): + ProcessInstanceReportService.run_process_instance_report( + report_metadata=report_metadata, + user=user_one, + ) + + def test_with_group_identifier_does_not_conflict_with_system_filters( + self, + app: Flask, + client: FlaskClient, + with_db_and_bpmn_file_cleanup: None, + ) -> None: + user_one = self.find_or_create_user(username="user_one") + report_metadata: ReportMetadata = { + "columns": [], + "filter_by": [ + {"field_name": "with_tasks_i_can_complete", "field_value": True, "operator": "equals"}, + {"field_name": "user_group_identifier", "field_value": "group_one", "operator": "equals"}, + ], + "order_by": [], + } + result = ProcessInstanceReportService.run_process_instance_report( + report_metadata=report_metadata, + user=user_one, + ) + assert result is not None + + report_metadata = { + "columns": [], + "filter_by": [ + {"field_name": "with_tasks_completed_by_me", "field_value": True, "operator": "equals"}, + {"field_name": "user_group_identifier", "field_value": "group_one", "operator": "equals"}, + ], + "order_by": [], + } + result = ProcessInstanceReportService.run_process_instance_report( + report_metadata=report_metadata, + user=user_one, + ) + assert result is not None + def test_can_filter_by_completed_instances_with_tasks_completed_by_me( self, app: Flask, From 4832256fc502f7f154f6b025885183d1e0c56002 Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 3 May 2023 11:16:13 -0400 Subject: [PATCH 4/9] removed the format header method from frontend so we only use the columns that come from the metadata now w/ burnettk --- .../process_instance_report_service.py | 2 +- .../components/ProcessInstanceListTable.tsx | 45 ++++++++----------- spiffworkflow-frontend/src/interfaces.ts | 6 +++ 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py index fc7b9d434..d64061170 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py @@ -100,7 +100,7 @@ class ProcessInstanceReportService: {"Header": "Waiting For", "accessor": "waiting_for", "filterable": False}, {"Header": "Started", "accessor": "start_in_seconds", "filterable": False}, {"Header": "Last Updated", "accessor": "task_updated_at_in_seconds", "filterable": False}, - {"Header": "status", "accessor": "status", "filterable": False}, + {"Header": "Status", "accessor": "status", "filterable": False}, ], "filter_by": [ {"field_name": "initiated_by_me", "field_value": True, "operator": "equals"}, diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index 464076425..ef213c92d 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -138,7 +138,9 @@ export default function ProcessInstanceListTable({ ); const canSearchUsers: boolean = ability.can('GET', targetUris.userSearch); - const [processInstances, setProcessInstances] = useState([]); + const [processInstances, setProcessInstances] = useState( + [] + ); const [reportMetadata, setReportMetadata] = useState(); const [pagination, setPagination] = useState(null); @@ -1509,7 +1511,7 @@ export default function ProcessInstanceListTable({ return value; }; - const formattedColumn = (row: any, column: any) => { + const formattedColumn = (row: ProcessInstance, column: ReportColumn) => { const reportColumnFormatters: Record = { id: formatProcessInstanceId, process_model_identifier: formatProcessModelIdentifier, @@ -1520,40 +1522,41 @@ export default function ProcessInstanceListTable({ updated_at_in_seconds: formatSecondsForDisplay, task_updated_at_in_seconds: formatSecondsForDisplay, }; + const columnAccessor = column.accessor as keyof ProcessInstance; const formatter = - reportColumnFormatters[column.accessor] ?? defaultFormatter; - const value = row[column.accessor]; + reportColumnFormatters[columnAccessor] ?? defaultFormatter; + const value = row[columnAccessor]; - if (column.accessor === 'status') { + if (columnAccessor === 'status') { return ( {formatter(row, value)} ); } - if (column.accessor === 'process_model_display_name') { + if (columnAccessor === 'process_model_display_name') { return {formatter(row, value)} ; } - if (column.accessor === 'waiting_for') { + if (columnAccessor === 'waiting_for') { return {getWaitingForTableCellComponent(row)} ; } - if (column.accessor === 'updated_at_in_seconds') { + if (columnAccessor === 'updated_at_in_seconds') { return ( ); } - if (column.accessor === 'task_updated_at_in_seconds') { + if (columnAccessor === 'task_updated_at_in_seconds') { return ( ); } return ( // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions - + {formatter(row, value)} ); @@ -1561,27 +1564,15 @@ export default function ProcessInstanceListTable({ // eslint-disable-next-line sonarjs/cognitive-complexity const buildTable = () => { - const headerLabels: Record = { - id: 'Id', - process_model_identifier: 'Process', - process_model_display_name: 'Process', - start_in_seconds: 'Start Time', - end_in_seconds: 'End Time', - status: 'Status', - process_initiator_username: 'Started By', - }; - const getHeaderLabel = (header: string) => { - return headerLabels[header] ?? header; - }; - const headers = reportColumns().map((column: any) => { - return getHeaderLabel((column as any).Header); + const headers = reportColumns().map((column: ReportColumn) => { + return column.Header; }); if (showActionsColumn) { headers.push('Action'); } - const rows = processInstances.map((row: any) => { - const currentRow = reportColumns().map((column: any) => { + const rows = processInstances.map((row: ProcessInstance) => { + const currentRow = reportColumns().map((column: ReportColumn) => { return formattedColumn(row, column); }); if (showActionsColumn) { diff --git a/spiffworkflow-frontend/src/interfaces.ts b/spiffworkflow-frontend/src/interfaces.ts index 680d2ee5a..37899b3cb 100644 --- a/spiffworkflow-frontend/src/interfaces.ts +++ b/spiffworkflow-frontend/src/interfaces.ts @@ -143,6 +143,12 @@ export interface ProcessInstance { bpmn_version_control_type: string; process_metadata?: ProcessInstanceMetadata[]; process_model_with_diagram_identifier?: string; + + // from tasks + potential_owner_usernames?: string; + task_id?: string; + task_updated_at_in_seconds?: number; + waiting_for?: string; } export interface MessageCorrelationProperties { From 0cc15d0da61a14791e707c69cf3bf8650233f037 Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 3 May 2023 11:42:42 -0400 Subject: [PATCH 5/9] updated system report names to match more closely the text used on the homepage w/ burnettk --- .../process_instance_report_service.py | 22 +++++++++---------- .../components/ProcessInstanceListTable.tsx | 16 +++++++++----- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py index d64061170..57af17eae 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_report_service.py @@ -76,7 +76,7 @@ class ProcessInstanceReportService: system_report_completed_instances_with_tasks_completed_by_me: ReportMetadata = { "columns": cls.builtin_column_options(), "filter_by": [ - {"field_name": "with_tasks_completed_by_me", "field_value": True, "operator": "equals"}, + {"field_name": "instances_with_tasks_completed_by_me", "field_value": True, "operator": "equals"}, {"field_name": "process_status", "field_value": terminal_status_values, "operator": "equals"}, ], "order_by": ["-start_in_seconds", "-id"], @@ -127,7 +127,7 @@ class ProcessInstanceReportService: {"Header": "Last Updated", "accessor": "task_updated_at_in_seconds", "filterable": False}, ], "filter_by": [ - {"field_name": "with_tasks_i_can_complete", "field_value": True, "operator": "equals"}, + {"field_name": "instances_with_tasks_waiting_for_me", "field_value": True, "operator": "equals"}, {"field_name": "process_status", "field_value": active_status_values, "operator": "equals"}, { "field_name": "with_oldest_open_task", @@ -418,17 +418,17 @@ class ProcessInstanceReportService: process_initiator_id = initiator.id process_instance_query = process_instance_query.filter_by(process_initiator_id=process_initiator_id) - with_tasks_completed_by_me = cls.get_filter_value(filters, "with_tasks_completed_by_me") - with_tasks_i_can_complete = cls.get_filter_value(filters, "with_tasks_i_can_complete") + instances_with_tasks_completed_by_me = cls.get_filter_value(filters, "instances_with_tasks_completed_by_me") + instances_with_tasks_waiting_for_me = cls.get_filter_value(filters, "instances_with_tasks_waiting_for_me") user_group_identifier = cls.get_filter_value(filters, "user_group_identifier") # builtin only - for the for-me paths with_relation_to_me = cls.get_filter_value(filters, "with_relation_to_me") if ( - not with_tasks_completed_by_me + not instances_with_tasks_completed_by_me and not user_group_identifier - and not with_tasks_i_can_complete + and not instances_with_tasks_waiting_for_me and with_relation_to_me is True ): process_instance_query = process_instance_query.outerjoin(HumanTaskModel).outerjoin( @@ -445,16 +445,16 @@ class ProcessInstanceReportService: ) ) - if with_tasks_completed_by_me is True and with_tasks_i_can_complete is True: + if instances_with_tasks_completed_by_me is True and instances_with_tasks_waiting_for_me is True: raise ProcessInstanceReportMetadataInvalidError( - "Cannot set both 'with_tasks_completed_by_me' and 'with_tasks_i_can_complete' to true. You must choose" - " one." + "Cannot set both 'instances_with_tasks_completed_by_me' and 'instances_with_tasks_waiting_for_me' to" + " true. You must choose one." ) # ensure we only join with HumanTaskModel once human_task_already_joined = False - if with_tasks_completed_by_me is True: + if instances_with_tasks_completed_by_me is True: process_instance_query = process_instance_query.filter( ProcessInstanceModel.process_initiator_id != user.id ) @@ -469,7 +469,7 @@ class ProcessInstanceReportService: # this excludes some tasks you can complete, because that's the way the requirements were described. # if it's assigned to one of your groups, it does not get returned by this query. - if with_tasks_i_can_complete is True: + if instances_with_tasks_waiting_for_me is True: process_instance_query = process_instance_query.filter( ProcessInstanceModel.process_initiator_id != user.id ) diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index ef213c92d..775df8932 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -217,7 +217,10 @@ export default function ProcessInstanceListTable({ ); const [userGroups, setUserGroups] = useState([]); const systemReportOptions: string[] = useMemo(() => { - return ['with_tasks_i_can_complete', 'with_tasks_completed_by_me']; + return [ + 'instances_with_tasks_waiting_for_me', + 'instances_with_tasks_completed_by_me', + ]; }, []); const [reportHash, setReportHash] = useState(null); @@ -1215,9 +1218,9 @@ export default function ProcessInstanceListTable({ item} + itemToString={(item: any) => titleizeString(item)} selectedItem={systemReport} onChange={(value: any) => { setSystemReport(value.selectedItem); @@ -1228,7 +1231,7 @@ export default function ProcessInstanceListTable({ item} selectedItem={selectedUserGroup} @@ -1264,6 +1267,7 @@ export default function ProcessInstanceListTable({ onRequestSubmit={handleAdvancedOptionsClose} onRequestClose={handleAdvancedOptionsClose} hasScrollingContent + size="lg" > {formElements} @@ -1338,7 +1342,7 @@ export default function ProcessInstanceListTable({ return null; }} placeholder="Start typing username" - titleText="Started By" + titleText="Started by" selectedItem={processInitiatorSelection} /> ); @@ -1347,7 +1351,7 @@ export default function ProcessInstanceListTable({ { From ae035a5f58c40b7d4eb16c814bf6803cf93c2bfe Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 3 May 2023 11:45:35 -0400 Subject: [PATCH 6/9] fixed broken report tests w/ burnettk --- .../unit/test_process_instance_report_service.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_report_service.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_report_service.py index 9c36de92b..a4fd46d27 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_report_service.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_report_service.py @@ -63,8 +63,8 @@ class TestProcessInstanceReportService(BaseTest): report_metadata: ReportMetadata = { "columns": [], "filter_by": [ - {"field_name": "with_tasks_i_can_complete", "field_value": True, "operator": "equals"}, - {"field_name": "with_tasks_completed_by_me", "field_value": True, "operator": "equals"}, + {"field_name": "instances_with_tasks_waiting_for_me", "field_value": True, "operator": "equals"}, + {"field_name": "instances_with_tasks_completed_by_me", "field_value": True, "operator": "equals"}, ], "order_by": [], } @@ -84,7 +84,7 @@ class TestProcessInstanceReportService(BaseTest): report_metadata: ReportMetadata = { "columns": [], "filter_by": [ - {"field_name": "with_tasks_i_can_complete", "field_value": True, "operator": "equals"}, + {"field_name": "instances_with_tasks_waiting_for_me", "field_value": True, "operator": "equals"}, {"field_name": "user_group_identifier", "field_value": "group_one", "operator": "equals"}, ], "order_by": [], @@ -98,7 +98,7 @@ class TestProcessInstanceReportService(BaseTest): report_metadata = { "columns": [], "filter_by": [ - {"field_name": "with_tasks_completed_by_me", "field_value": True, "operator": "equals"}, + {"field_name": "instances_with_tasks_completed_by_me", "field_value": True, "operator": "equals"}, {"field_name": "user_group_identifier", "field_value": "group_one", "operator": "equals"}, ], "order_by": [], From 387eb8b9fee70715f487c8968f22811940af00f3 Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 3 May 2023 13:19:33 -0400 Subject: [PATCH 7/9] clear advanced filter options as well --- .../src/components/ProcessInstanceListTable.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index 775df8932..84c7bc96c 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -851,6 +851,9 @@ export default function ProcessInstanceListTable({ setEndToDate(''); setEndToTime(''); setProcessInitiatorSelection(null); + setWithOldestOpenTask(false); + setSystemReport(null); + setSelectedUserGroup(null); setRequiresRefilter(true); if (reportMetadata) { reportMetadata.filter_by = []; From 245e34b0bb1dc905022d2fb501622d2934ed6433 Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 3 May 2023 15:12:41 -0400 Subject: [PATCH 8/9] added script to demonstrate how to use message start events w/ burnettk --- .../bin/run_message_start_event_with_api | 43 +++++++++++++++++++ .../routes/messages_controller.py | 1 - 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100755 spiffworkflow-backend/bin/run_message_start_event_with_api diff --git a/spiffworkflow-backend/bin/run_message_start_event_with_api b/spiffworkflow-backend/bin/run_message_start_event_with_api new file mode 100755 index 000000000..449cfb91e --- /dev/null +++ b/spiffworkflow-backend/bin/run_message_start_event_with_api @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +function error_handler() { + >&2 echo "Exited with BAD EXIT CODE '${2}' in ${0} script at line: ${1}." + exit "$2" +} +trap 'error_handler ${LINENO} $?' ERR +set -o errtrace -o errexit -o nounset -o pipefail + +script_dir="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" + +if [[ -z "${KEYCLOAK_BASE_URL:-}" ]]; then + # export KEYCLOAK_BASE_URL=https://keycloak.dev.spiffworkflow.org + export KEYCLOAK_BASE_URL=http://localhost:7002 +fi +if [[ -z "${BACKEND_BASE_URL:-}" ]]; then + # export BACKEND_BASE_URL=https://api.dev.spiffworkflow.org + export BACKEND_BASE_URL=http://localhost:7000 +fi + +message_identifier="${1:-start_test}" +username="${2:-admin}" +password="${3:-admin}" +realm_name="${4:-spiffworkflow}" +if [[ -z "${message_identifier}" ]]; then + >&2 echo "usage: $(basename "$0") [message_identifier] [username: OPTONAL] [password: OPTONAL] [realm_name: OPTONAL]" + exit 1 +fi + +function check_result_for_error() { + local result="$1" + error_code=$(jq '.error_code' <<<"$result") + if [[ -n "$error_code" && "$error_code" != "null" ]]; then + >&2 echo "ERROR: Failed to run process instance. Received error: $result" + exit 1 + fi +} + +access_token=$("${script_dir}/get_token" "$username" "$password" "$realm_name") +curl --silent -X POST "${BACKEND_BASE_URL}/v1.0/login_with_access_token?access_token=${access_token}" -H "Authorization: Bearer $access_token" >/dev/null +result=$(curl --silent -X POST "${BACKEND_BASE_URL}/v1.0/messages/${message_identifier}" -H "Authorization: Bearer $access_token" -d '{"payload": {"email": "HEY@example.com"}}' -H 'Content-type: application/json') +check_result_for_error "$result" +echo "$result" diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/routes/messages_controller.py b/spiffworkflow-backend/src/spiffworkflow_backend/routes/messages_controller.py index f7db74db3..62d3779c7 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/messages_controller.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/messages_controller.py @@ -69,7 +69,6 @@ def message_send( message_name: str, body: Dict[str, Any], ) -> flask.wrappers.Response: - """Message_start.""" if "payload" not in body: raise ( ApiError( From 34d78cff17a86e8ebdf73ef41d8227e12f9eee91 Mon Sep 17 00:00:00 2001 From: jasquat Date: Wed, 3 May 2023 15:13:06 -0400 Subject: [PATCH 9/9] removed commented out variables w/ burnettk --- spiffworkflow-backend/bin/run_message_start_event_with_api | 2 -- 1 file changed, 2 deletions(-) diff --git a/spiffworkflow-backend/bin/run_message_start_event_with_api b/spiffworkflow-backend/bin/run_message_start_event_with_api index 449cfb91e..2e5c7064e 100755 --- a/spiffworkflow-backend/bin/run_message_start_event_with_api +++ b/spiffworkflow-backend/bin/run_message_start_event_with_api @@ -10,11 +10,9 @@ set -o errtrace -o errexit -o nounset -o pipefail script_dir="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" if [[ -z "${KEYCLOAK_BASE_URL:-}" ]]; then - # export KEYCLOAK_BASE_URL=https://keycloak.dev.spiffworkflow.org export KEYCLOAK_BASE_URL=http://localhost:7002 fi if [[ -z "${BACKEND_BASE_URL:-}" ]]; then - # export BACKEND_BASE_URL=https://api.dev.spiffworkflow.org export BACKEND_BASE_URL=http://localhost:7000 fi