diff --git a/components/bpmn-q/modeler-component/editor/ui/ConfirmationModal.js b/components/bpmn-q/modeler-component/editor/ui/ConfirmationModal.js new file mode 100644 index 00000000..b0cf5651 --- /dev/null +++ b/components/bpmn-q/modeler-component/editor/ui/ConfirmationModal.js @@ -0,0 +1,43 @@ +/** + * Copyright (c) 2023 Institute of Architecture of Application Systems - + * University of Stuttgart + * + * This program and the accompanying materials are made available under the + * terms the Apache Software License 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: Apache-2.0 + */ +import React from 'react'; +import Modal from '../ui/modal/Modal'; + +// polyfill upcoming structural components +const Title = Modal.Title || (({children}) =>

{children}

); +const Body = Modal.Body || (({children}) =>
{children}
); +const Footer = Modal.Footer || (({children}) =>
{children}
); + +/** + * Modal component for confirming the discard of changes in the editor. + * + * @param onClose Function called when the modal is closed. + * @param onConfirm Function called when the "Yes" button is clicked to confirm discarding changes. + * @returns {JSX.Element} The modal as a React component. + * @constructor + */ +export default function ConfirmationModal({onClose, onConfirm}) { + + return + + Confirm Discard Changes + + + There are unsaved changes. Are you sure you want to discard all changes and generate a new diagram? + + + ; +} \ No newline at end of file diff --git a/components/bpmn-q/modeler-component/editor/ui/NewDiagramButton.js b/components/bpmn-q/modeler-component/editor/ui/NewDiagramButton.js index 2bff09b4..528a5467 100644 --- a/components/bpmn-q/modeler-component/editor/ui/NewDiagramButton.js +++ b/components/bpmn-q/modeler-component/editor/ui/NewDiagramButton.js @@ -1,25 +1,63 @@ -import React from "react"; -import { createNewDiagram } from "../util/IoUtilities"; +import React, { useState, useEffect } from 'react'; +import { createNewDiagram } from '../util/IoUtilities'; +import { getModeler } from '../ModelerHandler'; +import ConfirmationModal from './ConfirmationModal'; -/** - * React button which creates a new workflow. - * - * @param props - * @returns {JSX.Element} - * @constructor - */ export default function NewDiagramButton(props) { - const { modeler } = props; + const { modeler } = props; + const [unsavedChanges, setUnsavedChanges] = useState(false); + const [showConfirmationModal, setShowConfirmationModal] = useState(false); - return ( - - ); + useEffect(() => { + if (unsavedChanges) { + setShowConfirmationModal(true); + } else { + createNewDiagram(modeler); + } + }, [unsavedChanges, modeler]); + + const checkUnsavedChanges = () => { + getModeler().saveXML({ format: true }, function (err, xml) { + if (!err) { + let oldXml = getModeler().oldXml; + if (oldXml !== undefined) { + oldXml = oldXml.trim(); + } + if (oldXml !== xml.trim() && oldXml !== undefined) { + setUnsavedChanges(true); + setShowConfirmationModal(true); + } else { + setShowConfirmationModal(false); + createNewDiagram(modeler); + } + } + }); + }; + + const handleConfirmDiscard = () => { + createNewDiagram(modeler); + setUnsavedChanges(false); + setShowConfirmationModal(false); + }; + + const handleCancelDiscard = () => { + setShowConfirmationModal(false); + }; + + return ( +
+ + + {showConfirmationModal && ( + + )} +
+ ); } diff --git a/components/bpmn-q/modeler-component/editor/util/IoUtilities.js b/components/bpmn-q/modeler-component/editor/util/IoUtilities.js index 7b8b4ecd..a15039ae 100644 --- a/components/bpmn-q/modeler-component/editor/util/IoUtilities.js +++ b/components/bpmn-q/modeler-component/editor/util/IoUtilities.js @@ -15,14 +15,14 @@ let FormData = require("form-data"); // workflow with a start event to use as template for new workflows const NEW_DIAGRAM_XML = '\n' + - '\n' + - ' \n' + - ' \n' + + '\n' + + ' \n' + + ' \n' + " \n" + ' \n' + ' \n' + ' \n' + - ' \n' + + ' \n' + " \n" + " \n" + " \n" + @@ -72,8 +72,9 @@ export async function saveModelerAsLocalFile( fileFormat === saveFileFormats.ALL ) { if (openWindow) { - await openFileDialog(xml, fileName, saveFileFormats.BPMN); + await openFileDialog(modeler, xml, fileName, saveFileFormats.BPMN); } else { + modeler.oldXml = xml; await saveXmlAsLocalFile(xml, fileName); } } @@ -346,7 +347,7 @@ export async function saveWorkflowAsSVG(modeler, fileName, fileFormat) { fileFormat === saveFileFormats.ALL || fileFormat === saveFileFormats.SVG ) { - openFileDialog(svg, fileName, saveFileFormats.SVG); + openFileDialog(modeler, svg, fileName, saveFileFormats.SVG); } if ( fileFormat === saveFileFormats.ALL || @@ -378,7 +379,7 @@ function downloadPng(pngDataUrl, fileName, fileFormat) { openFileUrlDialog(pngDataUrl, fileName, fileFormat); } -async function openFileDialog(content, fileName, fileFormat) { +async function openFileDialog(modeler, content, fileName, fileFormat) { let suggestedName = fileName; if (suggestedName.includes(".bpmn")) { suggestedName = fileName.split(".bpmn")[0]; @@ -398,6 +399,9 @@ async function openFileDialog(content, fileName, fileFormat) { ], }); writeFile(fileHandle, content); + if (fileFormat === saveFileFormats.BPMN || fileFormat === saveFileFormats.ALL) { + modeler.oldXml = content; + } } async function openFileUrlDialog(content, fileName, fileFormat) {