some updates so task_show no longer needs the processor. i think it mostly works w/ burnettk
This commit is contained in:
parent
431fde71bc
commit
5a561fb833
|
@ -69,6 +69,17 @@ class TaskModel(SpiffworkflowBaseDBModel):
|
|||
|
||||
data: Optional[dict] = None
|
||||
|
||||
# these are here to be compatible with task api
|
||||
form_schema: Optional[dict] = None
|
||||
form_ui_schema: Optional[dict] = None
|
||||
process_model_display_name: Optional[str] = None
|
||||
process_model_identifier: Optional[str] = None
|
||||
type: Optional[str] = None
|
||||
can_complete: Optional[bool] = None
|
||||
|
||||
def get_data(self) -> dict:
|
||||
return {**self.python_env_data(), **self.json_data()}
|
||||
|
||||
def python_env_data(self) -> dict:
|
||||
return JsonDataModel.find_data_dict_by_hash(self.python_env_data_hash)
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""APIs for dealing with process groups, process models, and process instances."""
|
||||
import json
|
||||
from spiffworkflow_backend.services.authorization_service import UserDoesNotHaveAccessToTaskError
|
||||
from spiffworkflow_backend.services.authorization_service import HumanTaskNotFoundError
|
||||
import os
|
||||
import uuid
|
||||
from sys import exc_info
|
||||
|
@ -283,39 +285,67 @@ def task_show(process_instance_id: int, task_guid: str = "next") -> flask.wrappe
|
|||
|
||||
form_schema_file_name = ""
|
||||
form_ui_schema_file_name = ""
|
||||
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
if task_guid == "next":
|
||||
spiff_task = processor.next_task()
|
||||
task_guid = spiff_task.id
|
||||
else:
|
||||
spiff_task = _get_spiff_task_from_process_instance(task_guid, process_instance, processor=processor)
|
||||
spiff_task = _get_spiff_task_from_process_instance(task_guid, process_instance, processor=processor)
|
||||
extensions = spiff_task.task_spec.extensions
|
||||
|
||||
task_model = _get_task_model_from_guid_or_raise(task_guid, process_instance_id)
|
||||
# extensions = task_model.properties_json['extensions'] if 'extensions' in task_model.properties_json else {}
|
||||
|
||||
if "properties" in extensions:
|
||||
properties = extensions["properties"]
|
||||
if "formJsonSchemaFilename" in properties:
|
||||
form_schema_file_name = properties["formJsonSchemaFilename"]
|
||||
if "formUiSchemaFilename" in properties:
|
||||
form_ui_schema_file_name = properties["formUiSchemaFilename"]
|
||||
|
||||
can_complete = False
|
||||
try:
|
||||
AuthorizationService.assert_user_can_complete_task(
|
||||
process_instance.id, task_model.task_definition.bpmn_identifier, g.user
|
||||
)
|
||||
can_complete = True
|
||||
except HumanTaskNotFoundError:
|
||||
can_complete = False
|
||||
except UserDoesNotHaveAccessToTaskError:
|
||||
can_complete = False
|
||||
|
||||
task = ProcessInstanceService.spiff_task_to_api_task(processor, spiff_task)
|
||||
task.data = spiff_task.data
|
||||
task.process_model_display_name = process_model.display_name
|
||||
task.process_model_identifier = process_model.id
|
||||
|
||||
# task.data
|
||||
# task.form_schema
|
||||
# task.form_ui_schema
|
||||
# task.id
|
||||
# task.process_model_display_name
|
||||
# task.process_model_identifier
|
||||
# task.state
|
||||
# task.type
|
||||
|
||||
task_model.data = task_model.get_data()
|
||||
task_model.process_model_display_name = process_model.display_name
|
||||
task_model.process_model_identifier = process_model.id
|
||||
task_model.type = task_model.task_definition.typename
|
||||
task_model.can_complete = can_complete
|
||||
task_process_identifier = task_model.bpmn_process.bpmn_process_definition.bpmn_identifier
|
||||
|
||||
process_model_with_form = process_model
|
||||
|
||||
refs = SpecFileService.get_references_for_process(process_model_with_form)
|
||||
all_processes = [i.identifier for i in refs]
|
||||
if task.process_identifier not in all_processes:
|
||||
top_process_name = processor.find_process_model_process_name_by_task_name(task.process_identifier)
|
||||
if task_process_identifier not in all_processes:
|
||||
top_bpmn_process = TaskService.bpmn_process_for_called_activity_or_top_level_process(task_model)
|
||||
bpmn_file_full_path = ProcessInstanceProcessor.bpmn_file_full_path_from_bpmn_process_identifier(
|
||||
top_process_name
|
||||
top_bpmn_process.bpmn_process_definition.bpmn_identifier
|
||||
)
|
||||
relative_path = os.path.relpath(bpmn_file_full_path, start=FileSystemService.root_path())
|
||||
process_model_relative_path = os.path.dirname(relative_path)
|
||||
process_model_with_form = ProcessModelService.get_process_model_from_relative_path(process_model_relative_path)
|
||||
|
||||
if task.type == "User Task":
|
||||
if task_model.task_definition.typename == "UserTask":
|
||||
if not form_schema_file_name:
|
||||
raise (
|
||||
ApiError(
|
||||
|
@ -330,37 +360,38 @@ def task_show(process_instance_id: int, task_guid: str = "next") -> flask.wrappe
|
|||
|
||||
form_dict = _prepare_form_data(
|
||||
form_schema_file_name,
|
||||
spiff_task,
|
||||
task_model,
|
||||
process_model_with_form,
|
||||
)
|
||||
|
||||
if task.data:
|
||||
_update_form_schema_with_task_data_as_needed(form_dict, task, spiff_task)
|
||||
if task_model.data:
|
||||
_update_form_schema_with_task_data_as_needed(form_dict, task_model)
|
||||
|
||||
if form_dict:
|
||||
task.form_schema = form_dict
|
||||
task_model.form_schema = form_dict
|
||||
|
||||
if form_ui_schema_file_name:
|
||||
ui_form_contents = _prepare_form_data(
|
||||
form_ui_schema_file_name,
|
||||
task,
|
||||
task_model,
|
||||
process_model_with_form,
|
||||
)
|
||||
if ui_form_contents:
|
||||
task.form_ui_schema = ui_form_contents
|
||||
task_model.form_ui_schema = ui_form_contents
|
||||
|
||||
_munge_form_ui_schema_based_on_hidden_fields_in_task_data(task)
|
||||
_render_instructions_for_end_user(spiff_task, task)
|
||||
return make_response(jsonify(task), 200)
|
||||
_munge_form_ui_schema_based_on_hidden_fields_in_task_data(task_model)
|
||||
_render_instructions_for_end_user(task_model)
|
||||
return make_response(jsonify(task_model), 200)
|
||||
|
||||
|
||||
def _render_instructions_for_end_user(spiff_task: SpiffTask, task: Task) -> str:
|
||||
def _render_instructions_for_end_user(task_model: TaskModel) -> str:
|
||||
"""Assure any instructions for end user are processed for jinja syntax."""
|
||||
if task.properties and "instructionsForEndUser" in task.properties:
|
||||
if task.properties["instructionsForEndUser"]:
|
||||
extensions = task_model.properties_json['extensions'] if 'extensions' in task_model.properties_json else {}
|
||||
if extensions and "instructionsForEndUser" in extensions:
|
||||
if extensions["instructionsForEndUser"]:
|
||||
try:
|
||||
instructions = _render_jinja_template(task.properties["instructionsForEndUser"], spiff_task)
|
||||
task.properties["instructionsForEndUser"] = instructions
|
||||
instructions = _render_jinja_template(extensions["instructionsForEndUser"], task_model)
|
||||
extensions["instructionsForEndUser"] = instructions
|
||||
return instructions
|
||||
except WorkflowTaskException as wfe:
|
||||
wfe.add_note("Failed to render instructions for end user.")
|
||||
|
@ -397,10 +428,12 @@ def _interstitial_stream(process_instance_id: int) -> Generator[str, Optional[st
|
|||
processor = ProcessInstanceProcessor(process_instance)
|
||||
reported_ids = [] # bit of an issue with end tasks showing as getting completed twice.
|
||||
spiff_task = processor.next_task()
|
||||
task_model = TaskModel.query.filter_by(guid=str(spiff_task.id)).first()
|
||||
last_task = None
|
||||
while last_task != spiff_task:
|
||||
# import pdb; pdb.set_trace()
|
||||
task = ProcessInstanceService.spiff_task_to_api_task(processor, processor.next_task())
|
||||
instructions = _render_instructions_for_end_user(spiff_task, task)
|
||||
instructions = _render_instructions_for_end_user(task_model)
|
||||
if instructions and spiff_task.id not in reported_ids:
|
||||
reported_ids.append(spiff_task.id)
|
||||
yield f"data: {current_app.json.dumps(task)} \n\n"
|
||||
|
@ -408,6 +441,9 @@ def _interstitial_stream(process_instance_id: int) -> Generator[str, Optional[st
|
|||
processor.do_engine_steps(execution_strategy_name="run_until_user_message")
|
||||
processor.do_engine_steps(execution_strategy_name="one_at_a_time")
|
||||
spiff_task = processor.next_task()
|
||||
task_model = TaskModel.query.filter_by(guid=str(spiff_task.id)).first()
|
||||
# print(f"spiff_task: {spiff_task}")
|
||||
# print(f"last_task: {last_task}")
|
||||
# Note, this has to be done in case someone leaves the page,
|
||||
# which can otherwise cancel this function and leave completed tasks un-registered.
|
||||
processor.save() # Fixme - maybe find a way not to do this on every loop?
|
||||
|
@ -446,7 +482,7 @@ def _task_submit_shared(
|
|||
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
spiff_task = _get_spiff_task_from_process_instance(task_guid, process_instance, processor=processor)
|
||||
AuthorizationService.assert_user_can_complete_spiff_task(process_instance.id, spiff_task, principal.user)
|
||||
AuthorizationService.assert_user_can_complete_task(process_instance.id, spiff_task.task_spec.name, principal.user)
|
||||
|
||||
if spiff_task.state != TaskState.READY:
|
||||
raise (
|
||||
|
@ -634,14 +670,14 @@ def _get_tasks(
|
|||
return make_response(jsonify(response_json), 200)
|
||||
|
||||
|
||||
def _prepare_form_data(form_file: str, spiff_task: SpiffTask, process_model: ProcessModelInfo) -> dict:
|
||||
def _prepare_form_data(form_file: str, task_model: TaskModel, process_model: ProcessModelInfo) -> dict:
|
||||
"""Prepare_form_data."""
|
||||
if spiff_task.data is None:
|
||||
if task_model.data is None:
|
||||
return {}
|
||||
|
||||
file_contents = SpecFileService.get_data(process_model, form_file).decode("utf-8")
|
||||
try:
|
||||
form_contents = _render_jinja_template(file_contents, spiff_task)
|
||||
form_contents = _render_jinja_template(file_contents, task_model)
|
||||
try:
|
||||
# form_contents is a str
|
||||
hot_dict: dict = json.loads(form_contents)
|
||||
|
@ -661,14 +697,14 @@ def _prepare_form_data(form_file: str, spiff_task: SpiffTask, process_model: Pro
|
|||
raise api_error
|
||||
|
||||
|
||||
def _render_jinja_template(unprocessed_template: str, spiff_task: SpiffTask) -> str:
|
||||
def _render_jinja_template(unprocessed_template: str, task_model: TaskModel) -> str:
|
||||
"""Render_jinja_template."""
|
||||
jinja_environment = jinja2.Environment(autoescape=True, lstrip_blocks=True, trim_blocks=True)
|
||||
try:
|
||||
template = jinja_environment.from_string(unprocessed_template)
|
||||
return template.render(**spiff_task.data)
|
||||
return template.render(**(task_model.data or {}))
|
||||
except jinja2.exceptions.TemplateError as template_error:
|
||||
wfe = WorkflowTaskException(str(template_error), task=spiff_task, exception=template_error)
|
||||
wfe = WorkflowTaskException(str(template_error), task=task_model, exception=template_error)
|
||||
if isinstance(template_error, TemplateSyntaxError):
|
||||
wfe.line_number = template_error.lineno
|
||||
wfe.error_line = template_error.source.split("\n")[template_error.lineno - 1]
|
||||
|
@ -676,7 +712,7 @@ def _render_jinja_template(unprocessed_template: str, spiff_task: SpiffTask) ->
|
|||
raise wfe from template_error
|
||||
except Exception as error:
|
||||
_type, _value, tb = exc_info()
|
||||
wfe = WorkflowTaskException(str(error), task=spiff_task, exception=error)
|
||||
wfe = WorkflowTaskException(str(error), task=task_model, exception=error)
|
||||
while tb:
|
||||
if tb.tb_frame.f_code.co_filename == "<template>":
|
||||
wfe.line_number = tb.tb_lineno
|
||||
|
@ -709,9 +745,9 @@ def _get_spiff_task_from_process_instance(
|
|||
|
||||
|
||||
# originally from: https://bitcoden.com/answers/python-nested-dictionary-update-value-where-any-nested-key-matches
|
||||
def _update_form_schema_with_task_data_as_needed(in_dict: dict, task: Task, spiff_task: SpiffTask) -> None:
|
||||
def _update_form_schema_with_task_data_as_needed(in_dict: dict, task_model: TaskModel) -> None:
|
||||
"""Update_nested."""
|
||||
if task.data is None:
|
||||
if task_model.data is None:
|
||||
return None
|
||||
|
||||
for k, value in in_dict.items():
|
||||
|
@ -724,25 +760,18 @@ def _update_form_schema_with_task_data_as_needed(in_dict: dict, task: Task, spif
|
|||
if first_element_in_value_list.startswith("options_from_task_data_var:"):
|
||||
task_data_var = first_element_in_value_list.replace("options_from_task_data_var:", "")
|
||||
|
||||
if task_data_var not in task.data:
|
||||
wte = WorkflowTaskException(
|
||||
(
|
||||
"Error building form. Attempting to create a"
|
||||
" selection list with options from variable"
|
||||
f" '{task_data_var}' but it doesn't exist in"
|
||||
" the Task Data."
|
||||
),
|
||||
task=spiff_task,
|
||||
if task_data_var not in task_model.data:
|
||||
message = (
|
||||
"Error building form. Attempting to create a selection list with options from variable"
|
||||
f" '{task_data_var}' but it doesn't exist in the Task Data."
|
||||
)
|
||||
raise (
|
||||
ApiError.from_workflow_exception(
|
||||
error_code="missing_task_data_var",
|
||||
message=str(wte),
|
||||
exp=wte,
|
||||
)
|
||||
raise ApiError(
|
||||
error_code="missing_task_data_var",
|
||||
message=message,
|
||||
status_code=500,
|
||||
)
|
||||
|
||||
select_options_from_task_data = task.data.get(task_data_var)
|
||||
select_options_from_task_data = task_model.data.get(task_data_var)
|
||||
if isinstance(select_options_from_task_data, list):
|
||||
if all("value" in d and "label" in d for d in select_options_from_task_data):
|
||||
|
||||
|
@ -762,11 +791,11 @@ def _update_form_schema_with_task_data_as_needed(in_dict: dict, task: Task, spif
|
|||
|
||||
in_dict[k] = options_for_react_json_schema_form
|
||||
elif isinstance(value, dict):
|
||||
_update_form_schema_with_task_data_as_needed(value, task, spiff_task)
|
||||
_update_form_schema_with_task_data_as_needed(value, task_model)
|
||||
elif isinstance(value, list):
|
||||
for o in value:
|
||||
if isinstance(o, dict):
|
||||
_update_form_schema_with_task_data_as_needed(o, task, spiff_task)
|
||||
_update_form_schema_with_task_data_as_needed(o, task_model)
|
||||
|
||||
|
||||
def _get_potential_owner_usernames(assigned_user: AliasedClass) -> Any:
|
||||
|
@ -811,15 +840,15 @@ def _find_human_task_or_raise(
|
|||
return human_task
|
||||
|
||||
|
||||
def _munge_form_ui_schema_based_on_hidden_fields_in_task_data(task: Task) -> None:
|
||||
if task.form_ui_schema is None:
|
||||
task.form_ui_schema = {}
|
||||
def _munge_form_ui_schema_based_on_hidden_fields_in_task_data(task_model: TaskModel) -> None:
|
||||
if task_model.form_ui_schema is None:
|
||||
task_model.form_ui_schema = {}
|
||||
|
||||
if task.data and "form_ui_hidden_fields" in task.data:
|
||||
hidden_fields = task.data["form_ui_hidden_fields"]
|
||||
if task_model.data and "form_ui_hidden_fields" in task_model.data:
|
||||
hidden_fields = task_model.data["form_ui_hidden_fields"]
|
||||
for hidden_field in hidden_fields:
|
||||
hidden_field_parts = hidden_field.split(".")
|
||||
relevant_depth_of_ui_schema = task.form_ui_schema
|
||||
relevant_depth_of_ui_schema = task_model.form_ui_schema
|
||||
for ii, hidden_field_part in enumerate(hidden_field_parts):
|
||||
if hidden_field_part not in relevant_depth_of_ui_schema:
|
||||
relevant_depth_of_ui_schema[hidden_field_part] = {}
|
||||
|
|
|
@ -412,27 +412,27 @@ class AuthorizationService:
|
|||
) from exception
|
||||
|
||||
@staticmethod
|
||||
def assert_user_can_complete_spiff_task(
|
||||
def assert_user_can_complete_task(
|
||||
process_instance_id: int,
|
||||
spiff_task: SpiffTask,
|
||||
task_bpmn_identifier: str,
|
||||
user: UserModel,
|
||||
) -> bool:
|
||||
"""Assert_user_can_complete_spiff_task."""
|
||||
human_task = HumanTaskModel.query.filter_by(
|
||||
task_name=spiff_task.task_spec.name,
|
||||
task_name=task_bpmn_identifier,
|
||||
process_instance_id=process_instance_id,
|
||||
completed=False,
|
||||
).first()
|
||||
if human_task is None:
|
||||
raise HumanTaskNotFoundError(
|
||||
f"Could find an human task with task name '{spiff_task.task_spec.name}'"
|
||||
f"Could find an human task with task name '{task_bpmn_identifier}'"
|
||||
f" for process instance '{process_instance_id}'"
|
||||
)
|
||||
|
||||
if user not in human_task.potential_owners:
|
||||
raise UserDoesNotHaveAccessToTaskError(
|
||||
f"User {user.username} does not have access to update"
|
||||
f" task'{spiff_task.task_spec.name}' for process instance"
|
||||
f" task'{task_bpmn_identifier}' for process instance"
|
||||
f" '{process_instance_id}'"
|
||||
)
|
||||
return True
|
||||
|
|
|
@ -1793,10 +1793,10 @@ class ProcessInstanceProcessor:
|
|||
|
||||
# If there are no ready tasks, but the thing isn't complete yet, find the first non-complete task
|
||||
# and return that
|
||||
next_task = None
|
||||
next_task_to_return = None
|
||||
for task in SpiffTask.Iterator(self.bpmn_process_instance.task_tree, TaskState.NOT_FINISHED_MASK):
|
||||
next_task = task
|
||||
return next_task
|
||||
next_task_to_return = task
|
||||
return next_task_to_return
|
||||
|
||||
def completed_user_tasks(self) -> List[SpiffTask]:
|
||||
"""Completed_user_tasks."""
|
||||
|
|
|
@ -344,7 +344,7 @@ class ProcessInstanceService:
|
|||
data: dict[str, Any],
|
||||
user: UserModel,
|
||||
) -> None:
|
||||
AuthorizationService.assert_user_can_complete_spiff_task(process_instance.id, spiff_task, user)
|
||||
AuthorizationService.assert_user_can_complete_task(process_instance.id, spiff_task.task_spec.name, user)
|
||||
cls.save_file_data_and_replace_with_digest_references(
|
||||
data,
|
||||
process_instance.id,
|
||||
|
@ -442,8 +442,8 @@ class ProcessInstanceService:
|
|||
# can complete it.
|
||||
can_complete = False
|
||||
try:
|
||||
AuthorizationService.assert_user_can_complete_spiff_task(
|
||||
processor.process_instance_model.id, spiff_task, g.user
|
||||
AuthorizationService.assert_user_can_complete_task(
|
||||
processor.process_instance_model.id, spiff_task.task_spec.name, g.user
|
||||
)
|
||||
can_complete = True
|
||||
except HumanTaskNotFoundError:
|
||||
|
|
|
@ -488,6 +488,17 @@ class TaskService:
|
|||
setattr(task_model, task_model_data_column, task_data_hash)
|
||||
return json_data_dict
|
||||
|
||||
@classmethod
|
||||
def bpmn_process_for_called_activity_or_top_level_process(cls, task_model: TaskModel) -> BpmnProcessModel:
|
||||
"""Returns either the bpmn process for the call activity calling the process or the top level bpmn process.
|
||||
|
||||
For example, process_modelA has processA which has a call activity that calls processB which is inside of process_modelB.
|
||||
processB has subprocessA which has taskA. Using taskA this method should return processB and then that can be used with
|
||||
the spec reference cache to find process_modelB.
|
||||
"""
|
||||
(bpmn_processes, _task_models) = TaskService.task_models_of_parent_bpmn_processes(task_model, stop_on_first_call_activity=True)
|
||||
return bpmn_processes[0]
|
||||
|
||||
@classmethod
|
||||
def bpmn_process_and_descendants(cls, bpmn_processes: list[BpmnProcessModel]) -> list[BpmnProcessModel]:
|
||||
bpmn_process_ids = [p.id for p in bpmn_processes]
|
||||
|
@ -500,27 +511,51 @@ class TaskService:
|
|||
|
||||
@classmethod
|
||||
def task_models_of_parent_bpmn_processes(
|
||||
cls, task_model: TaskModel
|
||||
cls, task_model: TaskModel, stop_on_first_call_activity: Optional[bool] = False
|
||||
) -> Tuple[list[BpmnProcessModel], list[TaskModel]]:
|
||||
"""Returns the list of task models that are associated with the paren bpmn process.
|
||||
|
||||
Example: TopLevelProcess has SubprocessTaskA which has CallActivityTaskA which has ScriptTaskA.
|
||||
SubprocessTaskA corresponds to SpiffSubprocess1.
|
||||
CallActivityTaskA corresponds to SpiffSubprocess2.
|
||||
Using ScriptTaskA this will return:
|
||||
(
|
||||
[TopLevelProcess, SpiffSubprocess1, SpiffSubprocess2],
|
||||
[SubprocessTaskA, CallActivityTaskA]
|
||||
)
|
||||
|
||||
If stop_on_first_call_activity it will stop when it reaches the first task model with a type of 'CallActivity'.
|
||||
This will change the return value in the example to:
|
||||
(
|
||||
[SpiffSubprocess2],
|
||||
[CallActivityTaskA]
|
||||
)
|
||||
"""
|
||||
bpmn_process = task_model.bpmn_process
|
||||
task_models: list[TaskModel] = []
|
||||
bpmn_processes: list[BpmnProcessModel] = [bpmn_process]
|
||||
if bpmn_process.guid is not None:
|
||||
parent_task_model = TaskModel.query.filter_by(guid=bpmn_process.guid).first()
|
||||
if parent_task_model is not None:
|
||||
b, t = cls.task_models_of_parent_bpmn_processes(parent_task_model)
|
||||
return (bpmn_processes + b, [parent_task_model] + t)
|
||||
task_models.append(parent_task_model)
|
||||
if not stop_on_first_call_activity or parent_task_model.task_definition.typename != 'CallActivity':
|
||||
if parent_task_model is not None:
|
||||
b, t = cls.task_models_of_parent_bpmn_processes(parent_task_model, stop_on_first_call_activity=stop_on_first_call_activity)
|
||||
return (b + bpmn_processes, t + task_models)
|
||||
return (bpmn_processes, task_models)
|
||||
|
||||
@classmethod
|
||||
def full_bpmn_process_path(cls, bpmn_process: BpmnProcessModel) -> list[str]:
|
||||
"""Returns a list of bpmn process identifiers pointing the given bpmn_process."""
|
||||
bpmn_process_identifiers: list[str] = [bpmn_process.bpmn_process_definition.bpmn_identifier]
|
||||
if bpmn_process.direct_parent_process_id is not None:
|
||||
parent_bpmn_process = BpmnProcessModel.query.filter_by(id=bpmn_process.direct_parent_process_id).first()
|
||||
if parent_bpmn_process is not None:
|
||||
# always prepend new identifiers since they come first in the path
|
||||
bpmn_process_identifiers = cls.full_bpmn_process_path(parent_bpmn_process) + bpmn_process_identifiers
|
||||
bpmn_process_identifiers: list[str] = []
|
||||
if bpmn_process.guid:
|
||||
task_model = TaskModel.query.filter_by(guid=bpmn_process.guid).first()
|
||||
(
|
||||
parent_bpmn_processes,
|
||||
_task_models_of_parent_bpmn_processes,
|
||||
) = TaskService.task_models_of_parent_bpmn_processes(task_model)
|
||||
for parent_bpmn_process in parent_bpmn_processes:
|
||||
bpmn_process_identifiers.append(parent_bpmn_process.bpmn_process_definition.bpmn_identifier)
|
||||
bpmn_process_identifiers.append(bpmn_process.bpmn_process_definition.bpmn_identifier)
|
||||
return bpmn_process_identifiers
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -4,40 +4,88 @@
|
|||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_1g3dpd7</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1g3dpd7" sourceRef="StartEvent_1" targetRef="do_nothing" />
|
||||
<bpmn:sequenceFlow id="Flow_1g3dpd7" sourceRef="StartEvent_1" targetRef="level_2b_script_task" />
|
||||
<bpmn:endEvent id="Event_18dla68">
|
||||
<bpmn:documentation># Main Workflow
|
||||
Hello {{my_other_var}}
|
||||
|
||||
</bpmn:documentation>
|
||||
<bpmn:incoming>Flow_0l0w6u9</bpmn:incoming>
|
||||
<bpmn:incoming>Flow_0wt4dbv</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_0l0w6u9" sourceRef="do_nothing" targetRef="Event_18dla68" />
|
||||
<bpmn:scriptTask id="do_nothing" name="Do Nothing">
|
||||
<bpmn:scriptTask id="level_2b_script_task" name="level_2b_script_task">
|
||||
<bpmn:incoming>Flow_1g3dpd7</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0l0w6u9</bpmn:outgoing>
|
||||
<bpmn:outgoing>Flow_1mvoqe4</bpmn:outgoing>
|
||||
<bpmn:script>a = 1</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
<bpmn:sequenceFlow id="Flow_1mvoqe4" sourceRef="level_2b_script_task" targetRef="level_2b_subprocess" />
|
||||
<bpmn:subProcess id="level_2b_subprocess" name="level_2b_subprocess">
|
||||
<bpmn:incoming>Flow_1mvoqe4</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0wt4dbv</bpmn:outgoing>
|
||||
<bpmn:startEvent id="Event_0fpb33c">
|
||||
<bpmn:outgoing>Flow_18nmqzh</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_18nmqzh" sourceRef="Event_0fpb33c" targetRef="level_2b_subprocess_script_task" />
|
||||
<bpmn:endEvent id="Event_1x11xe3">
|
||||
<bpmn:incoming>Flow_1srjuev</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1srjuev" sourceRef="level_2b_subprocess_script_task" targetRef="Event_1x11xe3" />
|
||||
<bpmn:scriptTask id="level_2b_subprocess_script_task" name="level_2b_subprocess_script_task">
|
||||
<bpmn:incoming>Flow_18nmqzh</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_1srjuev</bpmn:outgoing>
|
||||
<bpmn:script>z = 1</bpmn:script>
|
||||
</bpmn:scriptTask>
|
||||
</bpmn:subProcess>
|
||||
<bpmn:sequenceFlow id="Flow_0wt4dbv" sourceRef="level_2b_subprocess" targetRef="Event_18dla68" />
|
||||
</bpmn:process>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="Level2b">
|
||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_2" bpmnElement="StartEvent_1">
|
||||
<dc:Bounds x="179" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_18dla68_di" bpmnElement="Event_18dla68">
|
||||
<dc:Bounds x="432" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_1reqred_di" bpmnElement="do_nothing">
|
||||
<bpmndi:BPMNShape id="Activity_1reqred_di" bpmnElement="level_2b_script_task">
|
||||
<dc:Bounds x="260" y="77" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_18dla68_di" bpmnElement="Event_18dla68">
|
||||
<dc:Bounds x="592" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_1u9mmh7_di" bpmnElement="level_2b_subprocess">
|
||||
<dc:Bounds x="410" y="77" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_1g3dpd7_di" bpmnElement="Flow_1g3dpd7">
|
||||
<di:waypoint x="215" y="117" />
|
||||
<di:waypoint x="260" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0l0w6u9_di" bpmnElement="Flow_0l0w6u9">
|
||||
<bpmndi:BPMNEdge id="Flow_1mvoqe4_di" bpmnElement="Flow_1mvoqe4">
|
||||
<di:waypoint x="360" y="117" />
|
||||
<di:waypoint x="432" y="117" />
|
||||
<di:waypoint x="410" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_0wt4dbv_di" bpmnElement="Flow_0wt4dbv">
|
||||
<di:waypoint x="510" y="117" />
|
||||
<di:waypoint x="592" y="117" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
<bpmndi:BPMNDiagram id="BPMNDiagram_14p97s9">
|
||||
<bpmndi:BPMNPlane id="BPMNPlane_1qs3lh3" bpmnElement="level_2b_subprocess">
|
||||
<bpmndi:BPMNShape id="Event_0fpb33c_di" bpmnElement="Event_0fpb33c">
|
||||
<dc:Bounds x="332" y="212" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Event_1x11xe3_di" bpmnElement="Event_1x11xe3">
|
||||
<dc:Bounds x="572" y="212" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_0oiioqq_di" bpmnElement="level_2b_subprocess_script_task">
|
||||
<dc:Bounds x="420" y="190" width="100" height="80" />
|
||||
<bpmndi:BPMNLabel />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_18nmqzh_di" bpmnElement="Flow_18nmqzh">
|
||||
<di:waypoint x="368" y="230" />
|
||||
<di:waypoint x="420" y="230" />
|
||||
</bpmndi:BPMNEdge>
|
||||
<bpmndi:BPMNEdge id="Flow_1srjuev_di" bpmnElement="Flow_1srjuev">
|
||||
<di:waypoint x="520" y="230" />
|
||||
<di:waypoint x="572" y="230" />
|
||||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
<bpmn:startEvent id="StartEvent_1">
|
||||
<bpmn:outgoing>Flow_1g3dpd7</bpmn:outgoing>
|
||||
</bpmn:startEvent>
|
||||
<bpmn:sequenceFlow id="Flow_1g3dpd7" sourceRef="StartEvent_1" targetRef="do_nothing" />
|
||||
<bpmn:sequenceFlow id="Flow_0qdgvah" sourceRef="do_nothing" targetRef="Event_18dla68" />
|
||||
<bpmn:sequenceFlow id="Flow_1g3dpd7" sourceRef="StartEvent_1" targetRef="level_3_script_task" />
|
||||
<bpmn:sequenceFlow id="Flow_0qdgvah" sourceRef="level_3_script_task" targetRef="Event_18dla68" />
|
||||
<bpmn:endEvent id="Event_18dla68">
|
||||
<bpmn:documentation># Main Workflow
|
||||
Hello {{my_other_var}}
|
||||
|
@ -13,7 +13,7 @@ Hello {{my_other_var}}
|
|||
</bpmn:documentation>
|
||||
<bpmn:incoming>Flow_0qdgvah</bpmn:incoming>
|
||||
</bpmn:endEvent>
|
||||
<bpmn:scriptTask id="do_nothing" name="Do Nothing">
|
||||
<bpmn:scriptTask id="level_3_script_task" name="Do Nothing">
|
||||
<bpmn:incoming>Flow_1g3dpd7</bpmn:incoming>
|
||||
<bpmn:outgoing>Flow_0qdgvah</bpmn:outgoing>
|
||||
<bpmn:script>a = 3</bpmn:script>
|
||||
|
@ -27,7 +27,7 @@ Hello {{my_other_var}}
|
|||
<bpmndi:BPMNShape id="Event_18dla68_di" bpmnElement="Event_18dla68">
|
||||
<dc:Bounds x="432" y="99" width="36" height="36" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNShape id="Activity_1po21cu_di" bpmnElement="do_nothing">
|
||||
<bpmndi:BPMNShape id="Activity_1po21cu_di" bpmnElement="level_3_script_task">
|
||||
<dc:Bounds x="280" y="77" width="100" height="80" />
|
||||
</bpmndi:BPMNShape>
|
||||
<bpmndi:BPMNEdge id="Flow_1g3dpd7_di" bpmnElement="Flow_1g3dpd7">
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"description": "",
|
||||
"display_name": "call activity with nested calls",
|
||||
"display_order": 0,
|
||||
"exception_notification_addresses": [],
|
||||
"fault_or_suspend_on_exception": "fault",
|
||||
"files": [],
|
||||
"metadata_extraction_paths": null,
|
||||
"primary_file_name": "call_activity_nested.bpmn",
|
||||
"primary_process_id": "Level1"
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
{}
|
|
@ -29,12 +29,9 @@ class TestProcessModel(BaseTest):
|
|||
def test_can_run_process_model_with_call_activities_when_in_same_process_model_directory(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_super_admin_user: UserModel,
|
||||
) -> None:
|
||||
"""Test_can_run_process_model_with_call_activities."""
|
||||
self.create_process_group_with_api(client, with_super_admin_user, "test_group", "test_group")
|
||||
process_model = load_test_spec(
|
||||
"test_group/call_activity_test",
|
||||
# bpmn_file_name="call_activity_test.bpmn",
|
||||
|
@ -49,12 +46,9 @@ class TestProcessModel(BaseTest):
|
|||
def test_can_run_process_model_with_call_activities_when_not_in_same_directory(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_super_admin_user: UserModel,
|
||||
) -> None:
|
||||
"""Test_can_run_process_model_with_call_activities."""
|
||||
self.create_process_group_with_api(client, with_super_admin_user, "test_group", "test_group")
|
||||
process_model = load_test_spec(
|
||||
"test_group/call_activity_nested",
|
||||
process_model_source_directory="call_activity_nested",
|
||||
|
@ -80,12 +74,9 @@ class TestProcessModel(BaseTest):
|
|||
def test_can_run_process_model_with_call_activities_when_process_identifier_is_not_in_database(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_super_admin_user: UserModel,
|
||||
) -> None:
|
||||
"""Test_can_run_process_model_with_call_activities."""
|
||||
self.create_process_group_with_api(client, with_super_admin_user, "test_group", "test_group")
|
||||
process_model = load_test_spec(
|
||||
"test_group/call_activity_nested",
|
||||
process_model_source_directory="call_activity_nested",
|
||||
|
@ -116,9 +107,7 @@ class TestProcessModel(BaseTest):
|
|||
def test_extract_metadata(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_super_admin_user: UserModel,
|
||||
) -> None:
|
||||
"""Test_can_run_process_model_with_call_activities."""
|
||||
process_model = self.create_process_model_with_metadata()
|
||||
|
|
|
@ -14,12 +14,8 @@ class TestProcessModelService(BaseTest):
|
|||
def test_can_update_specified_attributes(
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_super_admin_user: UserModel,
|
||||
) -> None:
|
||||
"""Test_can_update_specified_attributes."""
|
||||
self.create_process_group_with_api(client, with_super_admin_user, "test_group", "test_group")
|
||||
process_model = load_test_spec(
|
||||
"test_group/hello_world",
|
||||
bpmn_file_name="hello_world.bpmn",
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
from flask import Flask
|
||||
from spiffworkflow_backend.models.task_definition import TaskDefinitionModel
|
||||
from spiffworkflow_backend.models.task import TaskModel # noqa: F401
|
||||
from spiffworkflow_backend.models.bpmn_process import BpmnProcessModel
|
||||
from flask.testing import FlaskClient
|
||||
from spiffworkflow_backend.models.bpmn_process_definition import BpmnProcessDefinitionModel
|
||||
from spiffworkflow_backend.services.process_instance_processor import ProcessInstanceProcessor
|
||||
from spiffworkflow_backend.services.task_service import TaskService
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
||||
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
|
||||
|
||||
class TestTaskService(BaseTest):
|
||||
|
||||
def test_can_get_full_bpmn_process_path(
|
||||
self,
|
||||
app: Flask,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
) -> None:
|
||||
process_model = load_test_spec(
|
||||
"test_group/call_activity_nested",
|
||||
process_model_source_directory="call_activity_nested",
|
||||
bpmn_file_name="call_activity_nested",
|
||||
)
|
||||
|
||||
bpmn_file_names = [
|
||||
"call_activity_level_2b",
|
||||
"call_activity_level_2",
|
||||
"call_activity_level_3",
|
||||
]
|
||||
for bpmn_file_name in bpmn_file_names:
|
||||
load_test_spec(
|
||||
f"test_group/{bpmn_file_name}",
|
||||
process_model_source_directory="call_activity_nested",
|
||||
bpmn_file_name=bpmn_file_name,
|
||||
)
|
||||
process_instance = self.create_process_instance_from_process_model(process_model)
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||
assert process_instance.status == "complete"
|
||||
|
||||
bpmn_process_level_2b = (
|
||||
BpmnProcessModel.query
|
||||
.join(BpmnProcessDefinitionModel)
|
||||
.filter(BpmnProcessDefinitionModel.bpmn_identifier == 'Level2b').first()
|
||||
)
|
||||
assert bpmn_process_level_2b is not None
|
||||
full_bpnmn_process_path = TaskService.full_bpmn_process_path(bpmn_process_level_2b)
|
||||
assert full_bpnmn_process_path == ['Level1', 'Level2', 'Level2b']
|
||||
|
||||
bpmn_process_level_3 = (
|
||||
BpmnProcessModel.query
|
||||
.join(BpmnProcessDefinitionModel)
|
||||
.filter(BpmnProcessDefinitionModel.bpmn_identifier == 'Level3').first()
|
||||
)
|
||||
assert bpmn_process_level_3 is not None
|
||||
full_bpnmn_process_path = TaskService.full_bpmn_process_path(bpmn_process_level_3)
|
||||
assert full_bpnmn_process_path == ['Level1', 'Level2', 'Level3']
|
||||
|
||||
def test_task_models_of_parent_bpmn_processes_stop_on_first_call_activity(
|
||||
self,
|
||||
app: Flask,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
) -> None:
|
||||
process_model = load_test_spec(
|
||||
"test_group/call_activity_nested",
|
||||
process_model_source_directory="call_activity_nested",
|
||||
bpmn_file_name="call_activity_nested",
|
||||
)
|
||||
|
||||
bpmn_file_names = [
|
||||
"call_activity_level_2b",
|
||||
"call_activity_level_2",
|
||||
"call_activity_level_3",
|
||||
]
|
||||
for bpmn_file_name in bpmn_file_names:
|
||||
load_test_spec(
|
||||
f"test_group/{bpmn_file_name}",
|
||||
process_model_source_directory="call_activity_nested",
|
||||
bpmn_file_name=bpmn_file_name,
|
||||
)
|
||||
process_instance = self.create_process_instance_from_process_model(process_model)
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||
assert process_instance.status == "complete"
|
||||
|
||||
task_model_level_2b = (
|
||||
TaskModel.query.join(TaskDefinitionModel)
|
||||
.filter(TaskDefinitionModel.bpmn_identifier == 'level_2b_subprocess_script_task').first()
|
||||
)
|
||||
assert task_model_level_2b is not None
|
||||
(bpmn_processes, task_models) = TaskService.task_models_of_parent_bpmn_processes(task_model_level_2b, stop_on_first_call_activity=True)
|
||||
assert len(bpmn_processes) == 2
|
||||
assert len(task_models) == 2
|
||||
assert bpmn_processes[0].bpmn_process_definition.bpmn_identifier == 'Level2b'
|
||||
assert task_models[0].task_definition.bpmn_identifier == 'level2b_second_call'
|
||||
|
||||
task_model_level_3 = (
|
||||
TaskModel.query.join(TaskDefinitionModel)
|
||||
.filter(TaskDefinitionModel.bpmn_identifier == 'level_3_script_task').first()
|
||||
)
|
||||
assert task_model_level_3 is not None
|
||||
(bpmn_processes, task_models) = TaskService.task_models_of_parent_bpmn_processes(task_model_level_3, stop_on_first_call_activity=True)
|
||||
assert len(bpmn_processes) == 1
|
||||
assert len(task_models) == 1
|
||||
assert bpmn_processes[0].bpmn_process_definition.bpmn_identifier == 'Level3'
|
||||
assert task_models[0].task_definition.bpmn_identifier == 'level3'
|
||||
|
||||
def test_bpmn_process_for_called_activity_or_top_level_process(
|
||||
self,
|
||||
app: Flask,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
) -> None:
|
||||
process_model = load_test_spec(
|
||||
"test_group/call_activity_nested",
|
||||
process_model_source_directory="call_activity_nested",
|
||||
bpmn_file_name="call_activity_nested",
|
||||
)
|
||||
|
||||
bpmn_file_names = [
|
||||
"call_activity_level_2b",
|
||||
"call_activity_level_2",
|
||||
"call_activity_level_3",
|
||||
]
|
||||
for bpmn_file_name in bpmn_file_names:
|
||||
load_test_spec(
|
||||
f"test_group/{bpmn_file_name}",
|
||||
process_model_source_directory="call_activity_nested",
|
||||
bpmn_file_name=bpmn_file_name,
|
||||
)
|
||||
process_instance = self.create_process_instance_from_process_model(process_model)
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||
assert process_instance.status == "complete"
|
||||
|
||||
task_model_level_2b = (
|
||||
TaskModel.query.join(TaskDefinitionModel)
|
||||
.filter(TaskDefinitionModel.bpmn_identifier == 'level_2b_subprocess_script_task').first()
|
||||
)
|
||||
assert task_model_level_2b is not None
|
||||
bpmn_process = TaskService.bpmn_process_for_called_activity_or_top_level_process(task_model_level_2b)
|
||||
assert bpmn_process is not None
|
||||
assert bpmn_process.bpmn_process_definition.bpmn_identifier == 'Level2b'
|
||||
|
||||
task_model_level_3 = (
|
||||
TaskModel.query.join(TaskDefinitionModel)
|
||||
.filter(TaskDefinitionModel.bpmn_identifier == 'level_3_script_task').first()
|
||||
)
|
||||
assert task_model_level_3 is not None
|
||||
bpmn_process = TaskService.bpmn_process_for_called_activity_or_top_level_process(task_model_level_3)
|
||||
assert bpmn_process.bpmn_process_definition.bpmn_identifier == 'Level3'
|
|
@ -8,7 +8,10 @@ export default function InstructionsForEndUser({ task }: any) {
|
|||
}
|
||||
let instructions =
|
||||
'There is no additional instructions or information for this task.';
|
||||
const { properties } = task;
|
||||
let { properties } = task;
|
||||
if (!properties) {
|
||||
properties = task.properties_json;
|
||||
}
|
||||
const { instructionsForEndUser } = properties;
|
||||
if (instructionsForEndUser) {
|
||||
instructions = instructionsForEndUser;
|
||||
|
|
|
@ -7,7 +7,6 @@ import MyTasks from './MyTasks';
|
|||
import CompletedInstances from './CompletedInstances';
|
||||
import CreateNewInstance from './CreateNewInstance';
|
||||
import InProgressInstances from './InProgressInstances';
|
||||
import ProcessInterstitial from './ProcessInterstitial';
|
||||
|
||||
export default function HomePageRoutes() {
|
||||
const location = useLocation();
|
||||
|
@ -56,10 +55,6 @@ export default function HomePageRoutes() {
|
|||
<Route path="my-tasks" element={<MyTasks />} />
|
||||
<Route path=":process_instance_id/:task_id" element={<TaskShow />} />
|
||||
<Route path="grouped" element={<InProgressInstances />} />
|
||||
<Route
|
||||
path="process/:process_instance_id/interstitial"
|
||||
element={<ProcessInterstitial />}
|
||||
/>
|
||||
<Route path="completed-instances" element={<CompletedInstances />} />
|
||||
<Route path="create-new-instance" element={<CreateNewInstance />} />
|
||||
</Routes>
|
||||
|
|
|
@ -21,6 +21,8 @@ export default function ProcessInterstitial() {
|
|||
return ['User Task', 'Manual Task'];
|
||||
}, []);
|
||||
|
||||
const processInstanceShowPageBaseUrl = `/admin/process-instances/for-me/${params.process_model_id}`;
|
||||
|
||||
useEffect(() => {
|
||||
fetchEventSource(
|
||||
`${BACKEND_BASE_URL}/tasks/${params.process_instance_id}`,
|
||||
|
@ -127,7 +129,10 @@ export default function ProcessInterstitial() {
|
|||
entityType: 'process-model-id',
|
||||
linkLastItem: true,
|
||||
},
|
||||
[`Process Instance Id: ${lastTask.process_instance_id}`],
|
||||
[
|
||||
`Process Instance: ${params.process_instance_id}`,
|
||||
`${processInstanceShowPageBaseUrl}/${params.process_instance_id}`,
|
||||
],
|
||||
]}
|
||||
/>
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
|
|
|
@ -6,7 +6,7 @@ export default function ProcessRoutes() {
|
|||
return (
|
||||
<Routes>
|
||||
<Route
|
||||
path=":process_model_identifier/:process_instance_id/interstitial"
|
||||
path=":process_model_id/:process_instance_id/interstitial"
|
||||
element={<ProcessInterstitial />}
|
||||
/>
|
||||
</Routes>
|
||||
|
|
Loading…
Reference in New Issue