Squashed 'spiffworkflow-frontend/' changes from 647a428c7..8afeb64f1

8afeb64f1 Front end changes to allow editing task data (#4)

git-subtree-dir: spiffworkflow-frontend
git-subtree-split: 8afeb64f153ed1d721a18113d5196dd9644fa0a2
This commit is contained in:
Dan 2022-10-27 14:57:29 -04:00
parent 3a0b6f634c
commit fb0ad7bfc5
1 changed files with 127 additions and 13 deletions

View File

@ -1,4 +1,5 @@
import { useEffect, useState } from 'react'; import { useContext, useEffect, useState } from 'react';
import Editor from '@monaco-editor/react';
import { useParams, useNavigate, Link } from 'react-router-dom'; import { useParams, useNavigate, Link } from 'react-router-dom';
import { Button, Modal, Stack } from 'react-bootstrap'; import { Button, Modal, Stack } from 'react-bootstrap';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb'; import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
@ -6,6 +7,7 @@ import HttpService from '../services/HttpService';
import ReactDiagramEditor from '../components/ReactDiagramEditor'; import ReactDiagramEditor from '../components/ReactDiagramEditor';
import { convertSecondsToFormattedDate } from '../helpers'; import { convertSecondsToFormattedDate } from '../helpers';
import ButtonWithConfirmation from '../components/ButtonWithConfirmation'; import ButtonWithConfirmation from '../components/ButtonWithConfirmation';
import ErrorContext from '../contexts/ErrorContext';
export default function ProcessInstanceShow() { export default function ProcessInstanceShow() {
const navigate = useNavigate(); const navigate = useNavigate();
@ -14,6 +16,10 @@ export default function ProcessInstanceShow() {
const [processInstance, setProcessInstance] = useState(null); const [processInstance, setProcessInstance] = useState(null);
const [tasks, setTasks] = useState<Array<object> | null>(null); const [tasks, setTasks] = useState<Array<object> | null>(null);
const [taskToDisplay, setTaskToDisplay] = useState<object | null>(null); const [taskToDisplay, setTaskToDisplay] = useState<object | null>(null);
const [taskDataToDisplay, setTaskDataToDisplay] = useState<string>('');
const [editingTaskData, setEditingTaskData] = useState<boolean>(false);
const setErrorMessage = (useContext as any)(ErrorContext)[1];
const navigateToProcessInstances = (_result: any) => { const navigateToProcessInstances = (_result: any) => {
navigate( navigate(
@ -168,19 +174,29 @@ export default function ProcessInstanceShow() {
return <div />; return <div />;
}; };
const initializeTaskDataToDisplay = (task: any) => {
if (task == null) {
setTaskDataToDisplay('');
} else {
setTaskDataToDisplay(JSON.stringify(task.data, null, 2));
}
};
const handleClickedDiagramTask = (shapeElement: any) => { const handleClickedDiagramTask = (shapeElement: any) => {
if (tasks) { if (tasks) {
const matchingTask = tasks.find( const matchingTask: any = tasks.find(
(task: any) => task.name === shapeElement.id (task: any) => task.name === shapeElement.id
); );
if (matchingTask) { if (matchingTask) {
setTaskToDisplay(matchingTask); setTaskToDisplay(matchingTask);
initializeTaskDataToDisplay(matchingTask);
} }
} }
}; };
const handleTaskDataDisplayClose = () => { const handleTaskDataDisplayClose = () => {
setTaskToDisplay(null); setTaskToDisplay(null);
initializeTaskDataToDisplay(null);
}; };
const getTaskById = (taskId: string) => { const getTaskById = (taskId: string) => {
@ -211,12 +227,57 @@ export default function ProcessInstanceShow() {
} }
}; };
const taskDataDisplayArea = () => { const canEditTaskData = (task: any) => {
const taskToUse: any = taskToDisplay; return task.state === 'READY';
if (taskToDisplay) { };
let createScriptUnitTestElement = null;
if (taskToUse.type === 'Script Task') { const cancelEditingTaskData = () => {
createScriptUnitTestElement = ( setEditingTaskData(false);
initializeTaskDataToDisplay(taskToDisplay);
setErrorMessage(null);
};
const taskDataStringToObject = (dataString: string) => {
return JSON.parse(dataString);
};
const saveTaskDataResult = (_: any) => {
setEditingTaskData(false);
const dataObject = taskDataStringToObject(taskDataToDisplay);
const taskToDisplayCopy = { ...taskToDisplay, data: dataObject }; // spread operator
setTaskToDisplay(taskToDisplayCopy);
refreshPage();
};
const saveTaskDataFailure = (result: any) => {
setErrorMessage({ message: result.toString() });
};
const saveTaskData = () => {
if (!taskToDisplay) {
return;
}
setErrorMessage(null);
// taskToUse is copy of taskToDisplay, with taskDataToDisplay in data attribute
const taskToUse: any = { ...taskToDisplay, data: taskDataToDisplay };
HttpService.makeCallToBackend({
path: `/process-instances/${params.process_instance_id}/task/${taskToUse.id}/update`,
httpMethod: 'POST',
successCallback: saveTaskDataResult,
failureCallback: saveTaskDataFailure,
postBody: {
new_task_data: taskToUse.data,
},
});
};
const taskDataButtons = (task: any) => {
const buttons = [];
if (task.type === 'Script Task') {
buttons.push(
<Button <Button
data-qa="create-script-unit-test-button" data-qa="create-script-unit-test-button"
onClick={createScriptUnitTest} onClick={createScriptUnitTest}
@ -225,15 +286,68 @@ export default function ProcessInstanceShow() {
</Button> </Button>
); );
} }
if (canEditTaskData(task)) {
if (editingTaskData) {
buttons.push(
<Button
data-qa="create-script-unit-test-button"
onClick={saveTaskData}
>
Save
</Button>
);
buttons.push(
<Button
data-qa="create-script-unit-test-button"
onClick={cancelEditingTaskData}
>
Cancel
</Button>
);
} else {
buttons.push(
<Button
data-qa="create-script-unit-test-button"
onClick={() => setEditingTaskData(true)}
>
Edit
</Button>
);
}
}
return buttons;
};
const taskDataContainer = () => {
return editingTaskData ? (
<Editor
height={600}
width="auto"
defaultLanguage="json"
defaultValue={taskDataToDisplay}
onChange={(value) => setTaskDataToDisplay(value || '')}
/>
) : (
<pre>{taskDataToDisplay}</pre>
);
};
const taskDataDisplayArea = () => {
const taskToUse: any = { ...taskToDisplay, data: taskDataToDisplay };
if (taskToDisplay) {
return ( return (
<Modal show={!!taskToUse} onHide={handleTaskDataDisplayClose}> <Modal show={!!taskToUse} onHide={handleTaskDataDisplayClose}>
<Modal.Header closeButton> <Modal.Header closeButton>
<Modal.Title> <Modal.Title>
<Stack direction="horizontal" gap={2}>
{taskToUse.name} ({taskToUse.type}): {taskToUse.state} {taskToUse.name} ({taskToUse.type}): {taskToUse.state}
{createScriptUnitTestElement} {taskDataButtons(taskToUse)}
</Stack>
</Modal.Title> </Modal.Title>
</Modal.Header> </Modal.Header>
<pre>{JSON.stringify(taskToUse.data, null, 2)}</pre> {taskDataContainer()}
</Modal> </Modal>
); );
} }