fixed test w/ burnettk
This commit is contained in:
parent
d73baedcbe
commit
b1568fb472
|
@ -1,9 +1,7 @@
|
|||
"""APIs for dealing with process groups, process models, and process instances."""
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from sys import exc_info
|
||||
from typing import Any
|
||||
from typing import Dict
|
||||
|
@ -14,10 +12,11 @@ from typing import Union
|
|||
import flask.wrappers
|
||||
import jinja2
|
||||
import sentry_sdk
|
||||
from flask import current_app, stream_with_context
|
||||
from flask import current_app
|
||||
from flask import g
|
||||
from flask import jsonify
|
||||
from flask import make_response
|
||||
from flask import stream_with_context
|
||||
from flask.wrappers import Response
|
||||
from jinja2 import TemplateSyntaxError
|
||||
from SpiffWorkflow.exceptions import WorkflowTaskException # type: ignore
|
||||
|
@ -85,7 +84,7 @@ class ReactJsonSchemaSelectOption(TypedDict):
|
|||
|
||||
|
||||
def task_list_my_tasks(
|
||||
process_instance_id: Optional[int] = None, page: int = 1, per_page: int = 100
|
||||
process_instance_id: Optional[int] = None, page: int = 1, per_page: int = 100
|
||||
) -> flask.wrappers.Response:
|
||||
"""Task_list_my_tasks."""
|
||||
principal = _find_principal_or_raise()
|
||||
|
@ -166,7 +165,7 @@ def task_list_for_me(page: int = 1, per_page: int = 100) -> flask.wrappers.Respo
|
|||
|
||||
|
||||
def task_list_for_my_groups(
|
||||
user_group_identifier: Optional[str] = None, page: int = 1, per_page: int = 100
|
||||
user_group_identifier: Optional[str] = None, page: int = 1, per_page: int = 100
|
||||
) -> flask.wrappers.Response:
|
||||
"""Task_list_for_my_groups."""
|
||||
return _get_tasks(
|
||||
|
@ -178,9 +177,9 @@ def task_list_for_my_groups(
|
|||
|
||||
|
||||
def task_data_show(
|
||||
modified_process_model_identifier: str,
|
||||
process_instance_id: int,
|
||||
task_guid: str,
|
||||
modified_process_model_identifier: str,
|
||||
process_instance_id: int,
|
||||
task_guid: str,
|
||||
) -> flask.wrappers.Response:
|
||||
task_model = _get_task_model_from_guid_or_raise(task_guid, process_instance_id)
|
||||
task_model.data = task_model.json_data()
|
||||
|
@ -188,10 +187,10 @@ def task_data_show(
|
|||
|
||||
|
||||
def task_data_update(
|
||||
process_instance_id: str,
|
||||
modified_process_model_identifier: str,
|
||||
task_guid: str,
|
||||
body: Dict,
|
||||
process_instance_id: str,
|
||||
modified_process_model_identifier: str,
|
||||
task_guid: str,
|
||||
body: Dict,
|
||||
) -> Response:
|
||||
"""Update task data."""
|
||||
process_instance = ProcessInstanceModel.query.filter(ProcessInstanceModel.id == int(process_instance_id)).first()
|
||||
|
@ -241,10 +240,10 @@ def task_data_update(
|
|||
|
||||
|
||||
def manual_complete_task(
|
||||
modified_process_model_identifier: str,
|
||||
process_instance_id: str,
|
||||
task_guid: str,
|
||||
body: Dict,
|
||||
modified_process_model_identifier: str,
|
||||
process_instance_id: str,
|
||||
task_guid: str,
|
||||
body: Dict,
|
||||
) -> Response:
|
||||
"""Mark a task complete without executing it."""
|
||||
execute = body.get("execute", True)
|
||||
|
@ -359,9 +358,7 @@ def _render_instructions_for_end_user(spiff_task: SpiffTask, task: Task):
|
|||
if task.properties and "instructionsForEndUser" in task.properties:
|
||||
if task.properties["instructionsForEndUser"]:
|
||||
try:
|
||||
instructions = _render_jinja_template(
|
||||
task.properties["instructionsForEndUser"], spiff_task
|
||||
)
|
||||
instructions = _render_jinja_template(task.properties["instructionsForEndUser"], spiff_task)
|
||||
task.properties["instructionsForEndUser"] = instructions
|
||||
return instructions
|
||||
except WorkflowTaskException as wfe:
|
||||
|
@ -371,9 +368,9 @@ def _render_instructions_for_end_user(spiff_task: SpiffTask, task: Task):
|
|||
|
||||
|
||||
def process_data_show(
|
||||
process_instance_id: int,
|
||||
process_data_identifier: str,
|
||||
modified_process_model_identifier: str,
|
||||
process_instance_id: int,
|
||||
process_data_identifier: str,
|
||||
modified_process_model_identifier: str,
|
||||
) -> flask.wrappers.Response:
|
||||
"""Process_data_show."""
|
||||
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||
|
@ -408,7 +405,7 @@ def _interstitial_stream(process_instance_id: int):
|
|||
instructions = _render_instructions_for_end_user(spiff_task, task)
|
||||
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'
|
||||
yield f"data: {current_app.json.dumps(task)} \n\n"
|
||||
last_task = spiff_task
|
||||
processor.do_engine_steps(execution_strategy_name="run_until_user_message")
|
||||
processor.do_engine_steps(execution_strategy_name="one_at_a_time")
|
||||
|
@ -420,15 +417,15 @@ def _interstitial_stream(process_instance_id: int):
|
|||
|
||||
def interstitial(process_instance_id: int):
|
||||
"""A Server Side Events Stream for watching the execution of engine tasks in a
|
||||
process instance. """
|
||||
return Response(stream_with_context(_interstitial_stream(process_instance_id)), mimetype='text/event-stream')
|
||||
process instance."""
|
||||
return Response(stream_with_context(_interstitial_stream(process_instance_id)), mimetype="text/event-stream")
|
||||
|
||||
|
||||
def _task_submit_shared(
|
||||
process_instance_id: int,
|
||||
task_guid: str,
|
||||
body: Dict[str, Any],
|
||||
save_as_draft: bool = False,
|
||||
process_instance_id: int,
|
||||
task_guid: str,
|
||||
body: Dict[str, Any],
|
||||
save_as_draft: bool = False,
|
||||
) -> flask.wrappers.Response:
|
||||
principal = _find_principal_or_raise()
|
||||
process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
|
||||
|
@ -509,18 +506,24 @@ def _task_submit_shared(
|
|||
task = ProcessInstanceService.spiff_task_to_api_task(processor, processor.next_task())
|
||||
return make_response(jsonify(task), 200)
|
||||
|
||||
return Response(json.dumps(
|
||||
{"ok": True,
|
||||
"process_model_identifier": process_instance.process_model_identifier,
|
||||
"process_instance_id": process_instance_id
|
||||
}), status=202, mimetype="application/json")
|
||||
return Response(
|
||||
json.dumps(
|
||||
{
|
||||
"ok": True,
|
||||
"process_model_identifier": process_instance.process_model_identifier,
|
||||
"process_instance_id": process_instance_id,
|
||||
}
|
||||
),
|
||||
status=202,
|
||||
mimetype="application/json",
|
||||
)
|
||||
|
||||
|
||||
def task_submit(
|
||||
process_instance_id: int,
|
||||
task_guid: str,
|
||||
body: Dict[str, Any],
|
||||
save_as_draft: bool = False,
|
||||
process_instance_id: int,
|
||||
task_guid: str,
|
||||
body: Dict[str, Any],
|
||||
save_as_draft: bool = False,
|
||||
) -> flask.wrappers.Response:
|
||||
"""Task_submit_user_data."""
|
||||
with sentry_sdk.start_span(op="controller_action", description="tasks_controller.task_submit"):
|
||||
|
@ -528,11 +531,11 @@ def task_submit(
|
|||
|
||||
|
||||
def _get_tasks(
|
||||
processes_started_by_user: bool = True,
|
||||
has_lane_assignment_id: bool = True,
|
||||
page: int = 1,
|
||||
per_page: int = 100,
|
||||
user_group_identifier: Optional[str] = None,
|
||||
processes_started_by_user: bool = True,
|
||||
has_lane_assignment_id: bool = True,
|
||||
page: int = 1,
|
||||
per_page: int = 100,
|
||||
user_group_identifier: Optional[str] = None,
|
||||
) -> flask.wrappers.Response:
|
||||
"""Get_tasks."""
|
||||
user_id = g.user.id
|
||||
|
@ -679,9 +682,9 @@ def _render_jinja_template(unprocessed_template: str, spiff_task: SpiffTask) ->
|
|||
|
||||
|
||||
def _get_spiff_task_from_process_instance(
|
||||
task_guid: str,
|
||||
process_instance: ProcessInstanceModel,
|
||||
processor: Union[ProcessInstanceProcessor, None] = None,
|
||||
task_guid: str,
|
||||
process_instance: ProcessInstanceModel,
|
||||
processor: Union[ProcessInstanceProcessor, None] = None,
|
||||
) -> SpiffTask:
|
||||
"""Get_spiff_task_from_process_instance."""
|
||||
if processor is None:
|
||||
|
@ -737,8 +740,9 @@ def _update_form_schema_with_task_data_as_needed(in_dict: dict, task: Task, spif
|
|||
select_options_from_task_data = task.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):
|
||||
|
||||
def map_function(
|
||||
task_data_select_option: TaskDataSelectOption,
|
||||
task_data_select_option: TaskDataSelectOption,
|
||||
) -> ReactJsonSchemaSelectOption:
|
||||
"""Map_function."""
|
||||
return {
|
||||
|
@ -776,9 +780,9 @@ def _get_potential_owner_usernames(assigned_user: AliasedClass) -> Any:
|
|||
|
||||
|
||||
def _find_human_task_or_raise(
|
||||
process_instance_id: int,
|
||||
task_guid: str,
|
||||
only_tasks_that_can_be_completed: bool = False,
|
||||
process_instance_id: int,
|
||||
task_guid: str,
|
||||
only_tasks_that_can_be_completed: bool = False,
|
||||
) -> HumanTaskModel:
|
||||
if only_tasks_that_can_be_completed:
|
||||
human_task_query = HumanTaskModel.query.filter_by(
|
||||
|
|
|
@ -10,7 +10,8 @@ from typing import Tuple
|
|||
from urllib.parse import unquote
|
||||
|
||||
import sentry_sdk
|
||||
from flask import current_app, g
|
||||
from flask import current_app
|
||||
from flask import g
|
||||
from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import _BoundaryEventParent # type: ignore
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
|
||||
|
@ -26,8 +27,9 @@ from spiffworkflow_backend.models.process_instance_file_data import (
|
|||
from spiffworkflow_backend.models.process_model import ProcessModelInfo
|
||||
from spiffworkflow_backend.models.task import Task
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.services.authorization_service import AuthorizationService, HumanTaskNotFoundError, \
|
||||
UserDoesNotHaveAccessToTaskError
|
||||
from spiffworkflow_backend.services.authorization_service import AuthorizationService
|
||||
from spiffworkflow_backend.services.authorization_service import HumanTaskNotFoundError
|
||||
from spiffworkflow_backend.services.authorization_service import UserDoesNotHaveAccessToTaskError
|
||||
from spiffworkflow_backend.services.git_service import GitCommandError
|
||||
from spiffworkflow_backend.services.git_service import GitService
|
||||
from spiffworkflow_backend.services.process_instance_processor import (
|
||||
|
@ -427,12 +429,13 @@ 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_spiff_task(
|
||||
processor.process_instance_model.id, spiff_task, g.user
|
||||
)
|
||||
can_complete = True
|
||||
except HumanTaskNotFoundError as e:
|
||||
except HumanTaskNotFoundError:
|
||||
can_complete = False
|
||||
except UserDoesNotHaveAccessToTaskError as ude:
|
||||
except UserDoesNotHaveAccessToTaskError:
|
||||
can_complete = False
|
||||
|
||||
if hasattr(spiff_task.task_spec, "spec"):
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import copy
|
||||
import time
|
||||
from typing import Callable, List
|
||||
from typing import Callable
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
from typing import Set
|
||||
from uuid import UUID
|
||||
|
@ -50,11 +51,11 @@ class TaskModelSavingDelegate(EngineStepDelegate):
|
|||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
serializer: BpmnWorkflowSerializer,
|
||||
process_instance: ProcessInstanceModel,
|
||||
bpmn_definition_to_task_definitions_mappings: dict,
|
||||
secondary_engine_step_delegate: Optional[EngineStepDelegate] = None,
|
||||
self,
|
||||
serializer: BpmnWorkflowSerializer,
|
||||
process_instance: ProcessInstanceModel,
|
||||
bpmn_definition_to_task_definitions_mappings: dict,
|
||||
secondary_engine_step_delegate: Optional[EngineStepDelegate] = None,
|
||||
) -> None:
|
||||
self.secondary_engine_step_delegate = secondary_engine_step_delegate
|
||||
self.process_instance = process_instance
|
||||
|
@ -132,12 +133,12 @@ class TaskModelSavingDelegate(EngineStepDelegate):
|
|||
# excludes COMPLETED. the others were required to get PP1 to go to completion.
|
||||
# process FUTURE tasks because Boundary events are not processed otherwise.
|
||||
for waiting_spiff_task in bpmn_process_instance.get_tasks(
|
||||
TaskState.WAITING
|
||||
| TaskState.CANCELLED
|
||||
| TaskState.READY
|
||||
| TaskState.MAYBE
|
||||
| TaskState.LIKELY
|
||||
| TaskState.FUTURE
|
||||
TaskState.WAITING
|
||||
| TaskState.CANCELLED
|
||||
| TaskState.READY
|
||||
| TaskState.MAYBE
|
||||
| TaskState.LIKELY
|
||||
| TaskState.FUTURE
|
||||
):
|
||||
# these will be removed from the parent and then ignored
|
||||
if waiting_spiff_task._has_state(TaskState.PREDICTED_MASK):
|
||||
|
@ -267,17 +268,21 @@ class RunUntilServiceTaskExecutionStrategy(ExecutionStrategy):
|
|||
|
||||
class RunUntilUserTaskOrMessageExecutionStrategy(ExecutionStrategy):
|
||||
"""When you want to run tasks until you hit something to report to the end user, or
|
||||
until there are no other engine steps to complete."""
|
||||
until there are no other engine steps to complete."""
|
||||
|
||||
def get_engine_steps(self, bpmn_process_instance: BpmnWorkflow) -> List[SpiffTask]:
|
||||
return list([t for t in bpmn_process_instance.get_tasks(TaskState.READY) \
|
||||
if t.task_spec.spec_type not in ["User Task", "Manual Task"] and
|
||||
not (hasattr(t.task_spec, "extensions") and
|
||||
t.task_spec.extensions.get("instructionsForEndUser", None))
|
||||
])
|
||||
return list(
|
||||
[
|
||||
t
|
||||
for t in bpmn_process_instance.get_tasks(TaskState.READY)
|
||||
if t.task_spec.spec_type not in ["User Task", "Manual Task"]
|
||||
and not (
|
||||
hasattr(t.task_spec, "extensions") and t.task_spec.extensions.get("instructionsForEndUser", None)
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
def spiff_run(self, bpmn_process_instance: BpmnWorkflow, exit_at: None = None) -> None:
|
||||
|
||||
engine_steps = self.get_engine_steps(bpmn_process_instance)
|
||||
while engine_steps:
|
||||
for task in engine_steps:
|
||||
|
@ -320,12 +325,12 @@ class WorkflowExecutionService:
|
|||
"""Provides the driver code for workflow execution."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
bpmn_process_instance: BpmnWorkflow,
|
||||
process_instance_model: ProcessInstanceModel,
|
||||
execution_strategy: ExecutionStrategy,
|
||||
process_instance_completer: ProcessInstanceCompleter,
|
||||
process_instance_saver: ProcessInstanceSaver,
|
||||
self,
|
||||
bpmn_process_instance: BpmnWorkflow,
|
||||
process_instance_model: ProcessInstanceModel,
|
||||
execution_strategy: ExecutionStrategy,
|
||||
process_instance_completer: ProcessInstanceCompleter,
|
||||
process_instance_saver: ProcessInstanceSaver,
|
||||
):
|
||||
"""__init__."""
|
||||
self.bpmn_process_instance = bpmn_process_instance
|
||||
|
@ -402,12 +407,12 @@ class WorkflowExecutionService:
|
|||
for event in waiting_message_events:
|
||||
# Ensure we are only creating one message instance for each waiting message
|
||||
if (
|
||||
MessageInstanceModel.query.filter_by(
|
||||
process_instance_id=self.process_instance_model.id,
|
||||
message_type="receive",
|
||||
name=event["name"],
|
||||
).count()
|
||||
> 0
|
||||
MessageInstanceModel.query.filter_by(
|
||||
process_instance_id=self.process_instance_model.id,
|
||||
message_type="receive",
|
||||
name=event["name"],
|
||||
).count()
|
||||
> 0
|
||||
):
|
||||
continue
|
||||
|
||||
|
|
|
@ -120,4 +120,4 @@
|
|||
</bpmndi:BPMNEdge>
|
||||
</bpmndi:BPMNPlane>
|
||||
</bpmndi:BPMNDiagram>
|
||||
</bpmn:definitions>
|
||||
</bpmn:definitions>
|
||||
|
|
|
@ -3,14 +3,13 @@ from typing import Any
|
|||
|
||||
from flask.app import Flask
|
||||
from flask.testing import FlaskClient
|
||||
|
||||
from spiffworkflow_backend.routes.tasks_controller import _interstitial_stream
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
||||
|
||||
from spiffworkflow_backend import db
|
||||
from spiffworkflow_backend.models.human_task import HumanTaskModel
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.routes.tasks_controller import _interstitial_stream
|
||||
|
||||
|
||||
class TestForGoodErrors(BaseTest):
|
||||
|
@ -22,7 +21,6 @@ class TestForGoodErrors(BaseTest):
|
|||
client: FlaskClient,
|
||||
with_super_admin_user: UserModel,
|
||||
) -> Any:
|
||||
|
||||
# Call this to assure all engine-steps are fully processed before we search for human tasks.
|
||||
_interstitial_stream(process_instance_id)
|
||||
|
||||
|
|
|
@ -10,8 +10,6 @@ import pytest
|
|||
from flask.app import Flask
|
||||
from flask.testing import FlaskClient
|
||||
from SpiffWorkflow.task import TaskState # type: ignore
|
||||
|
||||
from spiffworkflow_backend.routes.tasks_controller import _interstitial_stream
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
||||
|
||||
|
@ -35,6 +33,7 @@ from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema
|
|||
from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
|
||||
from spiffworkflow_backend.models.task import TaskModel # noqa: F401
|
||||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.routes.tasks_controller import _interstitial_stream
|
||||
from spiffworkflow_backend.services.authorization_service import AuthorizationService
|
||||
from spiffworkflow_backend.services.file_system_service import FileSystemService
|
||||
from spiffworkflow_backend.services.process_instance_processor import (
|
||||
|
@ -1615,13 +1614,12 @@ class TestProcessApi(BaseTest):
|
|||
}
|
||||
|
||||
def test_interstitial_page(
|
||||
self,
|
||||
self,
|
||||
app: Flask,
|
||||
client: FlaskClient,
|
||||
with_db_and_bpmn_file_cleanup: None,
|
||||
with_super_admin_user: UserModel,
|
||||
) -> None:
|
||||
|
||||
process_group_id = "my_process_group"
|
||||
process_model_id = "interstitial"
|
||||
bpmn_file_location = "interstitial"
|
||||
|
@ -1649,23 +1647,24 @@ class TestProcessApi(BaseTest):
|
|||
|
||||
assert response.json is not None
|
||||
assert response.json["next_task"] is not None
|
||||
assert response.json["next_task"]["state"] == 'READY'
|
||||
assert response.json["next_task"]["title"] == 'Script Task #2'
|
||||
assert response.json["next_task"]["state"] == "READY"
|
||||
assert response.json["next_task"]["title"] == "Script Task #2"
|
||||
|
||||
# Rather that call the API and deal with the Server Side Events, call the loop directly and covert it to
|
||||
# a list. It tests all of our code. No reason to test Flasks SSE support.
|
||||
results = list(_interstitial_stream(process_instance_id))
|
||||
json_results = list(map(lambda x: json.loads(x[5:]), results)) # strip the "data:" prefix and convert remaining string to dict.
|
||||
# strip the "data:" prefix and convert remaining string to dict.
|
||||
json_results = list(map(lambda x: json.loads(x[5:]), results))
|
||||
# There should be 2 results back -
|
||||
# the first script task should not be returned (it contains no end user instructions)
|
||||
# The second script task should produce rendered jinja text
|
||||
# The Manual Task should then return a message as well.
|
||||
assert len(results) == 2
|
||||
assert json_results[0]["state"] == 'READY'
|
||||
assert json_results[0]["title"] == 'Script Task #2'
|
||||
assert json_results[0]["properties"]["instructionsForEndUser"] == 'I am Script Task 2'
|
||||
assert json_results[1]["state"] == 'READY'
|
||||
assert json_results[1]["title"] == 'Manual Task'
|
||||
assert json_results[0]["state"] == "READY"
|
||||
assert json_results[0]["title"] == "Script Task #2"
|
||||
assert json_results[0]["properties"]["instructionsForEndUser"] == "I am Script Task 2"
|
||||
assert json_results[1]["state"] == "READY"
|
||||
assert json_results[1]["title"] == "Manual Task"
|
||||
|
||||
response = client.put(
|
||||
f"/v1.0/tasks/{process_instance_id}/{json_results[1]['id']}",
|
||||
|
@ -1678,10 +1677,10 @@ class TestProcessApi(BaseTest):
|
|||
results = list(_interstitial_stream(process_instance_id))
|
||||
json_results = list(map(lambda x: json.loads(x[5:]), results))
|
||||
assert len(results) == 1
|
||||
assert json_results[0]["state"] == 'READY'
|
||||
assert json_results[0]["state"] == "READY"
|
||||
assert json_results[0]["can_complete"] == False
|
||||
assert json_results[0]["title"] == 'Please Approve'
|
||||
assert json_results[0]["properties"]["instructionsForEndUser"] == 'I am a manual task in another lane'
|
||||
assert json_results[0]["title"] == "Please Approve"
|
||||
assert json_results[0]["properties"]["instructionsForEndUser"] == "I am a manual task in another lane"
|
||||
|
||||
# Complete task as the finance user.
|
||||
response = client.put(
|
||||
|
@ -1690,13 +1689,13 @@ class TestProcessApi(BaseTest):
|
|||
)
|
||||
|
||||
# We should now be on the end task with a valid message, even after loading it many times.
|
||||
results_1 = list(_interstitial_stream(process_instance_id))
|
||||
results_2 = list(_interstitial_stream(process_instance_id))
|
||||
list(_interstitial_stream(process_instance_id))
|
||||
list(_interstitial_stream(process_instance_id))
|
||||
results = list(_interstitial_stream(process_instance_id))
|
||||
json_results = list(map(lambda x: json.loads(x[5:]), results))
|
||||
assert len(json_results) == 1
|
||||
assert json_results[0]["state"] == 'COMPLETED'
|
||||
assert json_results[0]["properties"]["instructionsForEndUser"] == 'I am the end task'
|
||||
assert json_results[0]["state"] == "COMPLETED"
|
||||
assert json_results[0]["properties"]["instructionsForEndUser"] == "I am the end task"
|
||||
|
||||
def test_process_instance_list_with_default_list(
|
||||
self,
|
||||
|
|
|
@ -405,7 +405,7 @@ class TestProcessInstanceProcessor(BaseTest):
|
|||
process_model=process_model, user=initiator_user
|
||||
)
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.do_engine_steps(save=True)
|
||||
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||
assert len(process_instance.active_human_tasks) == 1
|
||||
initial_human_task_id = process_instance.active_human_tasks[0].id
|
||||
|
||||
|
@ -436,7 +436,8 @@ class TestProcessInstanceProcessor(BaseTest):
|
|||
# recreate variables to ensure all bpmn json was recreated from scratch from the db
|
||||
process_instance_relookup = ProcessInstanceModel.query.filter_by(id=process_instance.id).first()
|
||||
processor_final = ProcessInstanceProcessor(process_instance_relookup)
|
||||
processor.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||
processor_final.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||
|
||||
assert process_instance_relookup.status == "complete"
|
||||
|
||||
data_set_1 = {"set_in_top_level_script": 1}
|
||||
|
@ -548,7 +549,6 @@ class TestProcessInstanceProcessor(BaseTest):
|
|||
# assert task_model.python_env_data() == expected_python_env_data, message
|
||||
assert task_model.json_data() == expected_python_env_data, message
|
||||
|
||||
processor_final.do_engine_steps(save=True, execution_strategy_name="greedy")
|
||||
all_spiff_tasks = processor_final.bpmn_process_instance.get_tasks()
|
||||
assert len(all_spiff_tasks) > 1
|
||||
for spiff_task in all_spiff_tasks:
|
||||
|
@ -607,7 +607,7 @@ class TestProcessInstanceProcessor(BaseTest):
|
|||
)
|
||||
assert task_models_that_are_predicted_count == 0
|
||||
|
||||
assert processor.get_data() == data_set_7
|
||||
assert processor_final.get_data() == data_set_7
|
||||
|
||||
def test_does_not_recreate_human_tasks_on_multiple_saves(
|
||||
self,
|
||||
|
|
|
@ -4477,11 +4477,6 @@
|
|||
"@lezer/common": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/fetch-event-source": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz",
|
||||
"integrity": "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA=="
|
||||
},
|
||||
"node_modules/@lezer/markdown": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.0.2.tgz",
|
||||
|
@ -4492,6 +4487,11 @@
|
|||
"@lezer/highlight": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@microsoft/fetch-event-source": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz",
|
||||
"integrity": "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA=="
|
||||
},
|
||||
"node_modules/@monaco-editor/loader": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.3.3.tgz",
|
||||
|
@ -35359,11 +35359,6 @@
|
|||
"@lezer/common": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"@microsoft/fetch-event-source": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz",
|
||||
"integrity": "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA=="
|
||||
},
|
||||
"@lezer/markdown": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@lezer/markdown/-/markdown-1.0.2.tgz",
|
||||
|
@ -35374,6 +35369,11 @@
|
|||
"@lezer/highlight": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"@microsoft/fetch-event-source": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz",
|
||||
"integrity": "sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA=="
|
||||
},
|
||||
"@monaco-editor/loader": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@monaco-editor/loader/-/loader-1.3.3.tgz",
|
||||
|
|
|
@ -7,7 +7,7 @@ export default function InstructionsForEndUser({ task }: any) {
|
|||
return null;
|
||||
}
|
||||
let instructions = '';
|
||||
console.log("I was passed a task: ", task);
|
||||
console.log('I was passed a task: ', task);
|
||||
const { properties } = task;
|
||||
const { instructionsForEndUser } = properties;
|
||||
if (instructionsForEndUser) {
|
||||
|
|
|
@ -1455,7 +1455,8 @@ export default function ProcessInstanceListTable({
|
|||
if (showActionsColumn) {
|
||||
let buttonElement = null;
|
||||
const interstitialUrl = `/process/${modifyProcessIdentifierForPathParam(
|
||||
row.process_model_identifier)}/${row.id}/interstitial`
|
||||
row.process_model_identifier
|
||||
)}/${row.id}/interstitial`;
|
||||
const regex = new RegExp(`\\b(${preferredUsername}|${userEmail})\\b`);
|
||||
let hasAccessToCompleteTask = false;
|
||||
if (
|
||||
|
|
|
@ -56,7 +56,10 @@ 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="process/:process_instance_id/interstitial"
|
||||
element={<ProcessInterstitial />}
|
||||
/>
|
||||
<Route path="completed-instances" element={<CompletedInstances />} />
|
||||
<Route path="create-new-instance" element={<CreateNewInstance />} />
|
||||
</Routes>
|
||||
|
|
|
@ -75,7 +75,12 @@ export default function ProcessInterstitial() {
|
|||
case 'COMPLETED':
|
||||
return <img src="/interstitial/checkmark.png" alt="Completed" />;
|
||||
case 'LOCKED':
|
||||
return <img src="/interstitial/lock.png" alt="Locked, Waiting on someone else." />;
|
||||
return (
|
||||
<img
|
||||
src="/interstitial/lock.png"
|
||||
alt="Locked, Waiting on someone else."
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -86,11 +91,13 @@ export default function ProcessInterstitial() {
|
|||
!myTask.can_complete &&
|
||||
['User Task', 'Manual Task'].includes(myTask.type)
|
||||
) {
|
||||
return (
|
||||
<div>This next task must be completed by a different person.</div>
|
||||
);
|
||||
return <div>This next task must be completed by a different person.</div>;
|
||||
}
|
||||
return <div><InstructionsForEndUser task={myTask} /></div>;
|
||||
return (
|
||||
<div>
|
||||
<InstructionsForEndUser task={myTask} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
if (lastTask) {
|
||||
|
@ -116,7 +123,9 @@ export default function ProcessInterstitial() {
|
|||
<Column md={6} lg={8} sm={4}>
|
||||
{data &&
|
||||
data.map((d) => (
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '2em' }}>
|
||||
<div
|
||||
style={{ display: 'flex', alignItems: 'center', gap: '2em' }}
|
||||
>
|
||||
<div>
|
||||
Task: <em>{d.title}</em>
|
||||
</div>
|
||||
|
|
|
@ -126,7 +126,6 @@ export default function TaskShow() {
|
|||
);
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const processResult = (result: ProcessInstanceTask) => {
|
||||
setTask(result);
|
||||
|
|
Loading…
Reference in New Issue