From 12ba324e898ba794fe31eef712b0a19055507270 Mon Sep 17 00:00:00 2001 From: Max Chopart Date: Thu, 26 Sep 2024 14:17:11 +0200 Subject: [PATCH 1/2] [Upd #527] Clicking on apply layout now overrides persisted nodes --- src/components/editor/faultTree/Editor.tsx | 28 ++++++++++++++++ .../editor/faultTree/canvas/EditorCanvas.tsx | 32 +++++++++---------- .../faultTree/menu/SidebarMenuHeader.tsx | 4 +-- src/components/editor/menu/DiagramOptions.tsx | 6 ++-- .../editor/system/canvas/EditorCanvas.tsx | 2 +- 5 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/components/editor/faultTree/Editor.tsx b/src/components/editor/faultTree/Editor.tsx index d5f6cb84..fd33c9fd 100644 --- a/src/components/editor/faultTree/Editor.tsx +++ b/src/components/editor/faultTree/Editor.tsx @@ -119,6 +119,33 @@ const Editor = () => { } }; + const handleAutomaticLayout = async (graph, jointPaper) => { + for (const el of graph.getElements()) { + const faultEventIri = el.get(JOINTJS_NODE_MODEL.faultEventIri); + const movedEvent = findEventByIri(faultEventIri, getRootEvent()); + + if (movedEvent) { + const elementView = el.findView(jointPaper); + const size = elementView.model.attributes.size; + const position = elementView.model.attributes.position; + const rect: Rectangle = movedEvent.rectangle; + + if (rect.x != position.x || rect.y != position.y || rect.width != size.width || rect.height != size.height) { + rect.x = position.x; + rect.y = position.y; + rect.width = size.width; + rect.height = size.height; + + try { + await faultEventService.updateEventRectangle(faultEventIri, rect.iri, rect); + } catch (err) { + console.error("Failed to persist node position", err); + } + } + } + } + }; + const highlightBorders = (elementView) => { const tools = new joint.dia.ToolsView({ tools: [FTABoundary.factory()], @@ -219,6 +246,7 @@ const Editor = () => { onCutSetAnalysis={handleCutSetAnalysis} onConvertToTable={() => setFailureModesTableOpen(true)} onNodeMove={handleMoveEvent} + onApplyAutomaticLayout={handleAutomaticLayout} setHighlightedElement={setHighlightedElementView} refreshTree={refreshTree} faultEventScenarios={faultEventScenarios} diff --git a/src/components/editor/faultTree/canvas/EditorCanvas.tsx b/src/components/editor/faultTree/canvas/EditorCanvas.tsx index 5d070ed3..2b766a7f 100644 --- a/src/components/editor/faultTree/canvas/EditorCanvas.tsx +++ b/src/components/editor/faultTree/canvas/EditorCanvas.tsx @@ -51,6 +51,7 @@ interface Props { showTable: boolean; possibleFaultEventScenarios: FaultEventScenario[]; onScenarioSelect: (scenario: FaultEventScenario) => void; + onApplyAutomaticLayout: (container: joint.dia.Graph, jointPaper: joint.dia.Paper) => void; } const EditorCanvas = ({ @@ -71,6 +72,7 @@ const EditorCanvas = ({ showTable, possibleFaultEventScenarios, onScenarioSelect, + onApplyAutomaticLayout, }: Props) => { const { classes } = useStyles(); const theme = useTheme(); @@ -210,14 +212,10 @@ const EditorCanvas = ({ } }, [isExportingImage]); - const addSelf = (shape: any) => { - shape.addTo(container); - layout(container); - }; - const layout = (graph) => { const autoLayoutElements = []; - const manualLayoutElements = []; + const conditionalEventLayoutElements = []; + graph.getElements().forEach((el) => { const faultEventIri = el.get(JOINTJS_NODE_MODEL.faultEventIri); if (faultEventIri && faultEventIri === sidebarSelectedEvent?.iri) { @@ -226,12 +224,13 @@ const EditorCanvas = ({ } if (el.get("type") === "fta.ConditioningEvent") { - manualLayoutElements.push(el); - } else if (!el.get(JOINTJS_NODE_MODEL.hasPersistentPosition)) { + conditionalEventLayoutElements.push(el); + } else { autoLayoutElements.push(el); } }); - // Automatic Layout + + // Apply the automatic layout joint.layout.DirectedGraph.layout(graph.getSubgraph(autoLayoutElements), { dagre: dagre, graphlib: graphlib, @@ -241,15 +240,17 @@ const EditorCanvas = ({ rankSep: 100, // Vertical separation between ranks marginX: 20, marginY: 20, - preserveNodeGeometry: true, }); - // Manual Layout - manualLayoutElements.forEach((el) => { + + // Conditioning Events Manual Layout + conditionalEventLayoutElements.forEach((el) => { const neighbor = graph.getNeighbors(el, { inbound: true })[0]; if (!neighbor) return; const neighborPosition = neighbor.getBBox().bottomRight(); el.position(neighborPosition.x + 20, neighborPosition.y - el.size().height / 2 - 20); }); + + onApplyAutomaticLayout(graph, jointPaper); }; const handleDiagramExport = () => { @@ -258,7 +259,7 @@ const EditorCanvas = ({ }; useEffect(() => { - const renderAndLayout = async () => { + const render = async () => { if (container && rootEvent) { setRendering(true); container.removeCells(container.getCells()); @@ -270,12 +271,11 @@ const EditorCanvas = ({ } await renderTree(container, rootEvent, null, listOfPaths, faultTree?.status); - layout(container); setRendering(false); } }; - renderAndLayout(); + render(); }, [container, rootEvent, faultEventScenarios]); useEffect(() => { @@ -331,7 +331,7 @@ const EditorCanvas = ({ layout(container)} + onApplyAutomaticLayout={() => layout(container)} onCutSetAnalysis={onCutSetAnalysis} rendering={rendering} /> diff --git a/src/components/editor/faultTree/menu/SidebarMenuHeader.tsx b/src/components/editor/faultTree/menu/SidebarMenuHeader.tsx index c2d969a4..8664c1cb 100644 --- a/src/components/editor/faultTree/menu/SidebarMenuHeader.tsx +++ b/src/components/editor/faultTree/menu/SidebarMenuHeader.tsx @@ -23,7 +23,7 @@ const useActionCall = (isModified: boolean, setShowUnsavedChangesDialog: (show: const SidebarMenuHeader: React.FC = ({ onConvertToTable, onExportDiagram, - onRestoreLayout, + onApplyAutomaticLayout, onCutSetAnalysis, rendering, }) => { @@ -37,7 +37,7 @@ const SidebarMenuHeader: React.FC = ({ actionCall(onExportDiagram)} onConvertToTable={() => actionCall(onConvertToTable)} - onRestoreLayout={() => actionCall(onRestoreLayout)} + onApplyAutomaticLayout={() => actionCall(onApplyAutomaticLayout)} onCutSetAnalysis={() => actionCall(onCutSetAnalysis)} tableConversionAllowed={!table} rendering={rendering} diff --git a/src/components/editor/menu/DiagramOptions.tsx b/src/components/editor/menu/DiagramOptions.tsx index f5feccfe..58484596 100644 --- a/src/components/editor/menu/DiagramOptions.tsx +++ b/src/components/editor/menu/DiagramOptions.tsx @@ -9,7 +9,7 @@ import { useTranslation } from "react-i18next"; import CircularProgress from "@mui/material/CircularProgress"; export interface Props { - onRestoreLayout: () => void; + onApplyAutomaticLayout: () => void; onExportDiagram: () => void; onConvertToTable?: () => void; onCutSetAnalysis?: () => void; @@ -18,7 +18,7 @@ export interface Props { } const DiagramOptions = ({ - onRestoreLayout, + onApplyAutomaticLayout, onExportDiagram, onConvertToTable, onCutSetAnalysis, @@ -33,7 +33,7 @@ const DiagramOptions = ({ Diagram Options
- + diff --git a/src/components/editor/system/canvas/EditorCanvas.tsx b/src/components/editor/system/canvas/EditorCanvas.tsx index f43e488a..c96c06ce 100644 --- a/src/components/editor/system/canvas/EditorCanvas.tsx +++ b/src/components/editor/system/canvas/EditorCanvas.tsx @@ -255,7 +255,7 @@ const EditorCanvas = ({ ))}
- layout(container)} onExportDiagram={handleDiagramExport} /> + layout(container)} onExportDiagram={handleDiagramExport} /> {t("diagramSidePanel.minimumOperationalHours")} From f9b2c238547d02890bf6c4d368d41d4641fba54f Mon Sep 17 00:00:00 2001 From: Max Chopart Date: Fri, 27 Sep 2024 14:44:51 +0200 Subject: [PATCH 2/2] [Fix #527] Fixed the issue that prevented events with non-integer positions from being persisted. --- src/components/editor/faultTree/Editor.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/editor/faultTree/Editor.tsx b/src/components/editor/faultTree/Editor.tsx index fd33c9fd..39e9f4a5 100644 --- a/src/components/editor/faultTree/Editor.tsx +++ b/src/components/editor/faultTree/Editor.tsx @@ -131,8 +131,8 @@ const Editor = () => { const rect: Rectangle = movedEvent.rectangle; if (rect.x != position.x || rect.y != position.y || rect.width != size.width || rect.height != size.height) { - rect.x = position.x; - rect.y = position.y; + rect.x = Math.round(position.x); + rect.y = Math.round(position.y); // The server only supports integers rect.width = size.width; rect.height = size.height;