make sure we can properly display lanes.
This commit is contained in:
parent
b6480fb9fe
commit
18f3b34c4a
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from flask import g
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
|
@ -68,12 +69,19 @@ class HumanTaskModel(SpiffworkflowBaseDBModel):
|
|||
@classmethod
|
||||
def to_task(cls, task: HumanTaskModel) -> Task:
|
||||
"""To_task."""
|
||||
can_complete = False
|
||||
for user in task.human_task_users:
|
||||
if user.user_id == g.user.id:
|
||||
can_complete = True
|
||||
break
|
||||
|
||||
new_task = Task(
|
||||
task.task_id,
|
||||
task.task_name,
|
||||
task.task_title,
|
||||
task.task_type,
|
||||
task.task_status,
|
||||
can_complete,
|
||||
process_instance_id=task.process_instance_id,
|
||||
)
|
||||
if hasattr(task, "process_model_display_name"):
|
||||
|
|
|
@ -88,6 +88,7 @@ class Task:
|
|||
title: str,
|
||||
type: str,
|
||||
state: str,
|
||||
can_complete: bool,
|
||||
lane: Union[str, None] = None,
|
||||
form: None = None,
|
||||
documentation: str = "",
|
||||
|
@ -116,6 +117,7 @@ class Task:
|
|||
self.title = title
|
||||
self.type = type
|
||||
self.state = state
|
||||
self.can_complete = can_complete
|
||||
self.form = form
|
||||
self.documentation = documentation
|
||||
self.lane = lane
|
||||
|
@ -160,6 +162,7 @@ class Task:
|
|||
"type": self.type,
|
||||
"state": self.state,
|
||||
"lane": self.lane,
|
||||
"can_complete": self.can_complete,
|
||||
"form": self.form,
|
||||
"documentation": self.documentation,
|
||||
"data": self.data,
|
||||
|
|
|
@ -10,7 +10,7 @@ from typing import Tuple
|
|||
from urllib.parse import unquote
|
||||
|
||||
import sentry_sdk
|
||||
from flask import current_app
|
||||
from flask import current_app, g
|
||||
from SpiffWorkflow.bpmn.specs.events.IntermediateEvent import _BoundaryEventParent # type: ignore
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
|
||||
|
@ -26,7 +26,8 @@ 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
|
||||
from spiffworkflow_backend.services.authorization_service import AuthorizationService, HumanTaskNotFoundError, \
|
||||
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 (
|
||||
|
@ -422,6 +423,18 @@ class ProcessInstanceService:
|
|||
else:
|
||||
lane = None
|
||||
|
||||
# Check for a human task, and if it exists, check to see if the current user
|
||||
# can complete it.
|
||||
can_complete = False
|
||||
try:
|
||||
AuthorizationService.assert_user_can_complete_spiff_task(processor.process_instance_model.id, spiff_task,
|
||||
g.user)
|
||||
can_complete = True
|
||||
except HumanTaskNotFoundError as e:
|
||||
can_complete = False
|
||||
except UserDoesNotHaveAccessToTaskError as ude:
|
||||
can_complete = False
|
||||
|
||||
if hasattr(spiff_task.task_spec, "spec"):
|
||||
call_activity_process_identifier = spiff_task.task_spec.spec
|
||||
else:
|
||||
|
@ -439,6 +452,7 @@ class ProcessInstanceService:
|
|||
spiff_task.task_spec.description,
|
||||
task_type,
|
||||
spiff_task.get_state_name(),
|
||||
can_complete=can_complete,
|
||||
lane=lane,
|
||||
process_identifier=spiff_task.task_spec._wf_spec.name,
|
||||
process_instance_id=processor.process_instance_model.id,
|
||||
|
|
|
@ -41,9 +41,7 @@ export interface Task {
|
|||
id: number;
|
||||
guid: string;
|
||||
bpmn_identifier: string;
|
||||
|
||||
bpmn_name?: string;
|
||||
|
||||
bpmn_process_direct_parent_guid: string;
|
||||
bpmn_process_definition_identifier: string;
|
||||
data: any;
|
||||
|
@ -64,7 +62,7 @@ export interface TaskIds {
|
|||
export interface ProcessInstanceTask {
|
||||
id: string;
|
||||
task_id: string;
|
||||
|
||||
can_complete: boolean;
|
||||
calling_subprocess_task_id: string;
|
||||
created_at_in_seconds: number;
|
||||
current_user_is_potential_owner: number;
|
||||
|
|
|
@ -9,6 +9,7 @@ import { getBasicHeaders } from '../services/HttpService';
|
|||
// @ts-ignore
|
||||
import InstructionsForEndUser from '../components/InstructionsForEndUser';
|
||||
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
|
||||
import { ProcessInstanceTask } from '../interfaces';
|
||||
|
||||
export default function ProcessInterstitial() {
|
||||
const [data, setData] = useState<any[]>([]);
|
||||
|
@ -39,7 +40,11 @@ export default function ProcessInterstitial() {
|
|||
useEffect(() => {
|
||||
// Added this seperate use effect so that the timer interval will be cleared if
|
||||
// we end up redirecting back to the TaskShow page.
|
||||
if (lastTask && ['User Task', 'Manual Task'].includes(lastTask.type)) {
|
||||
if (
|
||||
lastTask &&
|
||||
lastTask.can_complete &&
|
||||
['User Task', 'Manual Task'].includes(lastTask.type)
|
||||
) {
|
||||
const timerId = setInterval(() => {
|
||||
navigate(`/tasks/${lastTask.process_instance_id}/${lastTask.id}`);
|
||||
}, 1000);
|
||||
|
@ -52,6 +57,12 @@ export default function ProcessInterstitial() {
|
|||
if (status !== 'running') {
|
||||
setStatus(lastTask.state);
|
||||
}
|
||||
if (
|
||||
!lastTask.can_complete &&
|
||||
['User Task', 'Manual Task'].includes(lastTask.type)
|
||||
) {
|
||||
setStatus('LOCKED');
|
||||
}
|
||||
console.log(`Status is : ${status}}`);
|
||||
console.log('last task is : ', lastTask);
|
||||
switch (status) {
|
||||
|
@ -63,10 +74,25 @@ export default function ProcessInterstitial() {
|
|||
return <img src="/interstitial/clock.png" alt="Waiting ...." />;
|
||||
case 'COMPLETED':
|
||||
return <img src="/interstitial/checkmark.png" alt="Completed" />;
|
||||
case 'LOCKED':
|
||||
return <img src="/interstitial/lock.png" alt="Locked, Waiting on someone else." />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const userMessage = (myTask: ProcessInstanceTask) => {
|
||||
if (
|
||||
!myTask.can_complete &&
|
||||
['User Task', 'Manual Task'].includes(myTask.type)
|
||||
) {
|
||||
return (
|
||||
<div>This task is assigned to another user or group to complete. </div>
|
||||
);
|
||||
}
|
||||
return <InstructionsForEndUser task={myTask} />;
|
||||
};
|
||||
|
||||
if (lastTask) {
|
||||
return (
|
||||
<>
|
||||
|
@ -81,7 +107,7 @@ export default function ProcessInterstitial() {
|
|||
[`Process Instance Id: ${lastTask.process_instance_id}`],
|
||||
]}
|
||||
/>
|
||||
<h1 style={{display: 'inline-flex', alignItems: 'center'}}>
|
||||
<h1 style={{ display: 'inline-flex', alignItems: 'center' }}>
|
||||
{processStatusImage()}
|
||||
{lastTask.process_model_display_name}: {lastTask.process_instance_id}
|
||||
</h1>
|
||||
|
@ -89,18 +115,20 @@ export default function ProcessInterstitial() {
|
|||
<Grid condensed fullWidth>
|
||||
<Column md={6} lg={8} sm={4}>
|
||||
<table className="table table-bordered">
|
||||
<tbody>
|
||||
{data &&
|
||||
data.map((d) => (
|
||||
<tr key={d.id}>
|
||||
<td><h3>{d.title}</h3></td>
|
||||
<td>
|
||||
<InstructionsForEndUser task={d} />
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<tbody>
|
||||
{data &&
|
||||
data.map((d) => (
|
||||
<tr key={d.id}>
|
||||
<td>
|
||||
<h3>{d.title}</h3>
|
||||
</td>
|
||||
<td>
|
||||
<p>{userMessage(d)}</p>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</Column>
|
||||
</Grid>
|
||||
</>
|
||||
|
|
|
@ -91,8 +91,6 @@ function TypeAheadWidget({
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
class UnexpectedHumanTaskType extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
|
@ -121,11 +119,24 @@ export default function TaskShow() {
|
|||
// eslint-disable-next-line sonarjs/no-duplicate-string
|
||||
const supportedHumanTaskTypes = ['User Task', 'Manual Task'];
|
||||
|
||||
const navigateToInterstitial = (myTask: ProcessInstanceTask) => {
|
||||
navigate(
|
||||
`/process/${modifyProcessIdentifierForPathParam(
|
||||
myTask.process_model_identifier
|
||||
)}/${myTask.process_instance_id}/interstitial`
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
const processResult = (result: ProcessInstanceTask) => {
|
||||
setTask(result);
|
||||
setDisabled(false);
|
||||
|
||||
if (!result.can_complete) {
|
||||
navigateToInterstitial(result);
|
||||
}
|
||||
|
||||
/* Disable call to load previous tasks -- do not display menu.
|
||||
const url = `/v1.0/process-instances/for-me/${modifyProcessIdentifierForPathParam(
|
||||
result.process_model_identifier
|
||||
|
@ -162,14 +173,10 @@ export default function TaskShow() {
|
|||
if (result.ok) {
|
||||
navigate(`/tasks`);
|
||||
} else if (result.process_instance_id) {
|
||||
if (result.type in supportedHumanTaskTypes) {
|
||||
if (result.can_complete) {
|
||||
navigate(`/tasks/${result.process_instance_id}/${result.id}`);
|
||||
} else {
|
||||
navigate(
|
||||
`/process/${modifyProcessIdentifierForPathParam(
|
||||
result.process_model_identifier
|
||||
)}/${result.process_instance_id}/interstitial`
|
||||
);
|
||||
navigateToInterstitial(result);
|
||||
}
|
||||
} else {
|
||||
addError(result);
|
||||
|
|
Loading…
Reference in New Issue