do not navigate away from diagram editor page if there are changes w/ burnettk

This commit is contained in:
jasquat 2023-01-18 16:43:11 -05:00
parent 26de48193c
commit 7b78ff42da
5 changed files with 78 additions and 0 deletions

View File

@ -57,6 +57,7 @@
"react-icons": "^4.4.0", "react-icons": "^4.4.0",
"react-jsonschema-form": "^1.8.1", "react-jsonschema-form": "^1.8.1",
"react-markdown": "^8.0.3", "react-markdown": "^8.0.3",
"react-router": "^6.3.0",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.3.0",
"react-scripts": "^5.0.1", "react-scripts": "^5.0.1",
"remark-gfm": "^3.0.1", "remark-gfm": "^3.0.1",

View File

@ -53,6 +53,7 @@
"react-jsonschema-form": "^1.8.1", "react-jsonschema-form": "^1.8.1",
"react-markdown": "^8.0.3", "react-markdown": "^8.0.3",
"react-router-dom": "^6.3.0", "react-router-dom": "^6.3.0",
"react-router": "^6.3.0",
"react-scripts": "^5.0.1", "react-scripts": "^5.0.1",
"remark-gfm": "^3.0.1", "remark-gfm": "^3.0.1",
"serve": "^14.0.0", "serve": "^14.0.0",

View File

@ -84,6 +84,7 @@ type OwnProps = {
onJsonFilesRequested?: (..._args: any[]) => any; onJsonFilesRequested?: (..._args: any[]) => any;
onDmnFilesRequested?: (..._args: any[]) => any; onDmnFilesRequested?: (..._args: any[]) => any;
onSearchProcessModels?: (..._args: any[]) => any; onSearchProcessModels?: (..._args: any[]) => any;
onElementsChanged?: (..._args: any[]) => any;
url?: string; url?: string;
}; };
@ -109,6 +110,7 @@ export default function ReactDiagramEditor({
onJsonFilesRequested, onJsonFilesRequested,
onDmnFilesRequested, onDmnFilesRequested,
onSearchProcessModels, onSearchProcessModels,
onElementsChanged,
url, url,
}: OwnProps) { }: OwnProps) {
const [diagramXMLString, setDiagramXMLString] = useState(''); const [diagramXMLString, setDiagramXMLString] = useState('');
@ -291,6 +293,11 @@ export default function ReactDiagramEditor({
diagramModeler.on('element.click', (element: any) => { diagramModeler.on('element.click', (element: any) => {
handleElementClick(element); handleElementClick(element);
}); });
diagramModeler.on('elements.changed', (event: any) => {
if (onElementsChanged) {
onElementsChanged(event);
}
});
diagramModeler.on('spiff.service_tasks.requested', (event: any) => { diagramModeler.on('spiff.service_tasks.requested', (event: any) => {
handleServiceTasksRequested(event); handleServiceTasksRequested(event);
@ -330,6 +337,7 @@ export default function ReactDiagramEditor({
onJsonFilesRequested, onJsonFilesRequested,
onDmnFilesRequested, onDmnFilesRequested,
onSearchProcessModels, onSearchProcessModels,
onElementsChanged,
]); ]);
useEffect(() => { useEffect(() => {

View File

@ -0,0 +1,58 @@
/**
* These hooks re-implement the now removed useBlocker and usePrompt hooks in 'react-router-dom'.
* Thanks for the idea @piecyk https://github.com/remix-run/react-router/issues/8139#issuecomment-953816315
* Source: https://github.com/remix-run/react-router/commit/256cad70d3fd4500b1abcfea66f3ee622fb90874#diff-b60f1a2d4276b2a605c05e19816634111de2e8a4186fe9dd7de8e344b65ed4d3L344-L381
*/
import { useCallback, useContext, useEffect } from 'react';
import { UNSAFE_NavigationContext as NavigationContext } from 'react-router-dom';
/**
* Blocks all navigation attempts. This is useful for preventing the page from
* changing until some condition is met, like saving form data.
*
* @param blocker
* @param when
* @see https://reactrouter.com/api/useBlocker
*/
export function useBlocker(blocker: any, when: any = true) {
const { navigator } = useContext(NavigationContext);
useEffect(() => {
if (!when) return null;
const unblock = (navigator as any).block((tx: any) => {
const autoUnblockingTx = {
...tx,
retry() {
// Automatically unblock the transition so it can play all the way
// through before retrying it. TODO: Figure out how to re-enable
// this block if the transition is cancelled for some reason.
unblock();
tx.retry();
},
};
blocker(autoUnblockingTx);
});
return unblock;
}, [navigator, blocker, when]);
}
/**
* Prompts the user with an Alert before they leave the current screen.
*
* @param message
* @param when
*/
export function usePrompt(message: any, when: any = true) {
const blocker = useCallback(
(tx: any) => {
// eslint-disable-next-line no-alert
if (window.confirm(message)) tx.retry();
},
[message]
);
useBlocker(blocker, when);
}

View File

@ -35,11 +35,13 @@ import {
} from '../interfaces'; } from '../interfaces';
import ProcessSearch from '../components/ProcessSearch'; import ProcessSearch from '../components/ProcessSearch';
import { Notification } from '../components/Notification'; import { Notification } from '../components/Notification';
import { usePrompt } from '../hooks/UsePrompt';
export default function ProcessModelEditDiagram() { export default function ProcessModelEditDiagram() {
const [showFileNameEditor, setShowFileNameEditor] = useState(false); const [showFileNameEditor, setShowFileNameEditor] = useState(false);
const handleShowFileNameEditor = () => setShowFileNameEditor(true); const handleShowFileNameEditor = () => setShowFileNameEditor(true);
const [processModel, setProcessModel] = useState<ProcessModel | null>(null); const [processModel, setProcessModel] = useState<ProcessModel | null>(null);
const [diagramHasChanges, setDiagramHasChanges] = useState<boolean>(false);
const [scriptText, setScriptText] = useState<string>(''); const [scriptText, setScriptText] = useState<string>('');
const [scriptType, setScriptType] = useState<string>(''); const [scriptType, setScriptType] = useState<string>('');
@ -112,6 +114,8 @@ export default function ProcessModelEditDiagram() {
const processModelPath = `process-models/${modifiedProcessModelId}`; const processModelPath = `process-models/${modifiedProcessModelId}`;
usePrompt('Changes you made may not be saved.', diagramHasChanges);
useEffect(() => { useEffect(() => {
// Grab all available process models in case we need to search for them. // Grab all available process models in case we need to search for them.
// Taken from the Process Group List // Taken from the Process Group List
@ -206,6 +210,11 @@ export default function ProcessModelEditDiagram() {
// after saving the file, make sure we null out newFileName // after saving the file, make sure we null out newFileName
// so it does not get used over the params // so it does not get used over the params
setNewFileName(''); setNewFileName('');
setDiagramHasChanges(false);
};
const onElementsChanged = () => {
setDiagramHasChanges(true);
}; };
const onDeleteFile = (fileName = params.file_name) => { const onDeleteFile = (fileName = params.file_name) => {
@ -922,6 +931,7 @@ export default function ProcessModelEditDiagram() {
onLaunchDmnEditor={onLaunchDmnEditor} onLaunchDmnEditor={onLaunchDmnEditor}
onDmnFilesRequested={onDmnFilesRequested} onDmnFilesRequested={onDmnFilesRequested}
onSearchProcessModels={onSearchProcessModels} onSearchProcessModels={onSearchProcessModels}
onElementsChanged={onElementsChanged}
/> />
); );
}; };