From 5a7e3e7e23dd81828639a369bea530abfb45579e Mon Sep 17 00:00:00 2001 From: Elizabeth Esswein Date: Thu, 29 Dec 2022 20:11:18 -0500 Subject: [PATCH 1/7] improve button labels --- spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index 678ebdf2..96ad1138 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -717,7 +717,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { data-qa="mark-task-complete-button" onClick={() => completeTask(false)} > - Mark Complete + Skip Task ); buttons.push( @@ -745,7 +745,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { data-qa="reset-process-button" onClick={() => resetProcessInstance()} > - Resume Process Here + Reset Process Here ); } From 60fded7b2cdf8bca5e37649d2838936e02e9dad1 Mon Sep 17 00:00:00 2001 From: Elizabeth Esswein Date: Fri, 30 Dec 2022 01:39:04 -0500 Subject: [PATCH 2/7] create spiff steps for manual navigation --- .../routes/process_api_blueprint.py | 32 +---------- .../services/process_instance_processor.py | 56 ++++++++++++++++--- 2 files changed, 51 insertions(+), 37 deletions(-) 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 68259881..8f522af9 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_api_blueprint.py @@ -661,35 +661,9 @@ def process_instance_reset( process_instance = ProcessInstanceService().get_process_instance( process_instance_id ) - step_detail = ( - db.session.query(SpiffStepDetailsModel) - .filter( - SpiffStepDetailsModel.process_instance_id == process_instance.id, - SpiffStepDetailsModel.spiff_step == spiff_step, - ) - .first() - ) - if step_detail is not None and process_instance.bpmn_json is not None: - bpmn_json = json.loads(process_instance.bpmn_json) - bpmn_json["tasks"] = step_detail.task_json["tasks"] - bpmn_json["subprocesses"] = step_detail.task_json["subprocesses"] - process_instance.bpmn_json = json.dumps(bpmn_json) - - db.session.add(process_instance) - try: - db.session.commit() - except Exception as e: - db.session.rollback() - raise ApiError( - error_code="reset_process_instance_error", - message=f"Could not update the Instance. Original error is {e}", - ) from e - - return Response( - json.dumps(ProcessInstanceModelSchema().dump(process_instance)), - status=200, - mimetype="application/json", - ) + processor = ProcessInstanceProcessor(process_instance) + processor.reset_process(spiff_step) + return Response(json.dumps({"ok": True}), status=200, mimetype="application/json") def process_instance_log_list( 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 f9e6c620..842bca15 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -622,7 +622,7 @@ class ProcessInstanceProcessor: db.session.add(pim) db.session.commit() - def _save(self) -> None: + def save(self) -> None: """Saves the current state of this processor to the database.""" self.process_instance_model.bpmn_json = self.serialize() @@ -644,9 +644,6 @@ class ProcessInstanceProcessor: db.session.add(self.process_instance_model) db.session.commit() - def save(self) -> None: - """Saves the current state and moves on to the next state.""" - self._save() human_tasks = HumanTaskModel.query.filter_by( process_instance_id=self.process_instance_model.id ).all() @@ -733,6 +730,14 @@ class ProcessInstanceProcessor: self.bpmn_process_instance.catch(event_definition) self.do_engine_steps(save=True) + def add_step(self, step: Union[dict, None] = None) -> None: + """Add a spiff step.""" + self.increment_spiff_step() + if step is None: + step = self.spiff_step_details_mapping() + db.session.add(SpiffStepDetailsModel(**step)) + db.session.commit() + def manual_complete_task(self, task_id: str, execute: bool) -> None: """Mark the task complete optionally executing it.""" spiff_task = self.bpmn_process_instance.get_task(UUID(task_id)) @@ -742,17 +747,52 @@ class ProcessInstanceProcessor: ) spiff_task.complete() else: - current_app.logger.info( - f"Skipping Task {spiff_task.task_spec.name} of process instance {self.process_instance_model.id}" - ) + spiff_logger = logging.getLogger("spiff") + spiff_logger.info(f"Skipped task", extra=spiff_task.log_info()) spiff_task._set_state(TaskState.COMPLETED) for child in spiff_task.children: child.task_spec._update(child) self.bpmn_process_instance.last_task = spiff_task - self._save() + self.add_step() + self.save() # Saving the workflow seems to reset the status self.suspend() + def reset_process(self, spiff_step: int) -> None: + """Reset a process to an earlier state.""" + + spiff_logger = logging.getLogger("spiff") + spiff_logger.info( + f"Process reset from step {spiff_step}", + extra=self.bpmn_process_instance.log_info(), + ) + + step_detail = ( + db.session.query(SpiffStepDetailsModel) + .filter( + SpiffStepDetailsModel.process_instance_id + == self.process_instance_model.id, + SpiffStepDetailsModel.spiff_step == spiff_step, + ) + .first() + ) + if step_detail is not None: + self.add_step( + { + "process_instance_id": self.process_instance_model.id, + "spiff_step": self.process_instance_model.spiff_step or 1, + "task_json": step_detail.task_json, + "timestamp": round(time.time()), + } + ) + + dct = self._serializer.workflow_to_dict(self.bpmn_process_instance) + dct["tasks"] = step_detail.task_json["tasks"] + dct["subprocesses"] = step_detail.task_json["subprocesses"] + self.bpmn_process_instance = self._serializer.workflow_from_dict(dct) + self.save() + self.suspend() + @staticmethod def get_parser() -> MyCustomParser: """Get_parser.""" From ed999a154503bb4965d0f5288e6852f5651e0d22 Mon Sep 17 00:00:00 2001 From: Elizabeth Esswein Date: Fri, 30 Dec 2022 10:40:34 -0500 Subject: [PATCH 3/7] redirect to current step when resetting process instance --- .../src/routes/ProcessInstanceShow.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx index 96ad1138..b4078155 100644 --- a/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx +++ b/spiffworkflow-frontend/src/routes/ProcessInstanceShow.tsx @@ -262,10 +262,14 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { return spiffStepLink(, 1); }; + const returnToLastSpiffStep = () => { + window.location.href = `/admin/process-instances/${params.process_model_id}/${params.process_instance_id}`; + }; + const resetProcessInstance = () => { HttpService.makeCallToBackend({ path: `${targetUris.processInstanceResetPath}/${currentSpiffStep()}`, - successCallback: refreshPage, + successCallback: returnToLastSpiffStep, httpMethod: 'POST', }); }; @@ -637,8 +641,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) { HttpService.makeCallToBackend({ path: `/task-complete/${modifiedProcessModelId}/${params.process_instance_id}/${taskToUse.id}`, httpMethod: 'POST', - successCallback: saveTaskDataResult, - failureCallback: saveTaskDataFailure, + successCallback: returnToLastSpiffStep, postBody: { execute }, }); }; From 99f980df5e8cbbf9192ab52291add0d795745633 Mon Sep 17 00:00:00 2001 From: Elizabeth Esswein Date: Fri, 30 Dec 2022 12:30:02 -0500 Subject: [PATCH 4/7] fix method overwritten by merge --- .../routes/process_instances_controller.py | 34 +++---------------- 1 file changed, 4 insertions(+), 30 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 08ec712e..3bb1b171 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/routes/process_instances_controller.py @@ -565,39 +565,13 @@ def process_instance_reset( modified_process_model_identifier: str, spiff_step: int = 0, ) -> flask.wrappers.Response: - """Process_instance_reset.""" + """Reset a process instance to a particular step.""" process_instance = ProcessInstanceService().get_process_instance( process_instance_id ) - step_detail = ( - db.session.query(SpiffStepDetailsModel) - .filter( - SpiffStepDetailsModel.process_instance_id == process_instance.id, - SpiffStepDetailsModel.spiff_step == spiff_step, - ) - .first() - ) - if step_detail is not None and process_instance.bpmn_json is not None: - bpmn_json = json.loads(process_instance.bpmn_json) - bpmn_json["tasks"] = step_detail.task_json["tasks"] - bpmn_json["subprocesses"] = step_detail.task_json["subprocesses"] - process_instance.bpmn_json = json.dumps(bpmn_json) - - db.session.add(process_instance) - try: - db.session.commit() - except Exception as e: - db.session.rollback() - raise ApiError( - error_code="reset_process_instance_error", - message=f"Could not update the Instance. Original error is {e}", - ) from e - - return Response( - json.dumps(ProcessInstanceModelSchema().dump(process_instance)), - status=200, - mimetype="application/json", - ) + processor = ProcessInstanceProcessor(process_instance) + processor.reset_process(spiff_step) + return Response(json.dumps({"ok": True}), status=200, mimetype="application/json") def _get_process_instance( From 56bc262fa960efc21673fa56a7759e4f8bd70e26 Mon Sep 17 00:00:00 2001 From: Elizabeth Esswein Date: Fri, 30 Dec 2022 15:17:35 -0500 Subject: [PATCH 5/7] remove reset tasks from human task table --- .../services/process_instance_processor.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) 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 842bca15..382f073a 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -732,7 +732,6 @@ class ProcessInstanceProcessor: def add_step(self, step: Union[dict, None] = None) -> None: """Add a spiff step.""" - self.increment_spiff_step() if step is None: step = self.spiff_step_details_mapping() db.session.add(SpiffStepDetailsModel(**step)) @@ -748,11 +747,12 @@ class ProcessInstanceProcessor: spiff_task.complete() else: spiff_logger = logging.getLogger("spiff") - spiff_logger.info(f"Skipped task", extra=spiff_task.log_info()) + spiff_logger.info(f"Skipped task {spiff_task.task_spec.name}", extra=spiff_task.log_info()) spiff_task._set_state(TaskState.COMPLETED) for child in spiff_task.children: child.task_spec._update(child) self.bpmn_process_instance.last_task = spiff_task + self.increment_spiff_step() self.add_step() self.save() # Saving the workflow seems to reset the status @@ -760,7 +760,6 @@ class ProcessInstanceProcessor: def reset_process(self, spiff_step: int) -> None: """Reset a process to an earlier state.""" - spiff_logger = logging.getLogger("spiff") spiff_logger.info( f"Process reset from step {spiff_step}", @@ -777,6 +776,7 @@ class ProcessInstanceProcessor: .first() ) if step_detail is not None: + self.increment_spiff_step() self.add_step( { "process_instance_id": self.process_instance_model.id, @@ -790,6 +790,15 @@ class ProcessInstanceProcessor: dct["tasks"] = step_detail.task_json["tasks"] dct["subprocesses"] = step_detail.task_json["subprocesses"] self.bpmn_process_instance = self._serializer.workflow_from_dict(dct) + + # Cascade does not seems to work on filters, only directly through the session + tasks = self.bpmn_process_instance.get_tasks(TaskState.NOT_FINISHED_MASK) + rows = HumanTaskModel.query.filter( + HumanTaskModel.task_id.in_(str(t.id) for t in tasks) # type: ignore + ).all() + for row in rows: + db.session.delete(row) + self.save() self.suspend() From 6531888f9322d4e43c268e48027b25db1bc73107 Mon Sep 17 00:00:00 2001 From: Elizabeth Esswein Date: Fri, 30 Dec 2022 15:40:46 -0500 Subject: [PATCH 6/7] reformat file --- .../services/process_instance_processor.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 382f073a..a7e0f9ca 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -747,7 +747,9 @@ class ProcessInstanceProcessor: spiff_task.complete() else: spiff_logger = logging.getLogger("spiff") - spiff_logger.info(f"Skipped task {spiff_task.task_spec.name}", extra=spiff_task.log_info()) + spiff_logger.info( + f"Skipped task {spiff_task.task_spec.name}", extra=spiff_task.log_info() + ) spiff_task._set_state(TaskState.COMPLETED) for child in spiff_task.children: child.task_spec._update(child) From 5b28092dd8d374b5069e9ac94bf2e37b9e9d470a Mon Sep 17 00:00:00 2001 From: jasquat Date: Thu, 5 Jan 2023 10:53:51 -0500 Subject: [PATCH 7/7] pyl w/ burnettk --- .../services/process_instance_processor.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 fe0d2277..5ef4baf0 100644 --- a/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py +++ b/spiffworkflow-backend/src/spiffworkflow_backend/services/process_instance_processor.py @@ -301,9 +301,7 @@ class ProcessInstanceProcessor: tld.spiff_step = process_instance_model.spiff_step # 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 = ( + current_app.config["THREAD_LOCAL_DATA"].process_model_identifier = ( f"{process_instance_model.process_model_identifier}" )