cleaing up the design a little bit so it looks pretty and in keeping with the rest of the site.

This commit is contained in:
Dan 2023-04-18 16:58:59 -04:00
parent fb2af46521
commit 02e8add28f
7 changed files with 123 additions and 69 deletions

View File

@ -358,9 +358,11 @@ def _render_instructions_for_end_user(spiff_task: SpiffTask, task: Task):
if task.properties and "instructionsForEndUser" in task.properties: if task.properties and "instructionsForEndUser" in task.properties:
if task.properties["instructionsForEndUser"]: if task.properties["instructionsForEndUser"]:
try: try:
task.properties["instructionsForEndUser"] = _render_jinja_template( instructions = _render_jinja_template(
task.properties["instructionsForEndUser"], spiff_task task.properties["instructionsForEndUser"], spiff_task
) )
task.properties["instructionsForEndUser"] = instructions
return instructions
except WorkflowTaskException as wfe: except WorkflowTaskException as wfe:
wfe.add_note("Failed to render instructions for end user.") wfe.add_note("Failed to render instructions for end user.")
raise ApiError.from_workflow_exception("instructions_error", str(wfe), exp=wfe) from wfe raise ApiError.from_workflow_exception("instructions_error", str(wfe), exp=wfe) from wfe
@ -393,19 +395,22 @@ def process_data_show(
def interstitial(process_instance_id: int): def interstitial(process_instance_id: int):
process_instance = _find_process_instance_by_id_or_raise(process_instance_id) process_instance = _find_process_instance_by_id_or_raise(process_instance_id)
processor = ProcessInstanceProcessor(process_instance) processor = ProcessInstanceProcessor(process_instance)
reported_ids = [] # bit of an issue with end tasks showing as getting completed twice.
def get_data(): def get_data():
spiff_task = processor.next_task() spiff_task = processor.next_task()
last_task = None last_task = None
while last_task != spiff_task: while last_task != spiff_task:
task = ProcessInstanceService.spiff_task_to_api_task(processor, processor.next_task()) task = ProcessInstanceService.spiff_task_to_api_task(processor, processor.next_task())
_render_instructions_for_end_user(spiff_task, task) 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 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") processor.do_engine_steps(execution_strategy_name="one_at_a_time")
spiff_task = processor.next_task() spiff_task = processor.next_task()
# Note, this has to be done in case someone leaves the page, # Note, this has to be done in case someone leaves the page,
# which can cancel this function before saving. # 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 method? processor.save() # Fixme - maybe find a way not to do this on every method?
return return

View File

@ -443,6 +443,7 @@ class ProcessInstanceService:
process_identifier=spiff_task.task_spec._wf_spec.name, process_identifier=spiff_task.task_spec._wf_spec.name,
process_instance_id=processor.process_instance_model.id, process_instance_id=processor.process_instance_model.id,
process_model_identifier=processor.process_model_identifier, process_model_identifier=processor.process_model_identifier,
process_model_display_name=processor.process_model_display_name,
properties=props, properties=props,
parent=parent_id, parent=parent_id,
event_definition=serialized_task_spec.get("event_definition"), event_definition=serialized_task_spec.get("event_definition"),

View File

@ -243,6 +243,7 @@ class GreedyExecutionStrategy(ExecutionStrategy):
if non_human_waiting_task is not None: if non_human_waiting_task is not None:
self.run_until_user_input_required(exit_at) self.run_until_user_input_required(exit_at)
class RunUntilServiceTaskExecutionStrategy(ExecutionStrategy): class RunUntilServiceTaskExecutionStrategy(ExecutionStrategy):
"""For illustration purposes, not currently integrated. """For illustration purposes, not currently integrated.
@ -264,22 +265,29 @@ class RunUntilServiceTaskExecutionStrategy(ExecutionStrategy):
self.delegate.after_engine_steps(bpmn_process_instance) self.delegate.after_engine_steps(bpmn_process_instance)
class RunUntilUserMessageExecutionStrategy(ExecutionStrategy): class RunUntilUserTaskOrMessageExecutionStrategy(ExecutionStrategy):
"""When you want to run tasks until you hit something to report to the end user, or """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))
])
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_ready_engine_steps(bpmn_process_instance)
engine_steps = self.get_engine_steps(bpmn_process_instance)
while engine_steps: while engine_steps:
for spiff_task in engine_steps: for task in engine_steps:
self.delegate.will_complete_task(spiff_task) self.delegate.will_complete_task(task)
spiff_task.run() task.run()
self.delegate.did_complete_task(spiff_task) self.delegate.did_complete_task(task)
if spiff_task.task_spec.properties.get("instructionsForEndUser", None) is not None: engine_steps = self.get_engine_steps(bpmn_process_instance)
break
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)
class OneAtATimeExecutionStrategy(ExecutionStrategy): class OneAtATimeExecutionStrategy(ExecutionStrategy):
"""When you want to run only one engine step at a time.""" """When you want to run only one engine step at a time."""
@ -297,7 +305,7 @@ def execution_strategy_named(name: str, delegate: EngineStepDelegate) -> Executi
cls = { cls = {
"greedy": GreedyExecutionStrategy, "greedy": GreedyExecutionStrategy,
"run_until_service_task": RunUntilServiceTaskExecutionStrategy, "run_until_service_task": RunUntilServiceTaskExecutionStrategy,
"run_until_user_message": RunUntilUserMessageExecutionStrategy, "run_until_user_message": RunUntilUserTaskOrMessageExecutionStrategy,
"one_at_a_time": OneAtATimeExecutionStrategy, "one_at_a_time": OneAtATimeExecutionStrategy,
}[name] }[name]
@ -307,6 +315,7 @@ def execution_strategy_named(name: str, delegate: EngineStepDelegate) -> Executi
ProcessInstanceCompleter = Callable[[BpmnWorkflow], None] ProcessInstanceCompleter = Callable[[BpmnWorkflow], None]
ProcessInstanceSaver = Callable[[], None] ProcessInstanceSaver = Callable[[], None]
class WorkflowExecutionService: class WorkflowExecutionService:
"""Provides the driver code for workflow execution.""" """Provides the driver code for workflow execution."""
@ -366,7 +375,8 @@ class WorkflowExecutionService:
for bpmn_message in bpmn_messages: for bpmn_message in bpmn_messages:
message_instance = MessageInstanceModel( message_instance = MessageInstanceModel(
process_instance_id=self.process_instance_model.id, process_instance_id=self.process_instance_model.id,
user_id=self.process_instance_model.process_initiator_id, # TODO: use the correct swimlane user when that is set up user_id=self.process_instance_model.process_initiator_id,
# TODO: use the correct swimlane user when that is set up
message_type="send", message_type="send",
name=bpmn_message.name, name=bpmn_message.name,
payload=bpmn_message.payload, payload=bpmn_message.payload,

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -1,14 +1,19 @@
import { useEffect, useState } from 'react'; import React, { useEffect, 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
import { Loading, Grid, Column } 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';
import {Task} from '../interfaces';
// @ts-ignore
import InstructionsForEndUser from '../components/InstructionsForEndUser'; import InstructionsForEndUser from '../components/InstructionsForEndUser';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
export default function ProcessInterstitial() { export default function ProcessInterstitial() {
const [data, setData] = useState<any[]>([]); const [data, setData] = useState<any[]>([]);
const [lastTask, setLastTask] = useState<any>(null); const [lastTask, setLastTask] = useState<any>(null);
const [status, setStatus] = useState<string>('running');
const params = useParams(); const params = useParams();
const navigate = useNavigate(); const navigate = useNavigate();
@ -24,7 +29,8 @@ export default function ProcessInterstitial() {
setLastTask(task); setLastTask(task);
}, },
onclose() { onclose() {
console.log("Connection Closed by the Server"); setStatus('closed');
console.log('Connection Closed by the Server');
}, },
} }
); );
@ -42,23 +48,52 @@ export default function ProcessInterstitial() {
return undefined; return undefined;
}, [lastTask]); }, [lastTask]);
const processStatusImage = () => {
if (status !== 'running') {
setStatus(lastTask.state);
}
console.log(`Status is : ${status}}`);
console.log('last task is : ', lastTask);
switch (status) {
case 'running':
return ( return (
<div className="container"> <Loading description="Active loading indicator" withOverlay={false} />
<h3 className="p-3 text-center">React - Display a list of items</h3> );
<table className="table table-striped table-bordered"> case 'WAITING':
<thead> return <img src="/interstitial/clock.png" alt="Waiting ...." />;
<tr> case 'COMPLETED':
<th>Task Title</th> return <img src="/interstitial/checkmark.png" alt="Completed" />;
</tr> default:
</thead> return null;
}
};
if (lastTask) {
return (
<>
<ProcessBreadcrumb
hotCrumbs={[
['Process Groups', '/admin'],
{
entityToExplode: lastTask.process_model_identifier,
entityType: 'process-model-id',
linkLastItem: true,
},
[`Process Instance Id: ${lastTask.process_instance_id}`],
]}
/>
<h1 style={{display: 'inline-flex', alignItems: 'center'}}>
{processStatusImage()}
{lastTask.process_model_display_name}: {lastTask.process_instance_id}
</h1>
<Grid condensed fullWidth>
<Column md={6} lg={8} sm={4}>
<table className="table table-bordered">
<tbody> <tbody>
{data && {data &&
data.map((d) => ( data.map((d) => (
<tr key={d.id}> <tr key={d.id}>
<td>{d.title}</td> <td><h3>{d.title}</h3></td>
<td>{d.state}</td>
<td>{d.type}</td>
<td> <td>
<InstructionsForEndUser task={d} /> <InstructionsForEndUser task={d} />
</td> </td>
@ -66,6 +101,10 @@ export default function ProcessInterstitial() {
))} ))}
</tbody> </tbody>
</table> </table>
</div> </Column>
</Grid>
</>
); );
}
return null;
} }

View File

@ -17,7 +17,6 @@ import {
import MDEditor from '@uiw/react-md-editor'; import MDEditor from '@uiw/react-md-editor';
// eslint-disable-next-line import/no-named-as-default // eslint-disable-next-line import/no-named-as-default
import Form from '../themes/carbon'; import Form from '../themes/carbon';
import Loading from '../themes/carbon';
import HttpService from '../services/HttpService'; import HttpService from '../services/HttpService';
import useAPIError from '../hooks/UseApiError'; import useAPIError from '../hooks/UseApiError';
import { modifyProcessIdentifierForPathParam } from '../helpers'; import { modifyProcessIdentifierForPathParam } from '../helpers';