do not allow editing task data for process instances that are not suspended and some code cleanup w/ burnettk

This commit is contained in:
jasquat 2022-12-19 11:54:22 -05:00
parent e68d19d8b3
commit a096605047
6 changed files with 78 additions and 64 deletions

View File

@ -1,5 +1,3 @@
from __future__ import with_statement
import logging
from logging.config import fileConfig

View File

@ -26,6 +26,10 @@ class ProcessInstanceNotFoundError(Exception):
"""ProcessInstanceNotFoundError."""
class ProcessInstanceTaskDataCannotBeUpdatedError(Exception):
"""ProcessInstanceTaskDataCannotBeUpdatedError."""
class NavigationItemSchema(Schema):
"""NavigationItemSchema."""

View File

@ -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 ProcessInstanceModelSchema
from spiffworkflow_backend.models.process_instance import ProcessInstanceStatus
from spiffworkflow_backend.models.process_instance import (
ProcessInstanceTaskDataCannotBeUpdatedError,
)
from spiffworkflow_backend.models.process_instance_metadata import (
ProcessInstanceMetadataModel,
)
@ -2110,6 +2113,11 @@ def update_task_data(
ProcessInstanceModel.id == int(process_instance_id)
).first()
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)
if "new_task_data" in body:
new_task_data_str: str = body["new_task_data"]

View File

@ -100,7 +100,7 @@ class GitService:
branch_name_to_use,
git_username,
git_email,
current_app.config['GIT_USER_PASSWORD']
current_app.config["GIT_USER_PASSWORD"],
]
return cls.run_shell_command_to_get_stdout(shell_command)

View File

@ -52,6 +52,10 @@ export interface ProcessInstance {
id: number;
process_model_identifier: 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;
}

View File

@ -183,29 +183,23 @@ export default function ProcessInstanceShow() {
return taskIds;
};
const currentSpiffStep = (processInstanceToUse: any) => {
if (typeof params.spiff_step === 'undefined') {
return processInstanceToUse.spiff_step;
const currentSpiffStep = () => {
if (processInstance && typeof params.spiff_step === 'undefined') {
return processInstance.spiff_step || 0;
}
return Number(params.spiff_step);
};
const showingFirstSpiffStep = (processInstanceToUse: any) => {
return currentSpiffStep(processInstanceToUse) === 1;
const showingFirstSpiffStep = () => {
return currentSpiffStep() === 1;
};
const showingLastSpiffStep = (processInstanceToUse: any) => {
return (
currentSpiffStep(processInstanceToUse) === processInstanceToUse.spiff_step
);
const showingLastSpiffStep = () => {
return processInstance && currentSpiffStep() === processInstance.spiff_step;
};
const spiffStepLink = (
processInstanceToUse: any,
label: any,
distance: number
) => {
const spiffStepLink = (label: any, distance: number) => {
const processIdentifier = searchParams.get('process_identifier');
let queryParams = '';
if (processIdentifier) {
@ -217,32 +211,35 @@ export default function ProcessInstanceShow() {
data-qa="process-instance-step-link"
to={`/admin/process-instances/${params.process_model_id}/${
params.process_instance_id
}/${currentSpiffStep(processInstanceToUse) + distance}${queryParams}`}
}/${currentSpiffStep() + distance}${queryParams}`}
>
{label}
</Link>
);
};
const previousStepLink = (processInstanceToUse: any) => {
if (showingFirstSpiffStep(processInstanceToUse)) {
const previousStepLink = () => {
if (showingFirstSpiffStep()) {
return null;
}
return spiffStepLink(processInstanceToUse, <CaretLeft />, -1);
return spiffStepLink(<CaretLeft />, -1);
};
const nextStepLink = (processInstanceToUse: any) => {
if (showingLastSpiffStep(processInstanceToUse)) {
const nextStepLink = () => {
if (showingLastSpiffStep()) {
return null;
}
return spiffStepLink(processInstanceToUse, <CaretRight />, 1);
return spiffStepLink(<CaretRight />, 1);
};
const getInfoTag = (processInstanceToUse: any) => {
const getInfoTag = () => {
if (!processInstance) {
return null;
}
const currentEndDate = convertSecondsToFormattedDateTime(
processInstanceToUse.end_in_seconds
processInstance.end_in_seconds || 0
);
let currentEndDateTag;
if (currentEndDate) {
@ -253,7 +250,7 @@ export default function ProcessInstanceShow() {
</Column>
<Column sm={3} md={3} lg={3} className="grid-date">
{convertSecondsToFormattedDateTime(
processInstanceToUse.end_in_seconds
processInstance.end_in_seconds || 0
) || 'N/A'}
</Column>
</Grid>
@ -261,13 +258,13 @@ export default function ProcessInstanceShow() {
}
let statusIcon = <InProgress />;
if (processInstanceToUse.status === 'suspended') {
if (processInstance.status === 'suspended') {
statusIcon = <PauseOutline />;
} else if (processInstanceToUse.status === 'complete') {
} else if (processInstance.status === 'complete') {
statusIcon = <Checkmark />;
} else if (processInstanceToUse.status === 'terminated') {
} else if (processInstance.status === 'terminated') {
statusIcon = <StopOutline />;
} else if (processInstanceToUse.status === 'error') {
} else if (processInstance.status === 'error') {
statusIcon = <Warning />;
}
@ -279,7 +276,7 @@ export default function ProcessInstanceShow() {
</Column>
<Column sm={3} md={3} lg={3} className="grid-date">
{convertSecondsToFormattedDateTime(
processInstanceToUse.start_in_seconds
processInstance.start_in_seconds || 0
)}
</Column>
</Grid>
@ -290,7 +287,7 @@ export default function ProcessInstanceShow() {
</Column>
<Column sm={3} md={3} lg={3}>
<Tag type="gray" size="sm" className="span-tag">
{processInstanceToUse.status} {statusIcon}
{processInstance.status} {statusIcon}
</Tag>
</Column>
</Grid>
@ -333,11 +330,10 @@ export default function ProcessInstanceShow() {
);
};
const terminateButton = (processInstanceToUse: any) => {
const terminateButton = () => {
if (
['complete', 'terminated', 'error'].indexOf(
processInstanceToUse.status
) === -1
processInstance &&
!['complete', 'terminated', 'error'].includes(processInstance.status)
) {
return (
<ButtonWithConfirmation
@ -345,7 +341,7 @@ export default function ProcessInstanceShow() {
renderIcon={StopOutline}
iconDescription="Terminate"
hasIconOnly
description={`Terminate Process Instance: ${processInstanceToUse.id}`}
description={`Terminate Process Instance: ${processInstance.id}`}
onConfirmation={terminateProcessInstance}
confirmButtonLabel="Terminate"
/>
@ -354,11 +350,12 @@ export default function ProcessInstanceShow() {
return <div />;
};
const suspendButton = (processInstanceToUse: any) => {
const suspendButton = () => {
if (
['complete', 'terminated', 'error', 'suspended'].indexOf(
processInstanceToUse.status
) === -1
processInstance &&
!['complete', 'terminated', 'error', 'suspended'].includes(
processInstance.status
)
) {
return (
<Button
@ -374,8 +371,8 @@ export default function ProcessInstanceShow() {
return <div />;
};
const resumeButton = (processInstanceToUse: any) => {
if (processInstanceToUse.status === 'suspended') {
const resumeButton = () => {
if (processInstance && processInstance.status === 'suspended') {
return (
<Button
onClick={resumeProcessInstance}
@ -450,9 +447,11 @@ export default function ProcessInstanceShow() {
const canEditTaskData = (task: any) => {
return (
processInstance &&
ability.can('PUT', targetUris.processInstanceTaskListDataPath) &&
task.state === 'READY' &&
showingLastSpiffStep(processInstance as any)
processInstance.status === 'suspended' &&
showingLastSpiffStep()
);
};
@ -475,7 +474,7 @@ export default function ProcessInstanceShow() {
};
const saveTaskDataFailure = (result: any) => {
setErrorMessage({ message: result.toString() });
setErrorMessage({ message: result.message });
};
const saveTaskData = () => {
@ -591,35 +590,37 @@ export default function ProcessInstanceShow() {
return null;
};
const stepsElement = (processInstanceToUse: any) => {
const stepsElement = () => {
if (!processInstance) {
return null;
}
return (
<Grid condensed fullWidth>
<Column sm={3} md={3} lg={3}>
<Stack orientation="horizontal" gap={3} className="smaller-text">
{previousStepLink(processInstanceToUse)}
Step {currentSpiffStep(processInstanceToUse)} of{' '}
{processInstanceToUse.spiff_step}
{nextStepLink(processInstanceToUse)}
{previousStepLink()}
Step {currentSpiffStep()} of {processInstance.spiff_step}
{nextStepLink()}
</Stack>
</Column>
</Grid>
);
};
const buttonIcons = (processInstanceToUse: any) => {
const buttonIcons = () => {
const elements = [];
if (
ability.can('POST', `${targetUris.processInstanceActionPath}/terminate`)
) {
elements.push(terminateButton(processInstanceToUse));
elements.push(terminateButton());
}
if (
ability.can('POST', `${targetUris.processInstanceActionPath}/suspend`)
) {
elements.push(suspendButton(processInstanceToUse));
elements.push(suspendButton());
}
if (ability.can('POST', `${targetUris.processInstanceActionPath}/resume`)) {
elements.push(resumeButton(processInstanceToUse));
elements.push(resumeButton());
}
if (ability.can('DELETE', targetUris.processInstanceActionPath)) {
elements.push(
@ -629,7 +630,7 @@ export default function ProcessInstanceShow() {
renderIcon={TrashCan}
iconDescription="Delete"
hasIconOnly
description={`Delete Process Instance: ${processInstanceToUse.id}`}
description={`Delete Process Instance: ${processInstance}`}
onConfirmation={deleteProcessInstance}
confirmButtonLabel="Delete"
/>
@ -639,7 +640,6 @@ export default function ProcessInstanceShow() {
};
if (processInstance && (tasks || tasksCallHadError)) {
const processInstanceToUse = processInstance as any;
const taskIds = getTaskIds();
const processModelId = unModifyProcessIdentifierForPathParam(
params.process_model_id ? params.process_model_id : ''
@ -655,26 +655,26 @@ export default function ProcessInstanceShow() {
entityType: 'process-model-id',
linkLastItem: true,
},
[`Process Instance Id: ${processInstanceToUse.id}`],
[`Process Instance Id: ${processInstance.id}`],
]}
/>
<Stack orientation="horizontal" gap={1}>
<h1 className="with-icons">
Process Instance Id: {processInstanceToUse.id}
Process Instance Id: {processInstance.id}
</h1>
{buttonIcons(processInstanceToUse)}
{buttonIcons()}
</Stack>
<br />
<br />
{getInfoTag(processInstanceToUse)}
{getInfoTag()}
<br />
{taskDataDisplayArea()}
{stepsElement(processInstanceToUse)}
{stepsElement()}
<br />
<ReactDiagramEditor
processModelId={processModelId || ''}
diagramXML={processInstanceToUse.bpmn_xml_file_contents || ''}
fileName={processInstanceToUse.bpmn_xml_file_contents || ''}
diagramXML={processInstance.bpmn_xml_file_contents || ''}
fileName={processInstance.bpmn_xml_file_contents || ''}
readyOrWaitingProcessInstanceTasks={taskIds.readyOrWaiting}
completedProcessInstanceTasks={taskIds.completed}
diagramType="readonly"