Merge remote-tracking branch 'origin/main' into feature/home_page_filter_links

This commit is contained in:
jasquat 2023-04-27 07:28:47 -04:00
commit d29a4ca0ae
22 changed files with 2518 additions and 2393 deletions

File diff suppressed because it is too large Load Diff

View File

@ -519,16 +519,16 @@ paths:
schema: schema:
type: string type: string
/processes/{bpmn_process_identifier}/callers: /processes/callers:
parameters: parameters:
- name: bpmn_process_identifier - name: bpmn_process_identifier
in: path in: query
required: true required: true
description: the modified process model id description: the bpmn process identifier/id (not the name with spaces and not the process model identifier)
schema: schema:
type: string type: string
get: get:
operationId: spiffworkflow_backend.routes.process_api_blueprint.process_caller_lists operationId: spiffworkflow_backend.routes.process_api_blueprint.process_caller_list
summary: summary:
Return a list of information about all processes that call the provided process id Return a list of information about all processes that call the provided process id
tags: tags:

View File

@ -78,7 +78,7 @@ def process_list() -> Any:
return SpecReferenceSchema(many=True).dump(references) return SpecReferenceSchema(many=True).dump(references)
def process_caller_lists(bpmn_process_identifier: str) -> Any: def process_caller_list(bpmn_process_identifier: str) -> Any:
callers = ProcessCallerService.callers(bpmn_process_identifier) callers = ProcessCallerService.callers(bpmn_process_identifier)
references = ( references = (
SpecReferenceCache.query.filter_by(type="process").filter(SpecReferenceCache.identifier.in_(callers)).all() SpecReferenceCache.query.filter_by(type="process").filter(SpecReferenceCache.identifier.in_(callers)).all()

View File

@ -20,6 +20,7 @@ from flask import make_response
from flask import stream_with_context from flask import stream_with_context
from flask.wrappers import Response from flask.wrappers import Response
from jinja2 import TemplateSyntaxError from jinja2 import TemplateSyntaxError
from SpiffWorkflow.bpmn.workflow import BpmnWorkflow # type: ignore
from SpiffWorkflow.exceptions import WorkflowTaskException # type: ignore from SpiffWorkflow.exceptions import WorkflowTaskException # type: ignore
from SpiffWorkflow.task import Task as SpiffTask # type: ignore from SpiffWorkflow.task import Task as SpiffTask # type: ignore
from SpiffWorkflow.task import TaskState from SpiffWorkflow.task import TaskState
@ -385,47 +386,90 @@ def _render_instructions_for_end_user(task_model: TaskModel, extensions: Optiona
def _interstitial_stream(process_instance: ProcessInstanceModel) -> Generator[str, Optional[str], None]: def _interstitial_stream(process_instance: ProcessInstanceModel) -> Generator[str, Optional[str], None]:
processor = ProcessInstanceProcessor(process_instance) processor = ProcessInstanceProcessor(process_instance)
reported_ids = [] # bit of an issue with end tasks showing as getting completed twice. reported_ids = [] # A list of all the ids reported by this endpoint so far.
spiff_task = processor.next_task()
task_model = TaskModel.query.filter_by(guid=str(spiff_task.id)).first() def get_reportable_tasks() -> Any:
last_task = None return processor.bpmn_process_instance.get_tasks(
while last_task != spiff_task: TaskState.WAITING | TaskState.STARTED | TaskState.READY | TaskState.ERROR
task = ProcessInstanceService.spiff_task_to_api_task(processor, processor.next_task()) )
def render_instructions(spiff_task: SpiffTask) -> str:
task_model = TaskModel.query.filter_by(guid=str(spiff_task.id)).first()
extensions = TaskService.get_extensions_from_task_model(task_model) extensions = TaskService.get_extensions_from_task_model(task_model)
instructions = _render_instructions_for_end_user(task_model, extensions) return _render_instructions_for_end_user(task_model, extensions)
if instructions and spiff_task.id not in reported_ids:
reported_ids.append(spiff_task.id) tasks = get_reportable_tasks()
task.properties = extensions while True:
yield f"data: {current_app.json.dumps(task)} \n\n" for spiff_task in tasks:
last_task = spiff_task try:
instructions = render_instructions(spiff_task)
except Exception as e:
api_error = ApiError(
error_code="engine_steps_error",
message=f"Failed to complete an automated task. Error was: {str(e)}",
status_code=400,
)
yield f"data: {current_app.json.dumps(api_error)} \n\n"
raise e
if instructions and spiff_task.id not in reported_ids:
task = ProcessInstanceService.spiff_task_to_api_task(processor, spiff_task)
task.properties = {"instructionsForEndUser": instructions}
yield f"data: {current_app.json.dumps(task)} \n\n"
reported_ids.append(spiff_task.id)
if spiff_task.state == TaskState.READY:
try:
processor.do_engine_steps(execution_strategy_name="one_at_a_time")
processor.do_engine_steps(execution_strategy_name="run_until_user_message")
processor.save() # Fixme - maybe find a way not to do this on every loop?
except WorkflowTaskException as wfe:
api_error = ApiError.from_workflow_exception(
"engine_steps_error", "Failed complete an automated task.", exp=wfe
)
yield f"data: {current_app.json.dumps(api_error)} \n\n"
return
except Exception as e:
api_error = ApiError(
error_code="engine_steps_error",
message=f"Failed to complete an automated task. Error was: {str(e)}",
status_code=400,
)
yield f"data: {current_app.json.dumps(api_error)} \n\n"
return
processor.bpmn_process_instance.refresh_waiting_tasks()
ready_engine_task_count = get_ready_engine_step_count(processor.bpmn_process_instance)
tasks = get_reportable_tasks()
if ready_engine_task_count == 0:
break # No more tasks to report
spiff_task = processor.next_task()
task = ProcessInstanceService.spiff_task_to_api_task(processor, processor.next_task())
if task.id not in reported_ids:
try: try:
processor.do_engine_steps(execution_strategy_name="one_at_a_time") instructions = render_instructions(spiff_task)
processor.do_engine_steps(execution_strategy_name="run_until_user_message")
processor.save() # Fixme - maybe find a way not to do this on every loop?
except WorkflowTaskException as wfe:
api_error = ApiError.from_workflow_exception(
"engine_steps_error", "Failed complete an automated task.", exp=wfe
)
yield f"data: {current_app.json.dumps(api_error)} \n\n"
except Exception as e: except Exception as e:
api_error = ApiError( api_error = ApiError(
error_code="engine_steps_error", error_code="engine_steps_error",
message=f"Failed complete an automated task. Error was: {str(e)}", message=f"Failed to complete an automated task. Error was: {str(e)}",
status_code=400, status_code=400,
) )
yield f"data: {current_app.json.dumps(api_error)} \n\n" yield f"data: {current_app.json.dumps(api_error)} \n\n"
raise e
# Note, this has to be done in case someone leaves the page, task.properties = {"instructionsForEndUser": instructions}
# which can otherwise cancel this function and leave completed tasks un-registered.
spiff_task = processor.next_task()
task_model = TaskModel.query.filter_by(guid=str(spiff_task.id)).first()
# Always provide some response, in the event no instructions were provided.
if len(reported_ids) == 0:
task = ProcessInstanceService.spiff_task_to_api_task(processor, processor.next_task())
yield f"data: {current_app.json.dumps(task)} \n\n" yield f"data: {current_app.json.dumps(task)} \n\n"
def get_ready_engine_step_count(bpmn_process_instance: BpmnWorkflow) -> int:
return len(
list(
[
t
for t in bpmn_process_instance.get_tasks(TaskState.READY)
if bpmn_process_instance._is_engine_task(t.task_spec)
]
)
)
def _dequeued_interstitial_stream(process_instance_id: int) -> Generator[str, Optional[str], None]: def _dequeued_interstitial_stream(process_instance_id: int) -> Generator[str, Optional[str], None]:
process_instance = _find_process_instance_by_id_or_raise(process_instance_id) process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
with ProcessInstanceQueueService.dequeued(process_instance): with ProcessInstanceQueueService.dequeued(process_instance):

View File

@ -572,6 +572,7 @@ class AuthorizationService:
permissions_to_assign: list[PermissionToAssign] = [] permissions_to_assign: list[PermissionToAssign] = []
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/process-instances/for-me")) permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/process-instances/for-me"))
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/processes")) permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/processes"))
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/processes/callers"))
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/service-tasks")) permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/service-tasks"))
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/user-groups/for-current-user")) permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/user-groups/for-current-user"))
permissions_to_assign.append(PermissionToAssign(permission="create", target_uri="/users/exists/by-username")) permissions_to_assign.append(PermissionToAssign(permission="create", target_uri="/users/exists/by-username"))

View File

@ -220,14 +220,15 @@ class TaskService:
if task_model.state == "COMPLETED": if task_model.state == "COMPLETED":
event_type = ProcessInstanceEventType.task_completed.value event_type = ProcessInstanceEventType.task_completed.value
timestamp = task_model.end_in_seconds or task_model.start_in_seconds or time.time() timestamp = task_model.end_in_seconds or task_model.start_in_seconds or time.time()
process_instance_event, _process_instance_error_detail = ( (
ProcessInstanceTmpService.add_event_to_process_instance( process_instance_event,
self.process_instance, _process_instance_error_detail,
event_type, ) = ProcessInstanceTmpService.add_event_to_process_instance(
task_guid=task_model.guid, self.process_instance,
timestamp=timestamp, event_type,
add_to_db_session=False, task_guid=task_model.guid,
) timestamp=timestamp,
add_to_db_session=False,
) )
self.process_instance_events[task_model.guid] = process_instance_event self.process_instance_events[task_model.guid] = process_instance_event
@ -454,7 +455,6 @@ class TaskService:
spiff_task, spiff_task,
self.bpmn_definition_to_task_definitions_mappings, self.bpmn_definition_to_task_definitions_mappings,
) )
self.update_task_model(task_model, spiff_task) self.update_task_model(task_model, spiff_task)
self.task_models[task_model.guid] = task_model self.task_models[task_model.guid] = task_model

View File

@ -299,28 +299,28 @@ class RunUntilServiceTaskExecutionStrategy(ExecutionStrategy):
class RunUntilUserTaskOrMessageExecutionStrategy(ExecutionStrategy): class RunUntilUserTaskOrMessageExecutionStrategy(ExecutionStrategy):
"""When you want to run tasks until you hit something to report to the end user.""" """When you want to run tasks until you hit something to report to the end user.
def get_engine_steps(self, bpmn_process_instance: BpmnWorkflow) -> list[SpiffTask]: Note that this will run at least one engine step if possible,
return list( but will stop if it hits instructions after the first task.
[ """
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: def spiff_run(self, bpmn_process_instance: BpmnWorkflow, exit_at: None = None) -> None:
engine_steps = self.get_engine_steps(bpmn_process_instance) should_continue = True
while engine_steps: bpmn_process_instance.refresh_waiting_tasks()
engine_steps = self.get_ready_engine_steps(bpmn_process_instance)
while engine_steps and should_continue:
for task in engine_steps: for task in engine_steps:
if hasattr(task.task_spec, "extensions") and task.task_spec.extensions.get(
"instructionsForEndUser", None
):
should_continue = False
break
self.delegate.will_complete_task(task) self.delegate.will_complete_task(task)
task.run() task.run()
self.delegate.did_complete_task(task) self.delegate.did_complete_task(task)
engine_steps = self.get_engine_steps(bpmn_process_instance) bpmn_process_instance.refresh_waiting_tasks()
engine_steps = self.get_ready_engine_steps(bpmn_process_instance)
self.delegate.after_engine_steps(bpmn_process_instance) self.delegate.after_engine_steps(bpmn_process_instance)

View File

@ -591,7 +591,7 @@ class TestProcessApi(BaseTest):
# get the results # get the results
response = client.get( response = client.get(
"/v1.0/processes/Level2/callers", "/v1.0/processes/callers?bpmn_process_identifier=Level2",
headers=self.logged_in_headers(with_super_admin_user), headers=self.logged_in_headers(with_super_admin_user),
) )
assert response.json is not None assert response.json is not None

View File

@ -296,6 +296,7 @@ class TestAuthorizationService(BaseTest):
("/process-instances/reports/*", "read"), ("/process-instances/reports/*", "read"),
("/process-instances/reports/*", "update"), ("/process-instances/reports/*", "update"),
("/processes", "read"), ("/processes", "read"),
("/processes/callers", "read"),
("/service-tasks", "read"), ("/service-tasks", "read"),
("/tasks/*", "create"), ("/tasks/*", "create"),
("/tasks/*", "delete"), ("/tasks/*", "delete"),

View File

@ -348,8 +348,13 @@ class TestProcessInstanceProcessor(BaseTest):
assert len(process_instance.human_tasks) == 1 assert len(process_instance.human_tasks) == 1
spiff_manual_task = processor.bpmn_process_instance.get_task_from_id(UUID(human_task_one.task_id)) spiff_manual_task = processor.bpmn_process_instance.get_task_from_id(UUID(human_task_one.task_id))
assert len(process_instance.active_human_tasks) == 1, "expected 1 active human task"
ProcessInstanceService.complete_form_task(processor, spiff_manual_task, {}, initiator_user, human_task_one) ProcessInstanceService.complete_form_task(processor, spiff_manual_task, {}, initiator_user, human_task_one)
assert len(process_instance.human_tasks) == 2, "expected 2 human tasks after first one is completed" assert len(process_instance.human_tasks) == 2, "expected 2 human tasks after first one is completed"
assert (
len(process_instance.active_human_tasks) == 1
), "expected 1 active human tasks after 1st one is completed"
# unnecessary lookup just in case on windows # unnecessary lookup just in case on windows
process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first() process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first()
@ -359,8 +364,8 @@ class TestProcessInstanceProcessor(BaseTest):
ProcessInstanceService.complete_form_task(processor, spiff_manual_task, {}, initiator_user, human_task_one) ProcessInstanceService.complete_form_task(processor, spiff_manual_task, {}, initiator_user, human_task_one)
import pdb; pdb.set_trace() import pdb; pdb.set_trace()
assert ( assert (
len(process_instance.active_human_tasks) == 0 len(process_instance.active_human_tasks) == 1
), "expected 0 active human tasks after 2nd one is completed" ), "expected 1 active human tasks after 2nd one is completed, as we have looped back around."
processor.suspend() processor.suspend()
@ -373,7 +378,7 @@ class TestProcessInstanceProcessor(BaseTest):
assert len(all_task_models_matching_top_level_subprocess_script) == 1 assert len(all_task_models_matching_top_level_subprocess_script) == 1
task_model_to_reset_to = all_task_models_matching_top_level_subprocess_script[0] task_model_to_reset_to = all_task_models_matching_top_level_subprocess_script[0]
assert task_model_to_reset_to is not None assert task_model_to_reset_to is not None
assert len(process_instance.human_tasks) == 2, "expected 2 human tasks before reset" assert len(process_instance.human_tasks) == 3, "expected 3 human tasks before reset"
ProcessInstanceProcessor.reset_process(process_instance, task_model_to_reset_to.guid) ProcessInstanceProcessor.reset_process(process_instance, task_model_to_reset_to.guid)
assert len(process_instance.human_tasks) == 2, "still expected 2 human tasks after reset" assert len(process_instance.human_tasks) == 2, "still expected 2 human tasks after reset"
@ -381,7 +386,7 @@ class TestProcessInstanceProcessor(BaseTest):
db.session.expire_all() db.session.expire_all()
assert ( assert (
len(process_instance.human_tasks) == 2 len(process_instance.human_tasks) == 2
), "still expected 2 human tasks after reset and session expire_all" ), "still expected 3 human tasks after reset and session expire_all"
process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first() process_instance = ProcessInstanceModel.query.filter_by(id=process_instance.id).first()
processor = ProcessInstanceProcessor(process_instance) processor = ProcessInstanceProcessor(process_instance)

View File

@ -38,7 +38,7 @@
"bootstrap": "^5.2.0", "bootstrap": "^5.2.0",
"bpmn-js": "^9.3.2", "bpmn-js": "^9.3.2",
"bpmn-js-properties-panel": "^1.10.0", "bpmn-js-properties-panel": "^1.10.0",
"bpmn-js-spiffworkflow": "sartography/bpmn-js-spiffworkflow#main", "bpmn-js-spiffworkflow": "github:sartography/bpmn-js-spiffworkflow#main",
"cookie": "^0.5.0", "cookie": "^0.5.0",
"craco": "^0.0.3", "craco": "^0.0.3",
"cypress-slow-down": "^1.2.1", "cypress-slow-down": "^1.2.1",
@ -8343,7 +8343,7 @@
}, },
"node_modules/bpmn-js-spiffworkflow": { "node_modules/bpmn-js-spiffworkflow": {
"version": "0.0.8", "version": "0.0.8",
"resolved": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#5f2cb3d50b021dffce61fd6b2929ef5620dcdb2e", "resolved": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#313969da1067fce0a51b152626a609a122697693",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"inherits": "^2.0.4", "inherits": "^2.0.4",
@ -38215,8 +38215,8 @@
} }
}, },
"bpmn-js-spiffworkflow": { "bpmn-js-spiffworkflow": {
"version": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#5f2cb3d50b021dffce61fd6b2929ef5620dcdb2e", "version": "git+ssh://git@github.com/sartography/bpmn-js-spiffworkflow.git#313969da1067fce0a51b152626a609a122697693",
"from": "bpmn-js-spiffworkflow@sartography/bpmn-js-spiffworkflow#main", "from": "bpmn-js-spiffworkflow@github:sartography/bpmn-js-spiffworkflow#main",
"requires": { "requires": {
"inherits": "^2.0.4", "inherits": "^2.0.4",
"inherits-browser": "^0.0.1", "inherits-browser": "^0.0.1",

View File

@ -33,7 +33,7 @@
"bootstrap": "^5.2.0", "bootstrap": "^5.2.0",
"bpmn-js": "^9.3.2", "bpmn-js": "^9.3.2",
"bpmn-js-properties-panel": "^1.10.0", "bpmn-js-properties-panel": "^1.10.0",
"bpmn-js-spiffworkflow": "sartography/bpmn-js-spiffworkflow#main", "bpmn-js-spiffworkflow": "github:sartography/bpmn-js-spiffworkflow#main",
"cookie": "^0.5.0", "cookie": "^0.5.0",
"craco": "^0.0.3", "craco": "^0.0.3",
"cypress-slow-down": "^1.2.1", "cypress-slow-down": "^1.2.1",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -2,12 +2,19 @@ import React from 'react';
// @ts-ignore // @ts-ignore
import MDEditor from '@uiw/react-md-editor'; import MDEditor from '@uiw/react-md-editor';
export default function InstructionsForEndUser({ task }: any) { type OwnProps = {
task: any;
defaultMessage?: string;
};
export default function InstructionsForEndUser({
task,
defaultMessage = '',
}: OwnProps) {
if (!task) { if (!task) {
return null; return null;
} }
let instructions = let instructions = defaultMessage;
'There is no additional instructions or information for this task.';
let { properties } = task; let { properties } = task;
if (!properties) { if (!properties) {
properties = task.extensions; properties = task.extensions;

View File

@ -1551,6 +1551,7 @@ export default function ProcessInstanceListTable({
); );
}; };
// eslint-disable-next-line sonarjs/cognitive-complexity
const buildTable = () => { const buildTable = () => {
const headerLabels: Record<string, string> = { const headerLabels: Record<string, string> = {
id: 'Id', id: 'Id',
@ -1592,11 +1593,11 @@ export default function ProcessInstanceListTable({
buttonElement = ( buttonElement = (
<Button <Button
kind={ kind={
hasAccessToCompleteTask && row.task_id ? 'secondary' : 'tertiary' hasAccessToCompleteTask && row.task_id ? 'secondary' : 'ghost'
} }
href={interstitialUrl} href={interstitialUrl}
> >
Go {hasAccessToCompleteTask && row.task_id ? 'Go' : 'View'}
</Button> </Button>
); );
currentRow.push(<td>{buttonElement}</td>); currentRow.push(<td>{buttonElement}</td>);

View File

@ -29,6 +29,10 @@
border-color: none; border-color: none;
} }
.cds--loading__stroke {
stroke: gray;
}
/* make this a little less prominent so the actual human beings completing tasks stand out */ /* make this a little less prominent so the actual human beings completing tasks stand out */
.system-user-log-entry { .system-user-log-entry {
color: #B0B0B0; color: #B0B0B0;
@ -424,3 +428,24 @@ svg.notification-icon {
margin-bottom: 1em; margin-bottom: 1em;
font-weight: bold; font-weight: bold;
} }
.user_instructions_0 {
filter: opacity(1);
}
.user_instructions_1 {
filter: opacity(60%);
}
.user_instructions_2 {
filter: opacity(40%);
}
.user_instructions_3 {
filter: opacity(20%);
}
.user_instructions_4 {
filter: opacity(10%);
}

View File

@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom'; import { useNavigate, useParams } from 'react-router-dom';
import { fetchEventSource } from '@microsoft/fetch-event-source'; import { fetchEventSource } from '@microsoft/fetch-event-source';
// @ts-ignore // @ts-ignore
import { Loading, Grid, Column } from '@carbon/react'; import { Loading, Grid, Column, Button } from '@carbon/react';
import { BACKEND_BASE_URL } from '../config'; import { BACKEND_BASE_URL } from '../config';
import { getBasicHeaders } from '../services/HttpService'; import { getBasicHeaders } from '../services/HttpService';
@ -35,7 +35,7 @@ export default function ProcessInterstitial() {
if ('error_code' in retValue) { if ('error_code' in retValue) {
addError(retValue); addError(retValue);
} else { } else {
setData((prevData) => [...prevData, retValue]); setData((prevData) => [retValue, ...prevData]);
setLastTask(retValue); setLastTask(retValue);
} }
}, },
@ -100,6 +100,33 @@ export default function ProcessInterstitial() {
} }
}; };
const getReturnHomeButton = (index: number) => {
if (
index === 0 &&
state !== 'REDIRECTING' &&
['WAITING', 'ERROR', 'LOCKED', 'COMPLETED', 'READY'].includes(getStatus())
)
return (
<div style={{ padding: '10px 0 0 0' }}>
<Button kind="secondary" onClick={() => navigate(`/tasks`)}>
Return to Home
</Button>
</div>
);
return '';
};
const getHr = (index: number) => {
if (index === 0) {
return (
<div style={{ padding: '10px 0 50px 0' }}>
<hr />
</div>
);
}
return '';
};
function capitalize(str: string): string { function capitalize(str: string): string {
if (str && str.length > 0) { if (str && str.length > 0) {
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase(); return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
@ -109,7 +136,15 @@ export default function ProcessInterstitial() {
const userMessage = (myTask: ProcessInstanceTask) => { const userMessage = (myTask: ProcessInstanceTask) => {
if (!myTask.can_complete && userTasks.includes(myTask.type)) { if (!myTask.can_complete && userTasks.includes(myTask.type)) {
return <div>This next task must be completed by a different person.</div>; return (
<>
<h4 className="heading-compact-01">Waiting on Someone Else</h4>
<p>
This next task is assigned to a different person or team. There is
no action for you take at this time.
</p>
</>
);
} }
if (shouldRedirect(myTask)) { if (shouldRedirect(myTask)) {
return <div>Redirecting you to the next task now ...</div>; return <div>Redirecting you to the next task now ...</div>;
@ -120,7 +155,10 @@ export default function ProcessInterstitial() {
return ( return (
<div> <div>
<InstructionsForEndUser task={myTask} /> <InstructionsForEndUser
task={myTask}
defaultMessage="There are no additional instructions or information for this task."
/>
</div> </div>
); );
}; };
@ -147,7 +185,7 @@ export default function ProcessInterstitial() {
], ],
]} ]}
/> />
<div style={{ display: 'flex', alignItems: 'center' }}> <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
{getStatusImage()} {getStatusImage()}
<div> <div>
<h1 style={{ marginBottom: '0em' }}> <h1 style={{ marginBottom: '0em' }}>
@ -159,13 +197,20 @@ export default function ProcessInterstitial() {
</div> </div>
<br /> <br />
<br /> <br />
{data.map((d) => ( {data.map((d, index) => (
<Grid fullWidth style={{ marginBottom: '1em' }}> <Grid fullWidth style={{ marginBottom: '1em' }}>
<Column md={2} lg={4} sm={2}> <Column md={6} lg={8} sm={4}>
Task: <em>{d.title}</em> <div
</Column> className={
<Column md={6} lg={6} sm={4}> index < 4
{userMessage(d)} ? `user_instructions_${index}`
: `user_instructions_4`
}
>
{userMessage(d)}
</div>
{getReturnHomeButton(index)}
{getHr(index)}
</Column> </Column>
</Grid> </Grid>
))} ))}

View File

@ -168,7 +168,7 @@ export default function ProcessModelEditDiagram() {
useEffect(() => { useEffect(() => {
if (processModel !== null) { if (processModel !== null) {
HttpService.makeCallToBackend({ HttpService.makeCallToBackend({
path: `/processes/${processModel.primary_process_id}/callers`, path: `/processes/callers?bpmn_process_identifier=${processModel.primary_process_id}`,
successCallback: setCallers, successCallback: setCallers,
}); });
} }