mirror of
https://github.com/sartography/spiff-arena.git
synced 2025-01-12 18:44:14 +00:00
Fix dmn and user tasks (#1996)
* updated bpmn-js items * updated dmn-js items as well * fixed some linting * some initial changes to make our dmn and user task handlers work better with react w/ burnettk * removed unnecessary useEffects and existing form can be edited * json schema form can set data properly from examples w/ burnettk * some cleanup w/ burnettk --------- Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
parent
30b55a2e63
commit
77f272e6eb
@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useEffect, useState, useRef } from 'react';
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import Editor from '@monaco-editor/react';
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
import merge from 'lodash/merge';
|
||||
@ -15,7 +15,7 @@ import {
|
||||
Button,
|
||||
Loading,
|
||||
} from '@carbon/react';
|
||||
import { useDebounce } from 'use-debounce';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
import { ErrorBoundary, useErrorBoundary } from 'react-error-boundary';
|
||||
import HttpService from '../../services/HttpService';
|
||||
import ExamplesTable from './ExamplesTable';
|
||||
@ -72,11 +72,8 @@ export default function ReactFormBuilder({
|
||||
useState<boolean>(false);
|
||||
|
||||
const [strSchema, setStrSchema] = useState<string>('');
|
||||
const [debouncedStrSchema] = useDebounce(strSchema, 500);
|
||||
const [strUI, setStrUI] = useState<string>('');
|
||||
const [debouncedStrUI] = useDebounce(strUI, 500);
|
||||
const [strFormData, setStrFormData] = useState<string>('');
|
||||
const [debouncedFormData] = useDebounce(strFormData, 500);
|
||||
|
||||
const [postJsonSchema, setPostJsonSchema] = useState<object>({});
|
||||
const [postJsonUI, setPostJsonUI] = useState<object>({});
|
||||
@ -106,102 +103,6 @@ export default function ReactFormBuilder({
|
||||
dataEditorRef.current = editor;
|
||||
}
|
||||
|
||||
const saveFile = useCallback(
|
||||
(file: File, create: boolean = false, callback: Function | null = null) => {
|
||||
if ((create && !canCreateFiles) || (!create && !canUpdateFiles)) {
|
||||
return;
|
||||
}
|
||||
let httpMethod = 'PUT';
|
||||
let url = `/process-models/${processModelId}/files`;
|
||||
if (create && canCreateFiles) {
|
||||
httpMethod = 'POST';
|
||||
} else if (canUpdateFiles) {
|
||||
url += `/${file.name}`;
|
||||
}
|
||||
|
||||
const submission = new FormData();
|
||||
submission.append('file', file);
|
||||
submission.append('fileName', file.name);
|
||||
|
||||
HttpService.makeCallToBackend({
|
||||
path: url,
|
||||
successCallback: () => {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
failureCallback: (e: any) => {
|
||||
setErrorMessage(`Failed to save file: '${fileName}'. ${e.message}`);
|
||||
},
|
||||
httpMethod,
|
||||
postBody: submission,
|
||||
});
|
||||
},
|
||||
[processModelId, fileName, canUpdateFiles, canCreateFiles],
|
||||
);
|
||||
|
||||
const hasValidName = (identifierToCheck: string) => {
|
||||
return identifierToCheck.match(/^[a-z0-9][0-9a-z-]+[a-z0-9]$/);
|
||||
};
|
||||
|
||||
const createFiles = (base: string) => {
|
||||
if (hasValidName(base)) {
|
||||
// meaning it switched from invalid to valid
|
||||
if (filenameBaseInvalid) {
|
||||
setFilenameBaseInvalid(false);
|
||||
}
|
||||
} else {
|
||||
setFilenameBaseInvalid(true);
|
||||
return;
|
||||
}
|
||||
saveFile(new File(['{}'], base + SCHEMA_EXTENSION), true, () => {
|
||||
saveFile(new File(['{}'], base + UI_EXTENSION), true, () => {
|
||||
saveFile(new File(['{}'], base + DATA_EXTENSION), true, () => {
|
||||
setBaseFileName(base);
|
||||
onFileNameSet(base + SCHEMA_EXTENSION);
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const isReady = () => {
|
||||
// Use a ready flag so that we still allow people to completely delete
|
||||
// the schema, ui or data if they want to clear it out.
|
||||
if (ready) {
|
||||
return true;
|
||||
}
|
||||
if (
|
||||
debouncedStrSchema !== '' &&
|
||||
debouncedStrUI !== '' &&
|
||||
debouncedFormData !== ''
|
||||
) {
|
||||
setReady(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Auto save schema changes
|
||||
useEffect(() => {
|
||||
if (baseFileName !== '' && ready) {
|
||||
saveFile(new File([debouncedStrSchema], baseFileName + SCHEMA_EXTENSION));
|
||||
}
|
||||
}, [debouncedStrSchema, baseFileName, saveFile, ready]);
|
||||
|
||||
// Auto save ui changes
|
||||
useEffect(() => {
|
||||
if (baseFileName !== '' && ready) {
|
||||
saveFile(new File([debouncedStrUI], baseFileName + UI_EXTENSION));
|
||||
}
|
||||
}, [debouncedStrUI, baseFileName, saveFile, ready]);
|
||||
|
||||
// Auto save example data changes
|
||||
useEffect(() => {
|
||||
if (baseFileName !== '' && ready) {
|
||||
saveFile(new File([debouncedFormData], baseFileName + DATA_EXTENSION));
|
||||
}
|
||||
}, [debouncedFormData, baseFileName, saveFile, ready]);
|
||||
|
||||
useEffect(() => {
|
||||
/**
|
||||
* we need to run the schema and ui through a backend call before rendering the form,
|
||||
@ -212,28 +113,24 @@ export default function ReactFormBuilder({
|
||||
let ui = {};
|
||||
let data = {};
|
||||
|
||||
if (
|
||||
debouncedFormData === '' ||
|
||||
debouncedStrSchema === '' ||
|
||||
debouncedStrUI === ''
|
||||
) {
|
||||
if (strSchema === '' || strUI === '' || strFormData === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
schema = JSON.parse(debouncedStrSchema);
|
||||
schema = JSON.parse(strSchema);
|
||||
} catch (e) {
|
||||
setErrorMessage('Please check the Json Schema for errors.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ui = JSON.parse(debouncedStrUI);
|
||||
ui = JSON.parse(strUI);
|
||||
} catch (e) {
|
||||
setErrorMessage('Please check the UI Settings for errors.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
data = JSON.parse(debouncedFormData);
|
||||
data = JSON.parse(strFormData);
|
||||
} catch (e) {
|
||||
setErrorMessage('Please check the Data View for errors.');
|
||||
return;
|
||||
@ -261,7 +158,97 @@ export default function ReactFormBuilder({
|
||||
task_data: data,
|
||||
},
|
||||
});
|
||||
}, [debouncedStrSchema, debouncedStrUI, debouncedFormData, canCreateFiles]);
|
||||
}, [strSchema, strUI, strFormData, canCreateFiles]);
|
||||
|
||||
const saveFile = (
|
||||
file: File,
|
||||
create: boolean = false,
|
||||
callback: Function | null = null,
|
||||
) => {
|
||||
if ((create && !canCreateFiles) || (!create && !canUpdateFiles)) {
|
||||
return;
|
||||
}
|
||||
let httpMethod = 'PUT';
|
||||
let url = `/process-models/${processModelId}/files`;
|
||||
if (create && canCreateFiles) {
|
||||
httpMethod = 'POST';
|
||||
} else if (canUpdateFiles) {
|
||||
url += `/${file.name}`;
|
||||
}
|
||||
|
||||
const submission = new FormData();
|
||||
submission.append('file', file);
|
||||
submission.append('fileName', file.name);
|
||||
|
||||
HttpService.makeCallToBackend({
|
||||
path: url,
|
||||
successCallback: () => {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
failureCallback: (e: any) => {
|
||||
setErrorMessage(`Failed to save file: '${fileName}'. ${e.message}`);
|
||||
},
|
||||
httpMethod,
|
||||
postBody: submission,
|
||||
});
|
||||
};
|
||||
|
||||
const hasValidName = (identifierToCheck: string) => {
|
||||
return identifierToCheck.match(/^[a-z0-9][0-9a-z-]+[a-z0-9]$/);
|
||||
};
|
||||
|
||||
const createFiles = (base: string) => {
|
||||
if (hasValidName(base)) {
|
||||
// meaning it switched from invalid to valid
|
||||
if (filenameBaseInvalid) {
|
||||
setFilenameBaseInvalid(false);
|
||||
}
|
||||
} else {
|
||||
setFilenameBaseInvalid(true);
|
||||
return;
|
||||
}
|
||||
saveFile(new File(['{}'], base + SCHEMA_EXTENSION), true, () => {
|
||||
saveFile(new File(['{}'], base + UI_EXTENSION), true, () => {
|
||||
saveFile(new File(['{}'], base + DATA_EXTENSION), true, () => {
|
||||
setBaseFileName(base);
|
||||
onFileNameSet(base + SCHEMA_EXTENSION);
|
||||
setStrSchema('{}');
|
||||
setStrUI('{}');
|
||||
setStrFormData('{}');
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const isReady = () => {
|
||||
// Use a ready flag so that we still allow people to completely delete
|
||||
// the schema, ui or data if they want to clear it out.
|
||||
if (ready) {
|
||||
return true;
|
||||
}
|
||||
if (strSchema !== '' && strUI !== '' && strFormData !== '') {
|
||||
setReady(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// if we share a debounce and update all str states at once
|
||||
// then only one will get fired so split them out like this.
|
||||
const updateStrFileDebounce = useDebouncedCallback((newContent: string) => {
|
||||
saveFile(new File([newContent], baseFileName + SCHEMA_EXTENSION));
|
||||
}, 500);
|
||||
const updateStrUIFileDebounce = useDebouncedCallback((newContent: string) => {
|
||||
saveFile(new File([newContent], baseFileName + UI_EXTENSION));
|
||||
}, 500);
|
||||
const updateFormDataFileDebounce = useDebouncedCallback(
|
||||
(newContent: string) => {
|
||||
saveFile(new File([newContent], baseFileName + DATA_EXTENSION));
|
||||
},
|
||||
500,
|
||||
);
|
||||
|
||||
const handleTabChange = (evt: any) => {
|
||||
setSelectedIndex(evt.selectedIndex);
|
||||
@ -475,7 +462,10 @@ export default function ReactFormBuilder({
|
||||
width="auto"
|
||||
defaultLanguage="json"
|
||||
defaultValue={strSchema}
|
||||
onChange={(value) => setStrSchema(value || '')}
|
||||
onChange={(value) => {
|
||||
updateStrFileDebounce(value || '');
|
||||
setStrSchema(value || '');
|
||||
}}
|
||||
onMount={handleSchemaEditorDidMount}
|
||||
options={{ readOnly: !canUpdateFiles }}
|
||||
/>
|
||||
@ -497,7 +487,10 @@ export default function ReactFormBuilder({
|
||||
width="auto"
|
||||
defaultLanguage="json"
|
||||
defaultValue={strUI}
|
||||
onChange={(value) => setStrUI(value || '')}
|
||||
onChange={(value) => {
|
||||
updateStrUIFileDebounce(value || '');
|
||||
setStrUI(value || '');
|
||||
}}
|
||||
onMount={handleUiEditorDidMount}
|
||||
options={{ readOnly: !canUpdateFiles }}
|
||||
/>
|
||||
@ -515,7 +508,10 @@ export default function ReactFormBuilder({
|
||||
width="auto"
|
||||
defaultLanguage="json"
|
||||
defaultValue={strFormData}
|
||||
onChange={(value: any) => updateDataFromStr(value || '')}
|
||||
onChange={(value) => {
|
||||
updateFormDataFileDebounce(value || '');
|
||||
updateDataFromStr(value || '');
|
||||
}}
|
||||
onMount={handleDataEditorDidMount}
|
||||
options={{ readOnly: !canUpdateFiles }}
|
||||
/>
|
||||
|
@ -56,7 +56,6 @@ import {
|
||||
import ProcessSearch from '../components/ProcessSearch';
|
||||
import { Notification } from '../components/Notification';
|
||||
import ActiveUsers from '../components/ActiveUsers';
|
||||
import { useFocusedTabStatus } from '../hooks/useFocusedTabStatus';
|
||||
import useScriptAssistEnabled from '../hooks/useScriptAssistEnabled';
|
||||
import useProcessScriptAssistMessage from '../hooks/useProcessScriptAssistQuery';
|
||||
import SpiffTooltip from '../components/SpiffTooltip';
|
||||
@ -66,7 +65,6 @@ import { usePermissionFetcher } from '../hooks/PermissionService';
|
||||
|
||||
export default function ProcessModelEditDiagram() {
|
||||
const [showFileNameEditor, setShowFileNameEditor] = useState(false);
|
||||
const isFocused = useFocusedTabStatus();
|
||||
const handleShowFileNameEditor = () => setShowFileNameEditor(true);
|
||||
const [processModel, setProcessModel] = useState<ProcessModel | null>(null);
|
||||
const [diagramHasChanges, setDiagramHasChanges] = useState<boolean>(false);
|
||||
@ -74,7 +72,7 @@ export default function ProcessModelEditDiagram() {
|
||||
const [scriptText, setScriptText] = useState<string>('');
|
||||
const [scriptType, setScriptType] = useState<string>('');
|
||||
const [fileEventBus, setFileEventBus] = useState<any>(null);
|
||||
const [jsonScehmaFileName, setJsonScehmaFileName] = useState<string>('');
|
||||
const [jsonSchemaFileName, setJsonSchemaFileName] = useState<string>('');
|
||||
const [showJsonSchemaEditor, setShowJsonSchemaEditor] = useState(false);
|
||||
|
||||
const [scriptEventBus, setScriptEventBus] = useState<any>(null);
|
||||
@ -435,7 +433,6 @@ export default function ProcessModelEditDiagram() {
|
||||
|
||||
const onJsonSchemaFilesRequested = useCallback(
|
||||
(event: any) => {
|
||||
setFileEventBus(event.eventBus);
|
||||
const re = /.*[-.]schema.json/;
|
||||
if (processModel) {
|
||||
const jsonFiles = processModel.files.filter((f) => f.name.match(re));
|
||||
@ -452,7 +449,6 @@ export default function ProcessModelEditDiagram() {
|
||||
|
||||
const onDmnFilesRequested = useCallback(
|
||||
(event: any) => {
|
||||
setFileEventBus(event.eventBus);
|
||||
if (processModel) {
|
||||
const dmnFiles = processModel.files.filter((f) => f.type === 'dmn');
|
||||
const options: any[] = [];
|
||||
@ -494,27 +490,6 @@ export default function ProcessModelEditDiagram() {
|
||||
[ability, targetUris.messageModelListPath],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const updateDiagramFiles = (pm: ProcessModel) => {
|
||||
setProcessModel(pm);
|
||||
const re = /.*[-.]schema.json/;
|
||||
const jsonFiles = pm.files.filter((f) => f.name.match(re));
|
||||
const options = jsonFiles.map((f) => {
|
||||
return { label: f.name, value: f.name };
|
||||
});
|
||||
fileEventBus.fire('spiff.json_schema_files.returned', { options });
|
||||
};
|
||||
|
||||
if (isFocused && fileEventBus) {
|
||||
// Request the process model again, and manually fire off the
|
||||
// commands to update the file lists for json and dmn files.
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/${processModelPath}?include_file_references=true`,
|
||||
successCallback: updateDiagramFiles,
|
||||
});
|
||||
}
|
||||
}, [isFocused, fileEventBus, processModelPath]);
|
||||
|
||||
const getScriptUnitTestElements = (element: any) => {
|
||||
const { extensionElements } = element.businessObject;
|
||||
if (extensionElements && extensionElements.values.length > 0) {
|
||||
@ -1258,15 +1233,15 @@ export default function ProcessModelEditDiagram() {
|
||||
const onLaunchJsonSchemaEditor = useCallback(
|
||||
(_element: any, fileName: string, eventBus: any) => {
|
||||
setFileEventBus(eventBus);
|
||||
setJsonScehmaFileName(fileName);
|
||||
setJsonSchemaFileName(fileName);
|
||||
setShowJsonSchemaEditor(true);
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const handleJsonScehmaEditorClose = () => {
|
||||
const handleJsonSchemaEditorClose = () => {
|
||||
fileEventBus.fire('spiff.jsonSchema.update', {
|
||||
value: jsonScehmaFileName,
|
||||
value: jsonSchemaFileName,
|
||||
});
|
||||
setShowJsonSchemaEditor(false);
|
||||
};
|
||||
@ -1280,14 +1255,14 @@ export default function ProcessModelEditDiagram() {
|
||||
open={showJsonSchemaEditor}
|
||||
modalHeading="Edit JSON Schema"
|
||||
primaryButtonText="Close"
|
||||
onRequestSubmit={handleJsonScehmaEditorClose}
|
||||
onRequestClose={handleJsonScehmaEditorClose}
|
||||
onRequestSubmit={handleJsonSchemaEditorClose}
|
||||
onRequestClose={handleJsonSchemaEditorClose}
|
||||
size="lg"
|
||||
>
|
||||
<ReactFormBuilder
|
||||
processModelId={params.process_model_id || ''}
|
||||
fileName={jsonScehmaFileName}
|
||||
onFileNameSet={setJsonScehmaFileName}
|
||||
fileName={jsonSchemaFileName}
|
||||
onFileNameSet={setJsonSchemaFileName}
|
||||
canUpdateFiles={ability.can(
|
||||
'POST',
|
||||
targetUris.processModelFileCreatePath,
|
||||
|
Loading…
x
Reference in New Issue
Block a user