do not allow editing task data for process instances that are not suspended and some code cleanup w/ burnettk
This commit is contained in:
parent
e68d19d8b3
commit
a096605047
|
@ -1,5 +1,3 @@
|
||||||
from __future__ import with_statement
|
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
from logging.config import fileConfig
|
from logging.config import fileConfig
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,10 @@ class ProcessInstanceNotFoundError(Exception):
|
||||||
"""ProcessInstanceNotFoundError."""
|
"""ProcessInstanceNotFoundError."""
|
||||||
|
|
||||||
|
|
||||||
|
class ProcessInstanceTaskDataCannotBeUpdatedError(Exception):
|
||||||
|
"""ProcessInstanceTaskDataCannotBeUpdatedError."""
|
||||||
|
|
||||||
|
|
||||||
class NavigationItemSchema(Schema):
|
class NavigationItemSchema(Schema):
|
||||||
"""NavigationItemSchema."""
|
"""NavigationItemSchema."""
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,9 @@ from spiffworkflow_backend.models.process_instance import ProcessInstanceApiSche
|
||||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
from spiffworkflow_backend.models.process_instance import ProcessInstanceModel
|
||||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema
|
from spiffworkflow_backend.models.process_instance import ProcessInstanceModelSchema
|
||||||
from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus
|
from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus
|
||||||
|
from spiffworkflow_backend.models.process_instance import (
|
||||||
|
ProcessInstanceTaskDataCannotBeUpdatedError,
|
||||||
|
)
|
||||||
from spiffworkflow_backend.models.process_instance_metadata import (
|
from spiffworkflow_backend.models.process_instance_metadata import (
|
||||||
ProcessInstanceMetadataModel,
|
ProcessInstanceMetadataModel,
|
||||||
)
|
)
|
||||||
|
@ -2110,6 +2113,11 @@ def update_task_data(
|
||||||
ProcessInstanceModel.id == int(process_instance_id)
|
ProcessInstanceModel.id == int(process_instance_id)
|
||||||
).first()
|
).first()
|
||||||
if process_instance:
|
if process_instance:
|
||||||
|
if process_instance.status != "suspended":
|
||||||
|
raise ProcessInstanceTaskDataCannotBeUpdatedError(
|
||||||
|
f"The process instance needs to be suspended to udpate the task-data. It is currently: {process_instance.status}"
|
||||||
|
)
|
||||||
|
|
||||||
process_instance_bpmn_json_dict = json.loads(process_instance.bpmn_json)
|
process_instance_bpmn_json_dict = json.loads(process_instance.bpmn_json)
|
||||||
if "new_task_data" in body:
|
if "new_task_data" in body:
|
||||||
new_task_data_str: str = body["new_task_data"]
|
new_task_data_str: str = body["new_task_data"]
|
||||||
|
|
|
@ -100,7 +100,7 @@ class GitService:
|
||||||
branch_name_to_use,
|
branch_name_to_use,
|
||||||
git_username,
|
git_username,
|
||||||
git_email,
|
git_email,
|
||||||
current_app.config['GIT_USER_PASSWORD']
|
current_app.config["GIT_USER_PASSWORD"],
|
||||||
]
|
]
|
||||||
return cls.run_shell_command_to_get_stdout(shell_command)
|
return cls.run_shell_command_to_get_stdout(shell_command)
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,10 @@ export interface ProcessInstance {
|
||||||
id: number;
|
id: number;
|
||||||
process_model_identifier: string;
|
process_model_identifier: string;
|
||||||
process_model_display_name: string;
|
process_model_display_name: string;
|
||||||
|
status: string;
|
||||||
|
start_in_seconds: number | null;
|
||||||
|
end_in_seconds: number | null;
|
||||||
|
bpmn_xml_file_contents?: string;
|
||||||
spiff_step?: number;
|
spiff_step?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -183,29 +183,23 @@ export default function ProcessInstanceShow() {
|
||||||
return taskIds;
|
return taskIds;
|
||||||
};
|
};
|
||||||
|
|
||||||
const currentSpiffStep = (processInstanceToUse: any) => {
|
const currentSpiffStep = () => {
|
||||||
if (typeof params.spiff_step === 'undefined') {
|
if (processInstance && typeof params.spiff_step === 'undefined') {
|
||||||
return processInstanceToUse.spiff_step;
|
return processInstance.spiff_step || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return Number(params.spiff_step);
|
return Number(params.spiff_step);
|
||||||
};
|
};
|
||||||
|
|
||||||
const showingFirstSpiffStep = (processInstanceToUse: any) => {
|
const showingFirstSpiffStep = () => {
|
||||||
return currentSpiffStep(processInstanceToUse) === 1;
|
return currentSpiffStep() === 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
const showingLastSpiffStep = (processInstanceToUse: any) => {
|
const showingLastSpiffStep = () => {
|
||||||
return (
|
return processInstance && currentSpiffStep() === processInstance.spiff_step;
|
||||||
currentSpiffStep(processInstanceToUse) === processInstanceToUse.spiff_step
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const spiffStepLink = (
|
const spiffStepLink = (label: any, distance: number) => {
|
||||||
processInstanceToUse: any,
|
|
||||||
label: any,
|
|
||||||
distance: number
|
|
||||||
) => {
|
|
||||||
const processIdentifier = searchParams.get('process_identifier');
|
const processIdentifier = searchParams.get('process_identifier');
|
||||||
let queryParams = '';
|
let queryParams = '';
|
||||||
if (processIdentifier) {
|
if (processIdentifier) {
|
||||||
|
@ -217,32 +211,35 @@ export default function ProcessInstanceShow() {
|
||||||
data-qa="process-instance-step-link"
|
data-qa="process-instance-step-link"
|
||||||
to={`/admin/process-instances/${params.process_model_id}/${
|
to={`/admin/process-instances/${params.process_model_id}/${
|
||||||
params.process_instance_id
|
params.process_instance_id
|
||||||
}/${currentSpiffStep(processInstanceToUse) + distance}${queryParams}`}
|
}/${currentSpiffStep() + distance}${queryParams}`}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const previousStepLink = (processInstanceToUse: any) => {
|
const previousStepLink = () => {
|
||||||
if (showingFirstSpiffStep(processInstanceToUse)) {
|
if (showingFirstSpiffStep()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return spiffStepLink(processInstanceToUse, <CaretLeft />, -1);
|
return spiffStepLink(<CaretLeft />, -1);
|
||||||
};
|
};
|
||||||
|
|
||||||
const nextStepLink = (processInstanceToUse: any) => {
|
const nextStepLink = () => {
|
||||||
if (showingLastSpiffStep(processInstanceToUse)) {
|
if (showingLastSpiffStep()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return spiffStepLink(processInstanceToUse, <CaretRight />, 1);
|
return spiffStepLink(<CaretRight />, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getInfoTag = (processInstanceToUse: any) => {
|
const getInfoTag = () => {
|
||||||
|
if (!processInstance) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const currentEndDate = convertSecondsToFormattedDateTime(
|
const currentEndDate = convertSecondsToFormattedDateTime(
|
||||||
processInstanceToUse.end_in_seconds
|
processInstance.end_in_seconds || 0
|
||||||
);
|
);
|
||||||
let currentEndDateTag;
|
let currentEndDateTag;
|
||||||
if (currentEndDate) {
|
if (currentEndDate) {
|
||||||
|
@ -253,7 +250,7 @@ export default function ProcessInstanceShow() {
|
||||||
</Column>
|
</Column>
|
||||||
<Column sm={3} md={3} lg={3} className="grid-date">
|
<Column sm={3} md={3} lg={3} className="grid-date">
|
||||||
{convertSecondsToFormattedDateTime(
|
{convertSecondsToFormattedDateTime(
|
||||||
processInstanceToUse.end_in_seconds
|
processInstance.end_in_seconds || 0
|
||||||
) || 'N/A'}
|
) || 'N/A'}
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -261,13 +258,13 @@ export default function ProcessInstanceShow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
let statusIcon = <InProgress />;
|
let statusIcon = <InProgress />;
|
||||||
if (processInstanceToUse.status === 'suspended') {
|
if (processInstance.status === 'suspended') {
|
||||||
statusIcon = <PauseOutline />;
|
statusIcon = <PauseOutline />;
|
||||||
} else if (processInstanceToUse.status === 'complete') {
|
} else if (processInstance.status === 'complete') {
|
||||||
statusIcon = <Checkmark />;
|
statusIcon = <Checkmark />;
|
||||||
} else if (processInstanceToUse.status === 'terminated') {
|
} else if (processInstance.status === 'terminated') {
|
||||||
statusIcon = <StopOutline />;
|
statusIcon = <StopOutline />;
|
||||||
} else if (processInstanceToUse.status === 'error') {
|
} else if (processInstance.status === 'error') {
|
||||||
statusIcon = <Warning />;
|
statusIcon = <Warning />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -279,7 +276,7 @@ export default function ProcessInstanceShow() {
|
||||||
</Column>
|
</Column>
|
||||||
<Column sm={3} md={3} lg={3} className="grid-date">
|
<Column sm={3} md={3} lg={3} className="grid-date">
|
||||||
{convertSecondsToFormattedDateTime(
|
{convertSecondsToFormattedDateTime(
|
||||||
processInstanceToUse.start_in_seconds
|
processInstance.start_in_seconds || 0
|
||||||
)}
|
)}
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -290,7 +287,7 @@ export default function ProcessInstanceShow() {
|
||||||
</Column>
|
</Column>
|
||||||
<Column sm={3} md={3} lg={3}>
|
<Column sm={3} md={3} lg={3}>
|
||||||
<Tag type="gray" size="sm" className="span-tag">
|
<Tag type="gray" size="sm" className="span-tag">
|
||||||
{processInstanceToUse.status} {statusIcon}
|
{processInstance.status} {statusIcon}
|
||||||
</Tag>
|
</Tag>
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -333,11 +330,10 @@ export default function ProcessInstanceShow() {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const terminateButton = (processInstanceToUse: any) => {
|
const terminateButton = () => {
|
||||||
if (
|
if (
|
||||||
['complete', 'terminated', 'error'].indexOf(
|
processInstance &&
|
||||||
processInstanceToUse.status
|
!['complete', 'terminated', 'error'].includes(processInstance.status)
|
||||||
) === -1
|
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<ButtonWithConfirmation
|
<ButtonWithConfirmation
|
||||||
|
@ -345,7 +341,7 @@ export default function ProcessInstanceShow() {
|
||||||
renderIcon={StopOutline}
|
renderIcon={StopOutline}
|
||||||
iconDescription="Terminate"
|
iconDescription="Terminate"
|
||||||
hasIconOnly
|
hasIconOnly
|
||||||
description={`Terminate Process Instance: ${processInstanceToUse.id}`}
|
description={`Terminate Process Instance: ${processInstance.id}`}
|
||||||
onConfirmation={terminateProcessInstance}
|
onConfirmation={terminateProcessInstance}
|
||||||
confirmButtonLabel="Terminate"
|
confirmButtonLabel="Terminate"
|
||||||
/>
|
/>
|
||||||
|
@ -354,11 +350,12 @@ export default function ProcessInstanceShow() {
|
||||||
return <div />;
|
return <div />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const suspendButton = (processInstanceToUse: any) => {
|
const suspendButton = () => {
|
||||||
if (
|
if (
|
||||||
['complete', 'terminated', 'error', 'suspended'].indexOf(
|
processInstance &&
|
||||||
processInstanceToUse.status
|
!['complete', 'terminated', 'error', 'suspended'].includes(
|
||||||
) === -1
|
processInstance.status
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
@ -374,8 +371,8 @@ export default function ProcessInstanceShow() {
|
||||||
return <div />;
|
return <div />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const resumeButton = (processInstanceToUse: any) => {
|
const resumeButton = () => {
|
||||||
if (processInstanceToUse.status === 'suspended') {
|
if (processInstance && processInstance.status === 'suspended') {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
onClick={resumeProcessInstance}
|
onClick={resumeProcessInstance}
|
||||||
|
@ -450,9 +447,11 @@ export default function ProcessInstanceShow() {
|
||||||
|
|
||||||
const canEditTaskData = (task: any) => {
|
const canEditTaskData = (task: any) => {
|
||||||
return (
|
return (
|
||||||
|
processInstance &&
|
||||||
ability.can('PUT', targetUris.processInstanceTaskListDataPath) &&
|
ability.can('PUT', targetUris.processInstanceTaskListDataPath) &&
|
||||||
task.state === 'READY' &&
|
task.state === 'READY' &&
|
||||||
showingLastSpiffStep(processInstance as any)
|
processInstance.status === 'suspended' &&
|
||||||
|
showingLastSpiffStep()
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -475,7 +474,7 @@ export default function ProcessInstanceShow() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveTaskDataFailure = (result: any) => {
|
const saveTaskDataFailure = (result: any) => {
|
||||||
setErrorMessage({ message: result.toString() });
|
setErrorMessage({ message: result.message });
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveTaskData = () => {
|
const saveTaskData = () => {
|
||||||
|
@ -591,35 +590,37 @@ export default function ProcessInstanceShow() {
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const stepsElement = (processInstanceToUse: any) => {
|
const stepsElement = () => {
|
||||||
|
if (!processInstance) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Grid condensed fullWidth>
|
<Grid condensed fullWidth>
|
||||||
<Column sm={3} md={3} lg={3}>
|
<Column sm={3} md={3} lg={3}>
|
||||||
<Stack orientation="horizontal" gap={3} className="smaller-text">
|
<Stack orientation="horizontal" gap={3} className="smaller-text">
|
||||||
{previousStepLink(processInstanceToUse)}
|
{previousStepLink()}
|
||||||
Step {currentSpiffStep(processInstanceToUse)} of{' '}
|
Step {currentSpiffStep()} of {processInstance.spiff_step}
|
||||||
{processInstanceToUse.spiff_step}
|
{nextStepLink()}
|
||||||
{nextStepLink(processInstanceToUse)}
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Column>
|
</Column>
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const buttonIcons = (processInstanceToUse: any) => {
|
const buttonIcons = () => {
|
||||||
const elements = [];
|
const elements = [];
|
||||||
if (
|
if (
|
||||||
ability.can('POST', `${targetUris.processInstanceActionPath}/terminate`)
|
ability.can('POST', `${targetUris.processInstanceActionPath}/terminate`)
|
||||||
) {
|
) {
|
||||||
elements.push(terminateButton(processInstanceToUse));
|
elements.push(terminateButton());
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
ability.can('POST', `${targetUris.processInstanceActionPath}/suspend`)
|
ability.can('POST', `${targetUris.processInstanceActionPath}/suspend`)
|
||||||
) {
|
) {
|
||||||
elements.push(suspendButton(processInstanceToUse));
|
elements.push(suspendButton());
|
||||||
}
|
}
|
||||||
if (ability.can('POST', `${targetUris.processInstanceActionPath}/resume`)) {
|
if (ability.can('POST', `${targetUris.processInstanceActionPath}/resume`)) {
|
||||||
elements.push(resumeButton(processInstanceToUse));
|
elements.push(resumeButton());
|
||||||
}
|
}
|
||||||
if (ability.can('DELETE', targetUris.processInstanceActionPath)) {
|
if (ability.can('DELETE', targetUris.processInstanceActionPath)) {
|
||||||
elements.push(
|
elements.push(
|
||||||
|
@ -629,7 +630,7 @@ export default function ProcessInstanceShow() {
|
||||||
renderIcon={TrashCan}
|
renderIcon={TrashCan}
|
||||||
iconDescription="Delete"
|
iconDescription="Delete"
|
||||||
hasIconOnly
|
hasIconOnly
|
||||||
description={`Delete Process Instance: ${processInstanceToUse.id}`}
|
description={`Delete Process Instance: ${processInstance}`}
|
||||||
onConfirmation={deleteProcessInstance}
|
onConfirmation={deleteProcessInstance}
|
||||||
confirmButtonLabel="Delete"
|
confirmButtonLabel="Delete"
|
||||||
/>
|
/>
|
||||||
|
@ -639,7 +640,6 @@ export default function ProcessInstanceShow() {
|
||||||
};
|
};
|
||||||
|
|
||||||
if (processInstance && (tasks || tasksCallHadError)) {
|
if (processInstance && (tasks || tasksCallHadError)) {
|
||||||
const processInstanceToUse = processInstance as any;
|
|
||||||
const taskIds = getTaskIds();
|
const taskIds = getTaskIds();
|
||||||
const processModelId = unModifyProcessIdentifierForPathParam(
|
const processModelId = unModifyProcessIdentifierForPathParam(
|
||||||
params.process_model_id ? params.process_model_id : ''
|
params.process_model_id ? params.process_model_id : ''
|
||||||
|
@ -655,26 +655,26 @@ export default function ProcessInstanceShow() {
|
||||||
entityType: 'process-model-id',
|
entityType: 'process-model-id',
|
||||||
linkLastItem: true,
|
linkLastItem: true,
|
||||||
},
|
},
|
||||||
[`Process Instance Id: ${processInstanceToUse.id}`],
|
[`Process Instance Id: ${processInstance.id}`],
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<Stack orientation="horizontal" gap={1}>
|
<Stack orientation="horizontal" gap={1}>
|
||||||
<h1 className="with-icons">
|
<h1 className="with-icons">
|
||||||
Process Instance Id: {processInstanceToUse.id}
|
Process Instance Id: {processInstance.id}
|
||||||
</h1>
|
</h1>
|
||||||
{buttonIcons(processInstanceToUse)}
|
{buttonIcons()}
|
||||||
</Stack>
|
</Stack>
|
||||||
<br />
|
<br />
|
||||||
<br />
|
<br />
|
||||||
{getInfoTag(processInstanceToUse)}
|
{getInfoTag()}
|
||||||
<br />
|
<br />
|
||||||
{taskDataDisplayArea()}
|
{taskDataDisplayArea()}
|
||||||
{stepsElement(processInstanceToUse)}
|
{stepsElement()}
|
||||||
<br />
|
<br />
|
||||||
<ReactDiagramEditor
|
<ReactDiagramEditor
|
||||||
processModelId={processModelId || ''}
|
processModelId={processModelId || ''}
|
||||||
diagramXML={processInstanceToUse.bpmn_xml_file_contents || ''}
|
diagramXML={processInstance.bpmn_xml_file_contents || ''}
|
||||||
fileName={processInstanceToUse.bpmn_xml_file_contents || ''}
|
fileName={processInstance.bpmn_xml_file_contents || ''}
|
||||||
readyOrWaitingProcessInstanceTasks={taskIds.readyOrWaiting}
|
readyOrWaitingProcessInstanceTasks={taskIds.readyOrWaiting}
|
||||||
completedProcessInstanceTasks={taskIds.completed}
|
completedProcessInstanceTasks={taskIds.completed}
|
||||||
diagramType="readonly"
|
diagramType="readonly"
|
||||||
|
|
Loading…
Reference in New Issue