added ability to add and edit json files for forms

This commit is contained in:
jasquat 2022-07-19 14:39:13 -04:00
parent 6c9017c1aa
commit b2963f9725
4 changed files with 276 additions and 80 deletions

View File

@ -35,14 +35,16 @@ describe('process-models', () => {
cy.contains(modelId).should('not.exist');
});
it('can create new bpmn and dmn files', () => {
it('can create new bpmn, dmn, and json files', () => {
const uuid = () => Cypress._.random(0, 1e6);
const id = uuid();
const groupId = 'acceptance-tests-group-one';
const modelDisplayName = `Test Model 2 ${id}`;
const modelId = `test-model-2-${id}`;
const bpmnFileName = `bpmn_test_file_${id}`;
const dmnFileName = `dmn_test_file_${id}`;
const jsonFileName = `json_test_file_${id}`;
cy.contains(groupId).click();
cy.createModel(groupId, modelId, modelDisplayName);
@ -54,6 +56,7 @@ describe('process-models', () => {
cy.contains(`Process Model: ${modelId}`);
cy.contains(`${bpmnFileName}.bpmn`).should('not.exist');
cy.contains(`${dmnFileName}.dmn`).should('not.exist');
cy.contains(`${jsonFileName}.json`).should('not.exist');
// add new bpmn file
cy.contains('Add New BPMN File').click();
@ -84,6 +87,19 @@ describe('process-models', () => {
cy.contains(`Process Model: ${modelId}`);
cy.contains(`${dmnFileName}.dmn`).should('exist');
// add new json file
cy.contains('Add New JSON File').click();
cy.contains(/^Process Model File$/);
// Some reason, cypress evals json strings so we have to escape it it with '{{}'
cy.get('.view-line').type('{{} "test_key": "test_value" }');
cy.contains('Save').click();
cy.get('input[name=file_name]').type(jsonFileName);
cy.contains('Save Changes').click();
cy.contains(`Process Model File: ${jsonFileName}`);
cy.contains(modelId).click();
cy.contains(`Process Model: ${modelId}`);
cy.contains(`${jsonFileName}.json`).should('exist');
cy.contains('Edit process model').click();
cy.contains('Delete process model').click();
cy.url().should('include', `process-groups/${groupId}`);

View File

@ -90,7 +90,11 @@ export default function AdminRoutes() {
element={<ProcessInstanceReportEdit />}
/>
<Route
path="/admin/process-models/:process_group_id/:process_model_id/form/:file_name"
path="/process-models/:process_group_id/:process_model_id/form"
element={<ReactFormEditor />}
/>
<Route
path="/process-models/:process_group_id/:process_model_id/form/:file_name"
element={<ReactFormEditor />}
/>
</Routes>

View File

@ -4,7 +4,6 @@ import { Button, Stack } from 'react-bootstrap';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import FileInput from '../components/FileInput';
import HttpService from '../services/HttpService';
// import ReactFormBuilder from '../components/ReactFormBuilder';
export default function ProcessModelShow() {
const params = useParams();
@ -55,31 +54,119 @@ export default function ProcessModelShow() {
setReloadModel(true);
};
if (Object.keys(processModel).length > 1) {
const processModelFilesTag = (processModel as any).files.map(
(fileBpmn: any) => {
if (fileBpmn.name.match(/\.(dmn|bpmn)$/)) {
let primarySuffix = '';
if (fileBpmn.name === (processModel as any).primary_file_name) {
primarySuffix = '- Primary File';
}
return (
<li key={fileBpmn.name}>
<Link
to={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/file/${fileBpmn.name}`}
>
{fileBpmn.name}
</Link>
{primarySuffix}
</li>
);
const processModelFileList = () => {
let constructedTag;
const tags = (processModel as any).files.map((processModelFile: any) => {
if (processModelFile.name.match(/\.(dmn|bpmn)$/)) {
let primarySuffix = '';
if (processModelFile.name === (processModel as any).primary_file_name) {
primarySuffix = '- Primary File';
}
return <li key={fileBpmn.name}>{fileBpmn.name}</li>;
constructedTag = (
<li key={processModelFile.name}>
<Link
to={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/file/${processModelFile.name}`}
>
{processModelFile.name}
</Link>
{primarySuffix}
</li>
);
} else if (processModelFile.name.match(/\.(json)$/)) {
constructedTag = (
<li key={processModelFile.name}>
<Link
to={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/form/${processModelFile.name}`}
>
{processModelFile.name}
</Link>
</li>
);
} else {
constructedTag = (
<li key={processModelFile.name}>{processModelFile.name}</li>
);
}
);
return constructedTag;
});
return <ul>{tags}</ul>;
};
const processInstancesUl = () => {
return (
<ul>
<li>
<Link
to={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/process-instances`}
data-qa="process-instance-list-link"
>
List
</Link>
</li>
<li>
<Link
to={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/process-instances/reports`}
data-qa="process-instance-reports-link"
>
Reports
</Link>
</li>
</ul>
);
};
const processModelButtons = () => {
return (
<Stack direction="horizontal" gap={3}>
<Button onClick={processInstanceCreateAndRun} variant="primary">
Run
</Button>
<Button
href={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/edit`}
variant="secondary"
>
Edit process model
</Button>
<Button
href={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/file?file_type=bpmn`}
variant="warning"
>
Add New BPMN File
</Button>
<Button
href={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/file?file_type=dmn`}
variant="success"
>
Add New DMN File
</Button>
<Button
href={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/form`}
variant="info"
>
Add New JSON File
</Button>
</Stack>
);
};
if (Object.keys(processModel).length > 1) {
return (
<main style={{ padding: '1rem 0' }}>
<ProcessBreadcrumb
@ -94,66 +181,16 @@ export default function ProcessModelShow() {
onUploadedCallback={onUploadedCallback}
/>
<br />
<Stack direction="horizontal" gap={3}>
<Button onClick={processInstanceCreateAndRun} variant="primary">
Run
</Button>
<Button
href={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/edit`}
variant="secondary"
>
Edit process model
</Button>
<Button
href={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/file?file_type=bpmn`}
variant="warning"
>
Add New BPMN File
</Button>
<Button
href={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/file?file_type=dmn`}
variant="success"
>
Add New DMN File
</Button>
</Stack>
{processModelButtons()}
<br />
<br />
<h3>Process Instances</h3>
<ul>
<li>
<Link
to={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/process-instances`}
data-qa="process-instance-list-link"
>
List
</Link>
</li>
<li>
<Link
to={`/admin/process-models/${
(processModel as any).process_group_id
}/${(processModel as any).id}/process-instances/reports`}
data-qa="process-instance-reports-link"
>
Reports
</Link>
</li>
</ul>
{processInstancesUl()}
<br />
<br />
<h3>Files</h3>
<ul>{processModelFilesTag}</ul>
{processModelFileList()}
</main>
);
}
// <ReactFormBuilder schema="" uischema="" />
}

View File

@ -1,7 +1,146 @@
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import Editor from '@monaco-editor/react';
import { useNavigate, useParams } from 'react-router-dom';
import { Button, Modal } from 'react-bootstrap';
import ProcessBreadcrumb from '../components/ProcessBreadcrumb';
import HttpService from '../services/HttpService';
// NOTE: This is mostly the same as ProcessModelEditDiagram and if we go this route could
// possibly be merged into it. I'm leaving as a separate file now in case it does
// end up diverging greatly
export default function ReactFormEditor() {
useEffect(() => {}, []);
const params = useParams();
const [showFileNameEditor, setShowFileNameEditor] = useState(false);
const [newFileName, setNewFileName] = useState('');
const handleShowFileNameEditor = () => setShowFileNameEditor(true);
const navigate = useNavigate();
const [processModelFile, setProcessModelFile] = useState(null);
const [processModelFileContents, setProcessModelFileContents] = useState('');
useEffect(() => {
const processResult = (result: any) => {
setProcessModelFile(result);
setProcessModelFileContents(result.file_contents);
};
if (params.file_name) {
HttpService.makeCallToBackend({
path: `/process-models/${params.process_group_id}/${params.process_model_id}/file/${params.file_name}`,
successCallback: processResult,
});
}
}, [params]);
const navigateToProcessModelFile = (_result: any) => {
if (!params.file_name) {
const fileNameWithExtension = `${newFileName}.json`;
navigate(
`/admin/process-models/${params.process_group_id}/${params.process_model_id}/form/${fileNameWithExtension}`
);
}
};
const saveFile = () => {
let url = `/process-models/${params.process_group_id}/${params.process_model_id}/file`;
let httpMethod = 'PUT';
let fileNameWithExtension = params.file_name;
if (newFileName) {
fileNameWithExtension = `${newFileName}.json`;
httpMethod = 'POST';
} else {
url += `/${fileNameWithExtension}`;
}
if (!fileNameWithExtension) {
handleShowFileNameEditor();
return;
}
const file = new File(
[processModelFileContents],
fileNameWithExtension || ''
);
const formData = new FormData();
formData.append('file', file);
formData.append('fileName', file.name);
HttpService.makeCallToBackend({
path: url,
successCallback: navigateToProcessModelFile,
httpMethod,
postBody: formData,
});
};
const handleFileNameCancel = () => {
setShowFileNameEditor(false);
setNewFileName('');
};
const handleFileNameSave = (event: any) => {
event.preventDefault();
setShowFileNameEditor(false);
saveFile();
};
const newFileNameBox = () => {
const fileExtension = '.json';
return (
<Modal show={showFileNameEditor} onHide={handleFileNameCancel}>
<Modal.Header closeButton>
<Modal.Title>Process Model File Name</Modal.Title>
</Modal.Header>
<form onSubmit={handleFileNameSave}>
<label>File Name:</label>
<span>
<input
name="file_name"
type="text"
value={newFileName}
onChange={(e) => setNewFileName(e.target.value)}
autoFocus
/>
{fileExtension}
</span>
<Modal.Footer>
<Button variant="secondary" onClick={handleFileNameCancel}>
Cancel
</Button>
<Button variant="primary" type="submit">
Save Changes
</Button>
</Modal.Footer>
</form>
</Modal>
);
};
if (processModelFile || !params.file_name) {
return (
<main>
<ProcessBreadcrumb
processGroupId={params.process_group_id}
processModelId={params.process_model_id}
linkProcessModel
/>
<h2>
Process Model File
{processModelFile ? `: ${(processModelFile as any).name}` : ''}
</h2>
{newFileNameBox()}
<Button onClick={saveFile} variant="danger">
Save
</Button>
<Editor
height={600}
width="auto"
defaultLanguage="json"
defaultValue={processModelFileContents || ''}
onChange={(value) => setProcessModelFileContents(value || '')}
/>
</main>
);
}
return <main />;
}