mirror of
https://github.com/status-im/spiff-arena.git
synced 2025-02-05 14:44:12 +00:00
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:
parent
fb2af46521
commit
02e8add28f
@ -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
|
||||||
|
|
||||||
|
@ -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"),
|
||||||
|
@ -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,
|
||||||
|
BIN
spiffworkflow-frontend/public/interstitial/checkmark.png
Normal file
BIN
spiffworkflow-frontend/public/interstitial/checkmark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.9 KiB |
BIN
spiffworkflow-frontend/public/interstitial/clock.png
Normal file
BIN
spiffworkflow-frontend/public/interstitial/clock.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.1 KiB |
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user