mirror of
https://github.com/sartography/spiffworkflow-frontend.git
synced 2025-02-23 11:48:35 +00:00
added ability to add and edit json files for forms
This commit is contained in:
parent
6c9017c1aa
commit
b2963f9725
@ -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}`);
|
||||
|
@ -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>
|
||||
|
@ -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="" />
|
||||
}
|
||||
|
@ -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 />;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user