diff --git a/src/management-system-v2/app/globals.css b/src/management-system-v2/app/globals.css index a7cc15549..918cd8ad5 100644 --- a/src/management-system-v2/app/globals.css +++ b/src/management-system-v2/app/globals.css @@ -1,5 +1,12 @@ .bpmn-js-modeler-with-toolbar .djs-palette { - top: 125px; + top: 70px; +} + +.bpmn-js-modeler-with-toolbar .bjs-breadcrumbs { + top: unset; + left: 15px !important; + bottom: 10px; + font-size: 20px; } /* Workaround to make flex with breakpoints work. See: https://github.com/ant-design/ant-design/issues/28961#issuecomment-1712966521 */ diff --git a/src/management-system-v2/components/modeler-toolbar.tsx b/src/management-system-v2/components/modeler-toolbar.tsx index 5f2c5a46e..b0ccebb59 100644 --- a/src/management-system-v2/components/modeler-toolbar.tsx +++ b/src/management-system-v2/components/modeler-toolbar.tsx @@ -1,18 +1,19 @@ 'use client'; -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import type ElementRegistry from 'diagram-js/lib/core/ElementRegistry'; +import type CommandStack from 'diagram-js/lib/command/CommandStack'; -import { Row, Col, Tooltip, Button } from 'antd'; +import { Tooltip, Button, Space } from 'antd'; import { Toolbar, ToolbarGroup } from './toolbar'; import Icon, { - FormOutlined, ExportOutlined, - EyeOutlined, SettingOutlined, PlusOutlined, + UndoOutlined, + RedoOutlined, } from '@ant-design/icons'; import { SvgXML, SvgShare } from '@/components/svg'; @@ -26,7 +27,7 @@ import ProcessExportModal from './process-export'; import { createNewProcessVersion } from '@/lib/helpers/processVersioning'; import VersionCreationButton from './version-creation-button'; -import { useQueryClient } from '@tanstack/react-query'; + import { useInvalidateAsset } from '@/lib/fetch-data'; type ModelerToolbarProps = { @@ -40,7 +41,11 @@ const ModelerToolbar: React.FC = ({ onOpenXmlEditor }) => { const [showPropertiesPanel, setShowPropertiesPanel] = useState(false); const [showProcessExportModal, setShowProcessExportModal] = useState(false); + const [canUndo, setCanUndo] = useState(false); + const [canRedo, setCanRedo] = useState(false); + const modeler = useModelerStateStore((state) => state.modeler); + const editingDisabled = useModelerStateStore((state) => state.editingDisabled); const selectedElementId = useModelerStateStore((state) => state.selectedElementId); const { processId } = useParams(); @@ -65,6 +70,23 @@ const ModelerToolbar: React.FC = ({ onOpenXmlEditor }) => { : elementRegistry.getAll().filter((el) => el.businessObject.$type === 'bpmn:Process')[0]; } + useEffect(() => { + if (modeler) { + const commandStack = modeler.get('commandStack', false) as CommandStack; + // check if there is a commandStack (does not exist on the viewer used when editing is disabled) + if (commandStack) { + // init canUndo and canRedo + setCanUndo(commandStack.canUndo()); + setCanRedo(commandStack.canRedo()); + } + modeler.on('commandStack.changed', () => { + // update canUndo and canRedo when the state of the modelers commandStack changes + setCanUndo(commandStack.canUndo()); + setCanRedo(commandStack.canRedo()); + }); + } + }, [modeler]); + const createProcessVersion = async (values: { versionName: string; versionDescription: string; @@ -91,44 +113,60 @@ const ModelerToolbar: React.FC = ({ onOpenXmlEditor }) => { const selectedVersion = useSearchParams().get('version'); + const handleUndo = () => { + if (modeler) (modeler.get('commandStack') as CommandStack).undo(); + }; + + const handleRedo = () => { + if (modeler) (modeler.get('commandStack') as CommandStack).redo(); + }; + return ( <> - - - - {/* + + + {/* - - - - - - + + + + + + + + + + + } + createVersion={createProcessVersion} + > + + + {!editingDisabled && modeler && ( + + + - - } - createVersion={createProcessVersion} - > + + - {showPropertiesPanel &&
} - - {/* {showPropertiesPanel && } */} - {showPropertiesPanel && selectedElement && ( - <> - - )} -
+ {showPropertiesPanel &&
} + + {/* {showPropertiesPanel && } */} + {showPropertiesPanel && selectedElement && ( + <> + + + )}
{/* {showPropertiesPanel && selectedElement && ( diff --git a/src/management-system-v2/components/modeler.tsx b/src/management-system-v2/components/modeler.tsx index 1a5263f20..1cc832f0c 100644 --- a/src/management-system-v2/components/modeler.tsx +++ b/src/management-system-v2/components/modeler.tsx @@ -1,6 +1,7 @@ 'use client'; import React, { FC, useEffect, useRef, useState } from 'react'; +import 'bpmn-js/dist/assets/bpmn-js.css'; import 'bpmn-js/dist/assets/diagram-js.css'; import 'bpmn-js/dist/assets/bpmn-font/css/bpmn.css'; import type ModelerType from 'bpmn-js/lib/Modeler'; @@ -47,6 +48,7 @@ const Modeler: FC = ({ minimized, ...props }) => { const setModeler = useModelerStateStore((state) => state.setModeler); const setSelectedElementId = useModelerStateStore((state) => state.setSelectedElementId); + const setEditingDisabled = useModelerStateStore((state) => state.setEditingDisabled); /// Derived State const selectedVersionId = query.get('version'); @@ -69,6 +71,7 @@ const Modeler: FC = ({ minimized, ...props }) => { proceed: schema, }, }); + setEditingDisabled(true); } else { modeler.current = new Modeler!({ container: canvas.current!, @@ -79,7 +82,7 @@ const Modeler: FC = ({ minimized, ...props }) => { // update process after change with 2 second debounce let timer: ReturnType; - modeler.current.on('commandStack.changed', async () => { + modeler.current.on('commandStack.changed', () => { clearTimeout(timer); timer = setTimeout(async () => { try { @@ -94,6 +97,8 @@ const Modeler: FC = ({ minimized, ...props }) => { } }, 2000); }); + + setEditingDisabled(false); } // allow keyboard shortcuts like copy (strg+c) and paste (strg+v) etc. diff --git a/src/management-system-v2/lib/use-modeler-state-store.ts b/src/management-system-v2/lib/use-modeler-state-store.ts index 01a89d6ef..8f3e647c6 100644 --- a/src/management-system-v2/lib/use-modeler-state-store.ts +++ b/src/management-system-v2/lib/use-modeler-state-store.ts @@ -10,6 +10,7 @@ type ModelerStateStore = { editingDisabled: boolean; setModeler: (newModeler: Modeler | Viewer | null) => void; setSelectedElementId: (newId: null | string) => void; + setEditingDisabled: (isDisabled: boolean) => void; }; const useModelerStateStore = create()( @@ -25,6 +26,10 @@ const useModelerStateStore = create()( set((state) => { state.selectedElementId = newId; }), + setEditingDisabled: (isDisabled: boolean) => + set((state) => { + state.editingDisabled = isDisabled; + }), })), );