Merge pull request #88 from sartography/feature/process-nav-improvements

Feature/process nav improvements
This commit is contained in:
Kevin Burnett 2023-01-05 07:54:01 -08:00 committed by GitHub
commit 6459d13960
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 43 deletions

View File

@ -574,39 +574,13 @@ def process_instance_reset(
modified_process_model_identifier: str, modified_process_model_identifier: str,
spiff_step: int = 0, spiff_step: int = 0,
) -> flask.wrappers.Response: ) -> flask.wrappers.Response:
"""Process_instance_reset.""" """Reset a process instance to a particular step."""
process_instance = ProcessInstanceService().get_process_instance( process_instance = ProcessInstanceService().get_process_instance(
process_instance_id process_instance_id
) )
step_detail = ( processor = ProcessInstanceProcessor(process_instance)
db.session.query(SpiffStepDetailsModel) processor.reset_process(spiff_step)
.filter( return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
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",
)
def _get_process_instance( def _get_process_instance(

View File

@ -646,7 +646,7 @@ class ProcessInstanceProcessor:
subprocesses_by_child_task_ids[task_id] = subprocess_id subprocesses_by_child_task_ids[task_id] = subprocess_id
return subprocesses_by_child_task_ids return subprocesses_by_child_task_ids
def _save(self) -> None: def save(self) -> None:
"""Saves the current state of this processor to the database.""" """Saves the current state of this processor to the database."""
self.process_instance_model.bpmn_json = self.serialize() self.process_instance_model.bpmn_json = self.serialize()
@ -668,9 +668,6 @@ class ProcessInstanceProcessor:
db.session.add(self.process_instance_model) db.session.add(self.process_instance_model)
db.session.commit() 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( human_tasks = HumanTaskModel.query.filter_by(
process_instance_id=self.process_instance_model.id process_instance_id=self.process_instance_model.id
).all() ).all()
@ -758,6 +755,13 @@ class ProcessInstanceProcessor:
self.bpmn_process_instance.catch(event_definition) self.bpmn_process_instance.catch(event_definition)
self.do_engine_steps(save=True) self.do_engine_steps(save=True)
def add_step(self, step: Union[dict, None] = None) -> None:
"""Add a 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: def manual_complete_task(self, task_id: str, execute: bool) -> None:
"""Mark the task complete optionally executing it.""" """Mark the task complete optionally executing it."""
spiff_task = self.bpmn_process_instance.get_task(UUID(task_id)) spiff_task = self.bpmn_process_instance.get_task(UUID(task_id))
@ -768,18 +772,64 @@ class ProcessInstanceProcessor:
) )
spiff_task.complete() spiff_task.complete()
else: else:
current_app.logger.info( spiff_logger = logging.getLogger("spiff")
f"Skipping Task {spiff_task.task_spec.name} of process instance" spiff_logger.info(
f" {self.process_instance_model.id}" f"Skipped task {spiff_task.task_spec.name}", extra=spiff_task.log_info()
) )
spiff_task._set_state(TaskState.COMPLETED) spiff_task._set_state(TaskState.COMPLETED)
for child in spiff_task.children: for child in spiff_task.children:
child.task_spec._update(child) child.task_spec._update(child)
self.bpmn_process_instance.last_task = spiff_task self.bpmn_process_instance.last_task = spiff_task
self._save() self.increment_spiff_step()
self.add_step()
self.save()
# Saving the workflow seems to reset the status # Saving the workflow seems to reset the status
self.suspend() 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.increment_spiff_step()
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)
# 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()
@staticmethod @staticmethod
def get_parser() -> MyCustomParser: def get_parser() -> MyCustomParser:
"""Get_parser.""" """Get_parser."""

View File

@ -269,10 +269,14 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
return spiffStepLink(<CaretRight />, 1); return spiffStepLink(<CaretRight />, 1);
}; };
const returnToLastSpiffStep = () => {
window.location.href = `/admin/process-instances/${params.process_model_id}/${params.process_instance_id}`;
};
const resetProcessInstance = () => { const resetProcessInstance = () => {
HttpService.makeCallToBackend({ HttpService.makeCallToBackend({
path: `${targetUris.processInstanceResetPath}/${currentSpiffStep()}`, path: `${targetUris.processInstanceResetPath}/${currentSpiffStep()}`,
successCallback: refreshPage, successCallback: returnToLastSpiffStep,
httpMethod: 'POST', httpMethod: 'POST',
}); });
}; };
@ -647,8 +651,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
HttpService.makeCallToBackend({ HttpService.makeCallToBackend({
path: `/task-complete/${modifiedProcessModelId}/${params.process_instance_id}/${taskToUse.id}`, path: `/task-complete/${modifiedProcessModelId}/${params.process_instance_id}/${taskToUse.id}`,
httpMethod: 'POST', httpMethod: 'POST',
successCallback: saveTaskDataResult, successCallback: returnToLastSpiffStep,
failureCallback: saveTaskDataFailure,
postBody: { execute }, postBody: { execute },
}); });
}; };
@ -727,7 +730,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
data-qa="mark-task-complete-button" data-qa="mark-task-complete-button"
onClick={() => completeTask(false)} onClick={() => completeTask(false)}
> >
Mark Complete Skip Task
</Button> </Button>
); );
buttons.push( buttons.push(
@ -755,7 +758,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
data-qa="reset-process-button" data-qa="reset-process-button"
onClick={() => resetProcessInstance()} onClick={() => resetProcessInstance()}
> >
Resume Process Here Reset Process Here
</Button> </Button>
); );
} }