diff --git a/spiffworkflow-backend/migrations/env.py b/spiffworkflow-backend/migrations/env.py index 68feded2a..630e381ad 100644 --- a/spiffworkflow-backend/migrations/env.py +++ b/spiffworkflow-backend/migrations/env.py @@ -1,5 +1,3 @@ -from __future__ import with_statement - import logging from logging.config import fileConfig 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 3bba5aed6..e00e7cacf 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/models/spiff_step_details.py @@ -2,10 +2,9 @@ from dataclasses import dataclass from typing import Optional -from sqlalchemy import ForeignKey - from flask_bpmn.models.db import db from flask_bpmn.models.db import SpiffworkflowBaseDBModel +from sqlalchemy import ForeignKey from sqlalchemy.orm import deferred from spiffworkflow_backend.models.group import GroupModel @@ -22,4 +21,6 @@ class SpiffStepDetailsModel(SpiffworkflowBaseDBModel): task_json: str = 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(ForeignKey(GroupModel.id), nullable=True) + lane_assignment_id: Optional[int] = db.Column( + ForeignKey(GroupModel.id), nullable=True + ) 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 c4044b2a2..67f91ab19 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -1264,7 +1264,9 @@ def task_submit( if terminate_loop and spiff_task.is_looping(): spiff_task.terminate_loop() - active_task = ActiveTaskModel.query.filter_by(process_instance_id=process_instance_id, task_id=task_id).first() + active_task = ActiveTaskModel.query.filter_by( + process_instance_id=process_instance_id, task_id=task_id + ).first() if active_task is None: raise ( ApiError( @@ -1274,7 +1276,13 @@ def task_submit( ) ) - ProcessInstanceService.complete_form_task(processor=processor, spiff_task=spiff_task, data=body, user=g.user, active_task=active_task) + ProcessInstanceService.complete_form_task( + processor=processor, + spiff_task=spiff_task, + data=body, + user=g.user, + active_task=active_task, + ) # If we need to update all tasks, then get the next ready task and if it a multi-instance with the same # task spec, complete that form as well. 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 ccf362ab7..aac9b1760 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_service.py @@ -6,9 +6,9 @@ from typing import List from flask import current_app from flask_bpmn.api.api_error import ApiError from flask_bpmn.models.db import db -from SpiffWorkflow.task import Task as SpiffTask -from spiffworkflow_backend.models.active_task import ActiveTaskModel # type: ignore +from SpiffWorkflow.task import Task as SpiffTask # type: ignore +from spiffworkflow_backend.models.active_task import ActiveTaskModel from spiffworkflow_backend.models.process_instance import ProcessInstanceApi from spiffworkflow_backend.models.process_instance import ProcessInstanceModel from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus @@ -189,7 +189,7 @@ class ProcessInstanceService: spiff_task: SpiffTask, data: dict[str, Any], user: UserModel, - active_task: ActiveTaskModel + active_task: ActiveTaskModel, ) -> None: """All the things that need to happen when we complete a form. diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_localtime.py b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_localtime.py index 9e65b9707..f1834ab3a 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_localtime.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/scripts/test_get_localtime.py @@ -74,7 +74,11 @@ class TestGetLocaltime(BaseTest): ) ProcessInstanceService.complete_form_task( - processor, spiff_task, {"timezone": "US/Pacific"}, initiator_user + processor, + spiff_task, + {"timezone": "US/Pacific"}, + initiator_user, + active_task, ) active_task = process_instance.active_tasks[0] diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_authorization_service.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_authorization_service.py index 916347b35..36f077435 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_authorization_service.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_authorization_service.py @@ -126,7 +126,7 @@ class TestAuthorizationService(BaseTest): active_task.task_name, processor.bpmn_process_instance ) ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, initiator_user + processor, spiff_task, {}, initiator_user, active_task ) active_task = process_instance.active_tasks[0] @@ -137,5 +137,5 @@ class TestAuthorizationService(BaseTest): {"username": "testuser2", "sub": "open_id"} ) ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, finance_user + processor, spiff_task, {}, finance_user, active_task ) diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_dot_notation.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_dot_notation.py index 6bd1cca6d..18c115617 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_dot_notation.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_dot_notation.py @@ -44,6 +44,7 @@ class TestDotNotation(BaseTest): process_instance = ProcessInstanceService().get_process_instance( process_instance_id ) + active_task = process_instance.active_tasks[0] processor = ProcessInstanceProcessor(process_instance) processor.do_engine_steps(save=True) @@ -57,7 +58,7 @@ class TestDotNotation(BaseTest): "invoice.dueDate": "09/30/2022", } ProcessInstanceService.complete_form_task( - processor, user_task, form_data, with_super_admin_user + processor, user_task, form_data, with_super_admin_user, active_task ) expected = { diff --git a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py index ad7aefe34..f0de77aa7 100644 --- a/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py +++ b/spiffworkflow-backend/tests/spiffworkflow_backend/unit/test_process_instance_processor.py @@ -91,10 +91,10 @@ class TestProcessInstanceProcessor(BaseTest): ) with pytest.raises(UserDoesNotHaveAccessToTaskError): ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, finance_user + processor, spiff_task, {}, finance_user, active_task ) ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, initiator_user + processor, spiff_task, {}, initiator_user, active_task ) assert len(process_instance.active_tasks) == 1 @@ -108,11 +108,11 @@ class TestProcessInstanceProcessor(BaseTest): ) with pytest.raises(UserDoesNotHaveAccessToTaskError): ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, initiator_user + processor, spiff_task, {}, initiator_user, active_task ) ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, finance_user + processor, spiff_task, {}, finance_user, active_task ) assert len(process_instance.active_tasks) == 1 active_task = process_instance.active_tasks[0] @@ -124,7 +124,7 @@ class TestProcessInstanceProcessor(BaseTest): active_task.task_name, processor.bpmn_process_instance ) ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, initiator_user + processor, spiff_task, {}, initiator_user, active_task ) assert process_instance.status == ProcessInstanceStatus.complete.value @@ -173,10 +173,10 @@ class TestProcessInstanceProcessor(BaseTest): ) with pytest.raises(UserDoesNotHaveAccessToTaskError): ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, finance_user_three + processor, spiff_task, {}, finance_user_three, active_task ) ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, initiator_user + processor, spiff_task, {}, initiator_user, active_task ) assert len(process_instance.active_tasks) == 1 @@ -190,12 +190,12 @@ class TestProcessInstanceProcessor(BaseTest): ) with pytest.raises(UserDoesNotHaveAccessToTaskError): ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, initiator_user + processor, spiff_task, {}, initiator_user, active_task ) g.user = finance_user_three ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, finance_user_three + processor, spiff_task, {}, finance_user_three, active_task ) assert len(process_instance.active_tasks) == 1 active_task = process_instance.active_tasks[0] @@ -208,11 +208,11 @@ class TestProcessInstanceProcessor(BaseTest): ) with pytest.raises(UserDoesNotHaveAccessToTaskError): ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, initiator_user + processor, spiff_task, {}, initiator_user, active_task ) ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, finance_user_four + processor, spiff_task, {}, finance_user_four, active_task ) assert len(process_instance.active_tasks) == 1 active_task = process_instance.active_tasks[0] @@ -224,7 +224,7 @@ class TestProcessInstanceProcessor(BaseTest): active_task.task_name, processor.bpmn_process_instance ) ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, initiator_user + processor, spiff_task, {}, initiator_user, active_task ) assert len(process_instance.active_tasks) == 1 @@ -234,8 +234,10 @@ class TestProcessInstanceProcessor(BaseTest): ) with pytest.raises(UserDoesNotHaveAccessToTaskError): ProcessInstanceService.complete_form_task( - processor, spiff_task, {}, initiator_user + processor, spiff_task, {}, initiator_user, active_task ) - ProcessInstanceService.complete_form_task(processor, spiff_task, {}, testadmin1) + ProcessInstanceService.complete_form_task( + processor, spiff_task, {}, testadmin1, active_task + ) assert process_instance.status == ProcessInstanceStatus.complete.value diff --git a/spiffworkflow-frontend/src/components/MyCompletedInstances.tsx b/spiffworkflow-frontend/src/components/MyCompletedInstances.tsx new file mode 100644 index 000000000..fe6652951 --- /dev/null +++ b/spiffworkflow-frontend/src/components/MyCompletedInstances.tsx @@ -0,0 +1,13 @@ +import ProcessInstanceListTable from './ProcessInstanceListTable'; + +const paginationQueryParamPrefix = 'my_completed_instances'; + +export default function MyCompletedInstances() { + return ( + + ); +} diff --git a/spiffworkflow-frontend/src/components/PaginationForTable.tsx b/spiffworkflow-frontend/src/components/PaginationForTable.tsx index 19d098ffd..70da531d9 100644 --- a/spiffworkflow-frontend/src/components/PaginationForTable.tsx +++ b/spiffworkflow-frontend/src/components/PaginationForTable.tsx @@ -13,7 +13,6 @@ type OwnProps = { perPageOptions?: number[]; pagination: PaginationObject | null; tableToDisplay: any; - queryParamString?: string; paginationQueryParamPrefix?: string; }; diff --git a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx index 81a416f30..ceb0e997a 100644 --- a/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx +++ b/spiffworkflow-frontend/src/components/ProcessInstanceListTable.tsx @@ -46,12 +46,14 @@ type OwnProps = { filtersEnabled?: boolean; processModelFullIdentifier?: string; paginationQueryParamPrefix?: string; + perPageOptions?: number[]; }; export default function ProcessInstanceListTable({ filtersEnabled = true, processModelFullIdentifier, paginationQueryParamPrefix, + perPageOptions, }: OwnProps) { const params = useParams(); const [searchParams] = useSearchParams(); @@ -108,12 +110,17 @@ export default function ProcessInstanceListTable({ setPagination(result.pagination); } function getProcessInstances() { - const { page, perPage } = getPageInfoFromSearchParams( + // eslint-disable-next-line prefer-const + let { page, perPage } = getPageInfoFromSearchParams( searchParams, undefined, undefined, paginationQueryParamPrefix ); + if (perPageOptions && !perPageOptions.includes(perPage)) { + // eslint-disable-next-line prefer-destructuring + perPage = perPageOptions[1]; + } let queryParamString = `per_page=${perPage}&page=${page}`; Object.keys(parametersToAlwaysFilterBy).forEach((paramName: string) => { @@ -200,6 +207,9 @@ export default function ProcessInstanceListTable({ parametersToAlwaysFilterBy, parametersToGetFromSearchParams, filtersEnabled, + paginationQueryParamPrefix, + processModelFullIdentifier, + perPageOptions, ]); // does the comparison, but also returns false if either argument @@ -307,25 +317,6 @@ export default function ProcessInstanceListTable({ ); }; - const getSearchParamsAsQueryString = () => { - let queryParamString = ''; - Object.keys(parametersToAlwaysFilterBy).forEach((paramName) => { - const searchParamValue = searchParams.get(paramName); - if (searchParamValue) { - queryParamString += `&${paramName}=${searchParamValue}`; - } - }); - - Object.keys(parametersToGetFromSearchParams).forEach( - (paramName: string) => { - if (searchParams.get(paramName)) { - queryParamString += `&${paramName}=${searchParams.get(paramName)}`; - } - } - ); - return queryParamString; - }; - const processStatusSearch = () => { return ( {filterComponent()} @@ -550,8 +546,8 @@ export default function ProcessInstanceListTable({ perPage={perPage} pagination={pagination} tableToDisplay={buildTable()} - queryParamString={getSearchParamsAsQueryString()} paginationQueryParamPrefix={paginationQueryParamPrefix} + perPageOptions={perPageOptions} /> ); diff --git a/spiffworkflow-frontend/src/routes/CompletedInstances.tsx b/spiffworkflow-frontend/src/routes/CompletedInstances.tsx index 8b5dbcac7..237c21f3b 100644 --- a/spiffworkflow-frontend/src/routes/CompletedInstances.tsx +++ b/spiffworkflow-frontend/src/routes/CompletedInstances.tsx @@ -1,3 +1,5 @@ +import MyCompletedInstances from '../components/MyCompletedInstances'; + export default function CompletedInstances() { - return <>; + return ; } diff --git a/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx b/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx index 62e189b6c..09d283167 100644 --- a/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx +++ b/spiffworkflow-frontend/src/routes/MessageInstanceList.tsx @@ -94,14 +94,8 @@ export default function MessageInstanceList() { if (pagination) { const { page, perPage } = getPageInfoFromSearchParams(searchParams); - let queryParamString = ''; let breadcrumbElement = null; if (searchParams.get('process_instance_id')) { - queryParamString += `&process_group_id=${searchParams.get( - 'process_group_id' - )}&process_model_id=${searchParams.get( - 'process_model_id' - )}&process_instance_id=${searchParams.get('process_instance_id')}`; breadcrumbElement = ( );