diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/api.yml b/spiffworkflow-backend/src/spiffworkflow_backend/api.yml index 5be50b8d1..6141a861e 100755 --- a/spiffworkflow-backend/src/spiffworkflow_backend/api.yml +++ b/spiffworkflow-backend/src/spiffworkflow_backend/api.yml @@ -338,9 +338,9 @@ paths: schema: $ref: "#/components/schemas/ProcessModel" - /process-models/{modified_process_model_id}/files: + /process-models/{modified_process_model_identifier}/files: parameters: - - name: modified_process_model_id + - name: modified_process_model_identifier in: path required: true description: The process_model_id, modified to replace slashes (/) @@ -565,33 +565,6 @@ paths: items: $ref: "#/components/schemas/Workflow" - /process-instances/{process_instance_id}/task/{task_id}/update: - parameters: - - name: process_instance_id - in: path - required: true - description: The unique id of the process instance - schema: - type: string - - name: task_id - in: path - required: true - description: The unique id of the task - schema: - type: string - post: - operationId: spiffworkflow_backend.routes.process_api_blueprint.update_task_data - summary: Update the task data for requested instance and task - tags: - - Process Instances - responses: - "200": - description: Task Updated Successfully - content: - application/json: - schema: - $ref: "#/components/schemas/Workflow" - /process-models/{process_group_id}/{process_model_id}/script-unit-tests: parameters: - name: process_group_id @@ -646,15 +619,14 @@ paths: schema: $ref: "#/components/schemas/Workflow" - /process-models/{modified_process_model_id}/process-instances: + /process-instances/{modified_process_model_identifier}: parameters: - - name: modified_process_model_id + - name: modified_process_model_identifier in: path required: true description: The unique id of an existing process model. schema: type: string - # process_instance_create post: operationId: spiffworkflow_backend.routes.process_api_blueprint.process_instance_create summary: Creates an process instance from a process model and returns the instance @@ -668,28 +640,7 @@ paths: schema: $ref: "#/components/schemas/Workflow" - /process-instances/{process_instance_id}: - parameters: - - name: process_instance_id - in: path - required: true - description: The unique id of an existing process instance. - schema: - type: integer - delete: - operationId: spiffworkflow_backend.routes.process_api_blueprint.process_instance_delete - summary: Deletes a single process instance - tags: - - Process Instances - responses: - "200": - description: The process instance was deleted. - content: - application/json: - schema: - $ref: "#/components/schemas/OkTrue" - - /process-models/{modified_process_model_identifier}/process-instances/{process_instance_id}: + /process-instances/{modified_process_model_identifier}/{process_instance_id}: parameters: - name: modified_process_model_identifier in: path @@ -715,6 +666,18 @@ paths: application/json: schema: $ref: "#/components/schemas/Workflow" + delete: + operationId: spiffworkflow_backend.routes.process_api_blueprint.process_instance_delete + summary: Deletes a single process instance + tags: + - Process Instances + responses: + "200": + description: The process instance was deleted. + content: + application/json: + schema: + $ref: "#/components/schemas/OkTrue" /process-instances/{modified_process_model_identifier}/{process_instance_id}/run: parameters: @@ -743,7 +706,7 @@ paths: schema: $ref: "#/components/schemas/Workflow" - /process-instances/{process_instance_id}/terminate: + /process-instances/{modified_process_model_identifier}/{process_instance_id}/terminate: parameters: - name: process_instance_id in: path @@ -764,7 +727,7 @@ paths: schema: $ref: "#/components/schemas/OkTrue" - /process-instances/{process_instance_id}/suspend: + /process-instances/{modified_process_model_identifier}/{process_instance_id}/suspend: parameters: - name: process_instance_id in: path @@ -785,7 +748,7 @@ paths: schema: $ref: "#/components/schemas/OkTrue" - /process-instances/{process_instance_id}/resume: + /process-instances/{modified_process_model_identifier}/{process_instance_id}/resume: parameters: - name: process_instance_id in: path @@ -922,9 +885,9 @@ paths: schema: $ref: "#/components/schemas/OkTrue" - /process-models/{modified_process_model_id}/files/{file_name}: + /process-models/{modified_process_model_identifier}/files/{file_name}: parameters: - - name: modified_process_model_id + - name: modified_process_model_identifier in: path required: true description: The modified process model id @@ -1101,9 +1064,9 @@ paths: items: $ref: "#/components/schemas/Task" - /process-instances/{modified_process_model_id}/{process_instance_id}/tasks: + /task-data/{modified_process_model_identifier}/{process_instance_id}: parameters: - - name: modified_process_model_id + - name: modified_process_model_identifier in: path required: true description: The modified id of an existing process model @@ -1142,11 +1105,44 @@ paths: items: $ref: "#/components/schemas/Task" - /service_tasks: + /task-data/{modified_process_model_identifier}/{process_instance_id}/{task_id}: + parameters: + - name: modified_process_model_identifier + in: path + required: true + description: The modified id of an existing process model + schema: + type: string + - name: process_instance_id + in: path + required: true + description: The unique id of an existing process instance. + schema: + type: integer + - name: task_id + in: path + required: true + description: The unique id of the task. + schema: + type: string + put: + operationId: spiffworkflow_backend.routes.process_api_blueprint.update_task_data + summary: Update the task data for requested instance and task + tags: + - Process Instances + responses: + "200": + description: Task Updated Successfully + content: + application/json: + schema: + $ref: "#/components/schemas/Workflow" + + /service-tasks: get: tags: - Service Tasks - operationId: spiffworkflow_backend.routes.process_api_blueprint.service_tasks_show + operationId: spiffworkflow_backend.routes.process_api_blueprint.service_task_list summary: Gets all available service task connectors responses: "200": @@ -1326,7 +1322,7 @@ paths: schema: $ref: "#/components/schemas/Workflow" - /process-instances/{process_instance_id}/logs: + /logs/{modified_process_model_identifier}/{process_instance_id}: parameters: - name: process_instance_id in: path @@ -1346,6 +1342,12 @@ paths: description: The number of items to show per page. Defaults to page 10. schema: type: integer + - name: detailed + in: query + required: false + description: Show the detailed view, which includes all log entries + schema: + type: boolean get: tags: - Process Instances diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml b/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml index e17e3f110..4c748fd9a 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml +++ b/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/development.yml @@ -12,7 +12,6 @@ groups: mike, jason, j, - amir, jarrad, elizabeth, jon, @@ -70,6 +69,12 @@ permissions: users: [] allowed_permissions: [create, read, update, delete] uri: /v1.0/tasks/* + service-tasks: + groups: [everybody] + users: [] + allowed_permissions: [read] + uri: /v1.0/service-tasks + # read all for everybody read-all-process-groups: @@ -98,6 +103,12 @@ permissions: allowed_permissions: [read] uri: /v1.0/processes + task-data-read: + groups: [demo] + users: [] + allowed_permissions: [read] + uri: /v1.0/task-data/* + manage-procurement-admin: groups: ["Project Lead"] @@ -170,17 +181,17 @@ permissions: uri: /v1.0/process-instances/manage-procurement:vendor-lifecycle-management:* core1-admin-models-instantiate: - groups: ["core-contributor"] + groups: ["core-contributor", "Finance Team"] users: [] allowed_permissions: [create] uri: /v1.0/process-models/misc:category_number_one:process-model-with-form/process-instances core1-admin-instances: - groups: ["core-contributor"] + groups: ["core-contributor", "Finance Team"] users: [] allowed_permissions: [create, read] uri: /v1.0/process-instances/misc:category_number_one:process-model-with-form:* core1-admin-instances-slash: - groups: ["core-contributor"] + groups: ["core-contributor", "Finance Team"] users: [] allowed_permissions: [create, read] uri: /v1.0/process-instances/misc:category_number_one:process-model-with-form/* diff --git a/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/terraform_deployed_environment.yml b/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/terraform_deployed_environment.yml index e60946b3c..ce2e2dba1 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/terraform_deployed_environment.yml +++ b/spiffworkflow-backend/src/spiffworkflow_backend/config/permissions/terraform_deployed_environment.yml @@ -12,7 +12,6 @@ groups: mike, jason, j, - amir, jarrad, elizabeth, jon, @@ -98,6 +97,12 @@ permissions: allowed_permissions: [read] uri: /v1.0/processes + task-data-read: + groups: [demo] + users: [] + allowed_permissions: [read] + uri: /v1.0/task-data/* + manage-procurement-admin: groups: ["Project Lead"] 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 6843fb157..549c76f05 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -158,9 +158,9 @@ def modify_process_model_id(process_model_id: str) -> str: return process_model_id.replace("/", ":") -def un_modify_modified_process_model_id(modified_process_model_id: str) -> str: +def un_modify_modified_process_model_id(modified_process_model_identifier: str) -> str: """Un_modify_modified_process_model_id.""" - return modified_process_model_id.replace(":", "/") + return modified_process_model_identifier.replace(":", "/") def process_group_add(body: dict) -> flask.wrappers.Response: @@ -411,9 +411,9 @@ def process_list() -> Any: return SpecReferenceSchema(many=True).dump(references) -def get_file(modified_process_model_id: str, file_name: str) -> Any: +def get_file(modified_process_model_identifier: str, file_name: str) -> Any: """Get_file.""" - process_model_identifier = modified_process_model_id.replace(":", "/") + process_model_identifier = modified_process_model_identifier.replace(":", "/") process_model = get_process_model(process_model_identifier) files = SpecFileService.get_files(process_model, file_name) if len(files) == 0: @@ -433,10 +433,10 @@ def get_file(modified_process_model_id: str, file_name: str) -> Any: def process_model_file_update( - modified_process_model_id: str, file_name: str + modified_process_model_identifier: str, file_name: str ) -> flask.wrappers.Response: """Process_model_file_update.""" - process_model_identifier = modified_process_model_id.replace(":", "/") + process_model_identifier = modified_process_model_identifier.replace(":", "/") process_model = get_process_model(process_model_identifier) request_file = get_file_from_request() @@ -462,10 +462,10 @@ def process_model_file_update( def process_model_file_delete( - modified_process_model_id: str, file_name: str + modified_process_model_identifier: str, file_name: str ) -> flask.wrappers.Response: """Process_model_file_delete.""" - process_model_identifier = modified_process_model_id.replace(":", "/") + process_model_identifier = modified_process_model_identifier.replace(":", "/") process_model = get_process_model(process_model_identifier) try: SpecFileService.delete_file(process_model, file_name) @@ -481,9 +481,9 @@ def process_model_file_delete( return Response(json.dumps({"ok": True}), status=200, mimetype="application/json") -def add_file(modified_process_model_id: str) -> flask.wrappers.Response: +def add_file(modified_process_model_identifier: str) -> flask.wrappers.Response: """Add_file.""" - process_model_identifier = modified_process_model_id.replace(":", "/") + process_model_identifier = modified_process_model_identifier.replace(":", "/") process_model = get_process_model(process_model_identifier) request_file = get_file_from_request() if not request_file.filename: @@ -504,10 +504,12 @@ def add_file(modified_process_model_id: str) -> flask.wrappers.Response: ) -def process_instance_create(modified_process_model_id: str) -> flask.wrappers.Response: +def process_instance_create( + modified_process_model_identifier: str, +) -> flask.wrappers.Response: """Create_process_instance.""" process_model_identifier = un_modify_modified_process_model_id( - modified_process_model_id + modified_process_model_identifier ) process_instance = ( ProcessInstanceService.create_process_instance_from_process_model_identifier( @@ -565,6 +567,7 @@ def process_instance_run( def process_instance_terminate( process_instance_id: int, + modified_process_model_identifier: str, ) -> flask.wrappers.Response: """Process_instance_run.""" process_instance = ProcessInstanceService().get_process_instance( @@ -577,6 +580,7 @@ def process_instance_terminate( def process_instance_suspend( process_instance_id: int, + modified_process_model_identifier: str, ) -> flask.wrappers.Response: """Process_instance_suspend.""" process_instance = ProcessInstanceService().get_process_instance( @@ -589,6 +593,7 @@ def process_instance_suspend( def process_instance_resume( process_instance_id: int, + modified_process_model_identifier: str, ) -> flask.wrappers.Response: """Process_instance_resume.""" process_instance = ProcessInstanceService().get_process_instance( @@ -600,19 +605,24 @@ def process_instance_resume( def process_instance_log_list( + modified_process_model_identifier: str, process_instance_id: int, page: int = 1, per_page: int = 100, + detailed: bool = False, ) -> flask.wrappers.Response: """Process_instance_log_list.""" # to make sure the process instance exists process_instance = find_process_instance_by_id_or_raise(process_instance_id) + log_query = SpiffLoggingModel.query.filter( + SpiffLoggingModel.process_instance_id == process_instance.id + ) + if not detailed: + log_query = log_query.filter(SpiffLoggingModel.message.in_(["State change to COMPLETED"])) # type: ignore + logs = ( - SpiffLoggingModel.query.filter( - SpiffLoggingModel.process_instance_id == process_instance.id - ) - .order_by(SpiffLoggingModel.timestamp.desc()) # type: ignore + log_query.order_by(SpiffLoggingModel.timestamp.desc()) # type: ignore .join( UserModel, UserModel.id == SpiffLoggingModel.current_user_id, isouter=True ) # isouter since if we don't have a user, we still want the log @@ -1071,7 +1081,9 @@ def process_instance_show( return make_response(jsonify(process_instance), 200) -def process_instance_delete(process_instance_id: int) -> flask.wrappers.Response: +def process_instance_delete( + process_instance_id: int, modified_process_model_identifier: str +) -> flask.wrappers.Response: """Create_process_instance.""" process_instance = find_process_instance_by_id_or_raise(process_instance_id) @@ -1153,8 +1165,8 @@ def process_instance_report_delete( return Response(json.dumps({"ok": True}), status=200, mimetype="application/json") -def service_tasks_show() -> flask.wrappers.Response: - """Service_tasks_show.""" +def service_task_list() -> flask.wrappers.Response: + """Service_task_list.""" available_connectors = ServiceTaskService.available_connectors() return Response( json.dumps(available_connectors), status=200, mimetype="application/json" @@ -1361,7 +1373,7 @@ def get_tasks( def process_instance_task_list( - modified_process_model_id: str, + modified_process_model_identifier: str, process_instance_id: int, all_tasks: bool = False, spiff_step: int = 0, @@ -1922,7 +1934,12 @@ def _update_form_schema_with_task_data_as_needed( _update_form_schema_with_task_data_as_needed(o, task_data) -def update_task_data(process_instance_id: str, task_id: str, body: Dict) -> Response: +def update_task_data( + process_instance_id: str, + modified_process_model_identifier: str, + task_id: str, + body: Dict, +) -> Response: """Update task data.""" process_instance = ProcessInstanceModel.query.filter( ProcessInstanceModel.id == int(process_instance_id) diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/helpers/base_test.py b/spiffworkflow-backend/tests/spiffworkflow_backend/helpers/base_test.py index 8d56853b4..48982fc60 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/helpers/base_test.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/helpers/base_test.py @@ -265,7 +265,7 @@ class BaseTest: ) modified_process_model_id = test_process_model_id.replace("/", ":") response = client.post( - f"/v1.0/process-models/{modified_process_model_id}/process-instances", + f"/v1.0/process-instances/{modified_process_model_id}", headers=headers, ) assert response.status_code == 201 diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_logging_service.py b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_logging_service.py index 2f56d1d6c..f9dd44522 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_logging_service.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_logging_service.py @@ -57,7 +57,7 @@ class TestLoggingService(BaseTest): assert response.status_code == 200 log_response = client.get( - f"/v1.0/process-instances/{process_instance_id}/logs", + f"/v1.0/logs/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}", headers=headers, ) assert log_response.status_code == 200 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 cd2d37c6a..9d719a233 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/integration/test_process_api.py @@ -912,7 +912,7 @@ class TestProcessApi(BaseTest): modified_process_model_identifier = process_model_identifier.replace("/", ":") response = client.post( - f"/v1.0/process-models/{modified_process_model_identifier}/process-instances", + f"/v1.0/process-instances/{modified_process_model_identifier}", headers=self.logged_in_headers(with_super_admin_user), ) assert response.status_code == 201 @@ -1154,10 +1154,11 @@ class TestProcessApi(BaseTest): headers=self.logged_in_headers(with_super_admin_user), ) show_response = client.get( - f"/v1.0/process-models/{modified_process_model_identifier}/process-instances/{process_instance_id}", + f"/v1.0/process-instances/{modified_process_model_identifier}/{process_instance_id}", 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() file_path = ( f"{file_system_root}/{process_model_identifier}/{process_model_id}.bpmn" @@ -1320,7 +1321,7 @@ class TestProcessApi(BaseTest): assert response.json is not None response = client.post( - f"/v1.0/process-instances/{process_instance_id}/terminate", + f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}/terminate", headers=self.logged_in_headers(with_super_admin_user), ) assert response.status_code == 200 @@ -1367,7 +1368,7 @@ class TestProcessApi(BaseTest): assert response.json is not None delete_response = client.delete( - f"/v1.0/process-instances/{process_instance_id}", + f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}", headers=self.logged_in_headers(with_super_admin_user), ) assert delete_response.status_code == 200 @@ -2366,7 +2367,7 @@ class TestProcessApi(BaseTest): assert process_instance.status == "user_input_required" client.post( - f"/v1.0/process-instances/{process_instance_id}/suspend", + f"/v1.0/process-instances/{self.modify_process_identifier_for_path_param(process_model_identifier)}/{process_instance_id}/suspend", headers=self.logged_in_headers(with_super_admin_user), ) process_instance = ProcessInstanceService().get_process_instance( diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index cc5ad75a9..eee5a2736 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -372,15 +372,18 @@ export default function ProcessInstanceListTable({ titleOperation = 'Created'; } return ( - + <> + +
+ ); } return null; @@ -935,6 +938,15 @@ export default function ProcessInstanceListTable({ if (!showFilterOptions) { return null; } + + // get the columns anytime we display the filter options if they are empty + if (availableReportColumns.length < 1) { + HttpService.makeCallToBackend({ + path: `/process-instances/reports/columns`, + successCallback: setAvailableReportColumns, + }); + } + return ( <> @@ -1059,7 +1071,7 @@ export default function ProcessInstanceListTable({ return ( {id} @@ -1134,10 +1146,6 @@ export default function ProcessInstanceListTable({ const toggleShowFilterOptions = () => { setShowFilterOptions(!showFilterOptions); - HttpService.makeCallToBackend({ - path: `/process-instances/reports/columns`, - successCallback: setAvailableReportColumns, - }); }; const reportSearchComponent = () => { @@ -1166,6 +1174,9 @@ export default function ProcessInstanceListTable({ return ( <> + + {reportSearchComponent()} + { HttpService.makeCallToBackend({ - path: processInstanceActionPath, + path: processInstanceCreatePath, successCallback: processModelRun, httpMethod: 'POST', }); }; if (checkPermissions) { return ( - + diff --git a/spiffworkflow-frontend/src/components/ProcessModelForm.tsx b/spiffworkflow-frontend/src/components/ProcessModelForm.tsx index 1599aff5d..7cfd4d616 100644 --- a/spiffworkflow-frontend/src/components/ProcessModelForm.tsx +++ b/spiffworkflow-frontend/src/components/ProcessModelForm.tsx @@ -194,7 +194,6 @@ export default function ProcessModelForm({ onChange={(event: any) => { onDisplayNameChanged(event.target.value); }} - onBlur={(event: any) => console.log('event', event)} />, ]; diff --git a/spiffworkflow-frontend/src/components/ProcessModelListTiles.tsx b/spiffworkflow-frontend/src/components/ProcessModelListTiles.tsx index 4787fe94e..1412635c5 100644 --- a/spiffworkflow-frontend/src/components/ProcessModelListTiles.tsx +++ b/spiffworkflow-frontend/src/components/ProcessModelListTiles.tsx @@ -54,9 +54,9 @@ export default function ProcessModelListTiles({

Process Instance {processInstance.id} kicked off ( view diff --git a/spiffworkflow-frontend/src/components/TasksForMyOpenProcesses.tsx b/spiffworkflow-frontend/src/components/TasksForMyOpenProcesses.tsx index a81779c7a..deb2030ea 100644 --- a/spiffworkflow-frontend/src/components/TasksForMyOpenProcesses.tsx +++ b/spiffworkflow-frontend/src/components/TasksForMyOpenProcesses.tsx @@ -55,7 +55,7 @@ export default function MyOpenProcesses() { {rowToUse.process_instance_id} diff --git a/spiffworkflow-frontend/src/components/TasksWaitingForMe.tsx b/spiffworkflow-frontend/src/components/TasksWaitingForMe.tsx index 924202248..7d06b7a30 100644 --- a/spiffworkflow-frontend/src/components/TasksWaitingForMe.tsx +++ b/spiffworkflow-frontend/src/components/TasksWaitingForMe.tsx @@ -47,7 +47,7 @@ export default function TasksWaitingForMe() { {rowToUse.process_instance_id} diff --git a/spiffworkflow-frontend/src/components/TasksWaitingForMyGroups.tsx b/spiffworkflow-frontend/src/components/TasksWaitingForMyGroups.tsx index 51c38e946..565cd4a55 100644 --- a/spiffworkflow-frontend/src/components/TasksWaitingForMyGroups.tsx +++ b/spiffworkflow-frontend/src/components/TasksWaitingForMyGroups.tsx @@ -55,7 +55,7 @@ export default function TasksWaitingForMyGroups() { {rowToUse.process_instance_id} diff --git a/spiffworkflow-frontend/src/hooks/UriListForPermissions.tsx b/spiffworkflow-frontend/src/hooks/UriListForPermissions.tsx index 80c78987a..eff30a828 100644 --- a/spiffworkflow-frontend/src/hooks/UriListForPermissions.tsx +++ b/spiffworkflow-frontend/src/hooks/UriListForPermissions.tsx @@ -9,10 +9,12 @@ export const useUriListForPermissions = () => { messageInstanceListPath: '/v1.0/messages', processGroupListPath: '/v1.0/process-groups', processGroupShowPath: `/v1.0/process-groups/${params.process_group_id}`, - processInstanceActionPath: `/v1.0/process-models/${params.process_model_id}/process-instances`, + processInstanceCreatePath: `/v1.0/process-instances/${params.process_model_id}`, + processInstanceActionPath: `/v1.0/process-instances/${params.process_model_id}/${params.process_instance_id}`, processInstanceListPath: '/v1.0/process-instances', - processInstanceTaskListPath: `/v1.0/process-instances/${params.process_model_id}/${params.process_instance_id}/tasks`, + processInstanceLogListPath: `/v1.0/logs/${params.process_model_id}/${params.process_instance_id}`, processInstanceReportListPath: '/v1.0/process-instances/reports', + processInstanceTaskListPath: `/v1.0/task-data/${params.process_model_id}/${params.process_instance_id}`, processModelCreatePath: `/v1.0/process-models/${params.process_group_id}`, processModelFileCreatePath: `/v1.0/process-models/${params.process_model_id}/files`, processModelFileShowPath: `/v1.0/process-models/${params.process_model_id}/files/${params.file_name}`, diff --git a/spiffworkflow-frontend/src/routes/AdminRoutes.tsx b/spiffworkflow-frontend/src/routes/AdminRoutes.tsx index 91ae7ab08..da6cae356 100644 --- a/spiffworkflow-frontend/src/routes/AdminRoutes.tsx +++ b/spiffworkflow-frontend/src/routes/AdminRoutes.tsx @@ -71,11 +71,11 @@ export default function AdminRoutes() { element={} /> } /> } /> } /> } /> } /> diff --git a/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx b/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx index b77b744cb..a9ec6b69f 100644 --- a/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx +++ b/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx @@ -102,9 +102,9 @@ export default function MessageInstanceList() { {row.process_instance_id} @@ -163,9 +163,9 @@ export default function MessageInstanceList() { }, [ `Process Instance: ${searchParams.get('process_instance_id')}`, - `/admin/process-models/${searchParams.get( + `/admin/process-instances/${searchParams.get( 'process_model_id' - )}/process-instances/${searchParams.get('process_instance_id')}`, + )}/${searchParams.get('process_instance_id')}`, ], ['Messages'], ]} diff --git a/spiffworkflow-frontend/src/routes/MyTasks.tsx b/spiffworkflow-frontend/src/routes/MyTasks.tsx index 51f5f3e99..4c1cbc9bf 100644 --- a/spiffworkflow-frontend/src/routes/MyTasks.tsx +++ b/spiffworkflow-frontend/src/routes/MyTasks.tsx @@ -55,9 +55,9 @@ export default function MyTasks() {

Process Instance {processInstance.id} kicked off ( view @@ -95,7 +95,7 @@ export default function MyTasks() { {rowToUse.process_instance_id} diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx index f41caf944..37ef5519c 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceLogList.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; // @ts-ignore -import { Table } from '@carbon/react'; +import { Table, Tabs, TabList, Tab } from '@carbon/react'; import { useParams, useSearchParams, Link } from 'react-router-dom'; import PaginationForTable from '../components/PaginationForTable'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; @@ -10,15 +10,18 @@ import { convertSecondsToFormattedDateTime, } from '../helpers'; import HttpService from '../services/HttpService'; +import { useUriListForPermissions } from '../hooks/UriListForPermissions'; export default function ProcessInstanceLogList() { const params = useParams(); - const [searchParams] = useSearchParams(); + const [searchParams, setSearchParams] = useSearchParams(); const [processInstanceLogs, setProcessInstanceLogs] = useState([]); const [pagination, setPagination] = useState(null); const modifiedProcessModelId = modifyProcessIdentifierForPathParam( `${params.process_model_id}` ); + const { targetUris } = useUriListForPermissions(); + const isDetailedView = searchParams.get('detailed') === 'true'; useEffect(() => { const setProcessInstanceLogListFromResult = (result: any) => { @@ -27,26 +30,36 @@ export default function ProcessInstanceLogList() { }; const { page, perPage } = getPageInfoFromSearchParams(searchParams); HttpService.makeCallToBackend({ - path: `/process-instances/${params.process_instance_id}/logs?per_page=${perPage}&page=${page}`, + path: `${targetUris.processInstanceLogListPath}?per_page=${perPage}&page=${page}&detailed=${isDetailedView}`, successCallback: setProcessInstanceLogListFromResult, }); - }, [searchParams, params]); + }, [ + searchParams, + params, + targetUris.processInstanceLogListPath, + isDetailedView, + ]); const buildTable = () => { const rows = processInstanceLogs.map((row) => { const rowToUse = row as any; return ( - {rowToUse.bpmn_process_identifier} + {rowToUse.id} {rowToUse.message} - {rowToUse.bpmn_task_identifier} {rowToUse.bpmn_task_name} - {rowToUse.bpmn_task_type} + {isDetailedView && ( + <> + {rowToUse.bpmn_task_identifier} + {rowToUse.bpmn_task_type} + {rowToUse.bpmn_process_identifier} + + )} {rowToUse.username} {convertSecondsToFormattedDateTime(rowToUse.timestamp)} @@ -58,11 +71,16 @@ export default function ProcessInstanceLogList() { - + - - + {isDetailedView && ( + <> + + + + + )} @@ -71,11 +89,12 @@ export default function ProcessInstanceLogList() {
Bpmn Process IdentifierId MessageTask Identifier Task NameTask TypeTask IdentifierTask TypeBpmn Process IdentifierUser Timestamp
); }; + const selectedTabIndex = isDetailedView ? 1 : 0; if (pagination) { const { page, perPage } = getPageInfoFromSearchParams(searchParams); return ( -

+ <> + + + { + searchParams.set('detailed', 'false'); + setSearchParams(searchParams); + }} + > + Simple + + { + searchParams.set('detailed', 'true'); + setSearchParams(searchParams); + }} + > + Detailed + + + +
-
+ ); } return null; diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index c407c7713..9a0495d1d 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -59,6 +59,11 @@ export default function ProcessInstanceShow() { const permissionRequestData: PermissionsToCheck = { [targetUris.messageInstanceListPath]: ['GET'], [targetUris.processInstanceTaskListPath]: ['GET'], + [targetUris.processInstanceActionPath]: ['DELETE'], + [targetUris.processInstanceLogListPath]: ['GET'], + [`${targetUris.processInstanceActionPath}/suspend`]: ['PUT'], + [`${targetUris.processInstanceActionPath}/terminate`]: ['PUT'], + [`${targetUris.processInstanceActionPath}/resume`]: ['PUT'], }; const { ability, permissionsLoaded } = usePermissionFetcher( permissionRequestData @@ -76,7 +81,7 @@ export default function ProcessInstanceShow() { setTasksCallHadError(true); }; HttpService.makeCallToBackend({ - path: `/process-models/${modifiedProcessModelId}/process-instances/${params.process_instance_id}`, + path: `/process-instances/${modifiedProcessModelId}/${params.process_instance_id}`, successCallback: setProcessInstance, }); let taskParams = '?all_tasks=true'; @@ -85,7 +90,7 @@ export default function ProcessInstanceShow() { } if (ability.can('GET', targetUris.processInstanceTaskListPath)) { HttpService.makeCallToBackend({ - path: `/process-instances/${modifiedProcessModelId}/${params.process_instance_id}/tasks${taskParams}`, + path: `${targetUris.processInstanceTaskListPath}${taskParams}`, successCallback: setTasks, failureCallback: processTaskFailure, }); @@ -97,7 +102,7 @@ export default function ProcessInstanceShow() { const deleteProcessInstance = () => { HttpService.makeCallToBackend({ - path: `/process-instances/${params.process_instance_id}`, + path: targetUris.processInstanceActionPath, successCallback: navigateToProcessInstances, httpMethod: 'DELETE', }); @@ -110,7 +115,7 @@ export default function ProcessInstanceShow() { const terminateProcessInstance = () => { HttpService.makeCallToBackend({ - path: `/process-instances/${params.process_instance_id}/terminate`, + path: `${targetUris.processInstanceActionPath}/terminate`, successCallback: refreshPage, httpMethod: 'POST', }); @@ -118,7 +123,7 @@ export default function ProcessInstanceShow() { const suspendProcessInstance = () => { HttpService.makeCallToBackend({ - path: `/process-instances/${params.process_instance_id}/suspend`, + path: `${targetUris.processInstanceActionPath}/suspend`, successCallback: refreshPage, httpMethod: 'POST', }); @@ -126,7 +131,7 @@ export default function ProcessInstanceShow() { const resumeProcessInstance = () => { HttpService.makeCallToBackend({ - path: `/process-instances/${params.process_instance_id}/resume`, + path: `${targetUris.processInstanceActionPath}/resume`, successCallback: refreshPage, httpMethod: 'POST', }); @@ -174,7 +179,7 @@ export default function ProcessInstanceShow() { - + Completed:{' '} @@ -235,7 +240,7 @@ export default function ProcessInstanceShow() { return ( <> - + Started:{' '} @@ -246,7 +251,7 @@ export default function ProcessInstanceShow() { {currentEndDateTag} - + Status:{' '} @@ -259,14 +264,20 @@ export default function ProcessInstanceShow() { - + +
{ const elements = []; - elements.push(terminateButton(processInstanceToUse)); - elements.push(suspendButton(processInstanceToUse)); - elements.push(resumeButton(processInstanceToUse)); - elements.push( - - ); + if ( + ability.can('POST', `${targetUris.processInstanceActionPath}/terminate`) + ) { + elements.push(terminateButton(processInstanceToUse)); + } + if ( + ability.can('POST', `${targetUris.processInstanceActionPath}/suspend`) + ) { + elements.push(suspendButton(processInstanceToUse)); + } + if (ability.can('POST', `${targetUris.processInstanceActionPath}/resume`)) { + elements.push(resumeButton(processInstanceToUse)); + } + if (ability.can('DELETE', targetUris.processInstanceActionPath)) { + elements.push( + + ); + } return elements; }; diff --git a/spiffworkflow-frontend/src/routes/ProcessModelEditDiagram.tsx b/spiffworkflow-frontend/src/routes/ProcessModelEditDiagram.tsx index d117f798f..1a5c751f7 100644 --- a/spiffworkflow-frontend/src/routes/ProcessModelEditDiagram.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessModelEditDiagram.tsx @@ -283,7 +283,7 @@ export default function ProcessModelEditDiagram() { const onServiceTasksRequested = (event: any) => { HttpService.makeCallToBackend({ - path: `/service_tasks`, + path: `/service-tasks`, successCallback: makeApiHandler(event), }); }; diff --git a/spiffworkflow-frontend/src/routes/ProcessModelShow.tsx b/spiffworkflow-frontend/src/routes/ProcessModelShow.tsx index 2882e1832..96a656567 100644 --- a/spiffworkflow-frontend/src/routes/ProcessModelShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessModelShow.tsx @@ -66,7 +66,7 @@ export default function ProcessModelShow() { const permissionRequestData: PermissionsToCheck = { [targetUris.processModelShowPath]: ['PUT', 'DELETE'], [targetUris.processInstanceListPath]: ['GET'], - [targetUris.processInstanceActionPath]: ['POST'], + [targetUris.processInstanceCreatePath]: ['POST'], [targetUris.processModelFileCreatePath]: ['POST', 'PUT', 'GET', 'DELETE'], }; const { ability, permissionsLoaded } = usePermissionFetcher( @@ -95,7 +95,7 @@ export default function ProcessModelShow() {

Process Instance {processInstance.id} kicked off ( view @@ -556,7 +556,7 @@ export default function ProcessModelShow() { <> diff --git a/spiffworkflow-frontend/src/routes/TaskShow.tsx b/spiffworkflow-frontend/src/routes/TaskShow.tsx index 768043cd8..9e0f65c53 100644 --- a/spiffworkflow-frontend/src/routes/TaskShow.tsx +++ b/spiffworkflow-frontend/src/routes/TaskShow.tsx @@ -26,6 +26,9 @@ import Form from '../themes/carbon'; import HttpService from '../services/HttpService'; import ErrorContext from '../contexts/ErrorContext'; import { modifyProcessIdentifierForPathParam } from '../helpers'; +import { useUriListForPermissions } from '../hooks/UriListForPermissions'; +import { PermissionsToCheck } from '../interfaces'; +import { usePermissionFetcher } from '../hooks/PermissionService'; export default function TaskShow() { const [task, setTask] = useState(null); @@ -35,24 +38,36 @@ export default function TaskShow() { const setErrorMessage = (useContext as any)(ErrorContext)[1]; - useEffect(() => { - const processResult = (result: any) => { - setTask(result); - HttpService.makeCallToBackend({ - path: `/process-instances/${modifyProcessIdentifierForPathParam( - result.process_model_identifier - )}/${params.process_instance_id}/tasks`, - successCallback: setUserTasks, - }); - }; + const { targetUris } = useUriListForPermissions(); + const permissionRequestData: PermissionsToCheck = { + [targetUris.processInstanceTaskListPath]: ['GET'], + }; + const { ability, permissionsLoaded } = usePermissionFetcher( + permissionRequestData + ); - HttpService.makeCallToBackend({ - path: `/tasks/${params.process_instance_id}/${params.task_id}`, - successCallback: processResult, - // This causes the page to continuously reload - // failureCallback: setErrorMessage, - }); - }, [params]); + useEffect(() => { + if (permissionsLoaded) { + const processResult = (result: any) => { + setTask(result); + if (ability.can('GET', targetUris.processInstanceTaskListPath)) { + HttpService.makeCallToBackend({ + path: `/task-data/${modifyProcessIdentifierForPathParam( + result.process_model_identifier + )}/${params.process_instance_id}`, + successCallback: setUserTasks, + }); + } + }; + + HttpService.makeCallToBackend({ + path: `/tasks/${params.process_instance_id}/${params.task_id}`, + successCallback: processResult, + // This causes the page to continuously reload + // failureCallback: setErrorMessage, + }); + } + }, [params, permissionsLoaded, ability, targetUris]); const processSubmitResult = (result: any) => { setErrorMessage(null); @@ -116,17 +131,18 @@ export default function TaskShow() { } return null; }); + return ( + + + {userTasksElement} + + + ); } - return ( - - - {userTasksElement} - - - ); + return null; }; const formElement = (taskToUse: any) => { @@ -207,7 +223,7 @@ export default function TaskShow() { ); }; - if (task && userTasks) { + if (task) { const taskToUse = task as any; let statusString = ''; if (taskToUse.state !== 'READY') {