From 4a12c9b37d14ac1d032cd0c12a86936309993067 Mon Sep 17 00:00:00 2001 From: chihlasm Date: Mon, 13 Apr 2026 23:49:26 +0000 Subject: [PATCH] fix(network): persist group node type, size, and child parentId on save/load MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Backend DiagramNode schema was missing nodeType, style, and parentId fields — Pydantic stripped them on save, so group nodes lost their identity on reload and re-appeared as small device icons. - Backend: add nodeType, style (NodeStyle), parentId to DiagramNode schema - Frontend: serialize parentId for device nodes inside groups - Frontend: restore parentId + extent:'parent' on both deserializer paths (setNodes + history init) - Frontend: add parentId to DiagramNode interface Co-Authored-By: Claude Sonnet 4.6 --- backend/app/schemas/network_diagram.py | 8 ++++++++ frontend/src/pages/NetworkDiagrams/DiagramEditor.tsx | 3 +++ frontend/src/types/network-diagram.ts | 1 + 3 files changed, 12 insertions(+) diff --git a/backend/app/schemas/network_diagram.py b/backend/app/schemas/network_diagram.py index e31d5283..8b85a6f2 100644 --- a/backend/app/schemas/network_diagram.py +++ b/backend/app/schemas/network_diagram.py @@ -22,12 +22,20 @@ class DeviceProperties(BaseModel): status: str = Field(default="unknown", pattern=r"^(unknown|online|offline|degraded)$") +class NodeStyle(BaseModel): + width: float | None = None + height: float | None = None + + class DiagramNode(BaseModel): id: str type: str label: str position: Position properties: DeviceProperties = Field(default_factory=DeviceProperties) + nodeType: str | None = None + style: NodeStyle | None = None + parentId: str | None = None class DiagramEdge(BaseModel): diff --git a/frontend/src/pages/NetworkDiagrams/DiagramEditor.tsx b/frontend/src/pages/NetworkDiagrams/DiagramEditor.tsx index 635be4fe..749883d5 100644 --- a/frontend/src/pages/NetworkDiagrams/DiagramEditor.tsx +++ b/frontend/src/pages/NetworkDiagrams/DiagramEditor.tsx @@ -207,6 +207,7 @@ function DiagramEditorInner() { type: 'device', position: n.position, style: n.style || { width: 120, height: 120 }, + ...(n.parentId ? { parentId: n.parentId, extent: 'parent' as const } : {}), data: { label: n.label, deviceType: n.type, @@ -247,6 +248,7 @@ function DiagramEditorInner() { type: 'device' as const, position: n.position, style: n.style || { width: 120, height: 120 }, + ...(n.parentId ? { parentId: n.parentId, extent: 'parent' as const } : {}), data: { label: n.label, deviceType: n.type, properties: n.properties } satisfies DeviceNodeData, } }) @@ -297,6 +299,7 @@ function DiagramEditorInner() { position: n.position, properties: data.properties, style: { width: dw, height: dh }, + ...(n.parentId ? { parentId: n.parentId } : {}), } }) }, [getNodes]) diff --git a/frontend/src/types/network-diagram.ts b/frontend/src/types/network-diagram.ts index aeff51a4..0ce62a3f 100644 --- a/frontend/src/types/network-diagram.ts +++ b/frontend/src/types/network-diagram.ts @@ -18,6 +18,7 @@ export interface DiagramNode { properties: DeviceProperties nodeType?: string style?: { width?: number; height?: number } | null + parentId?: string | null } export interface DiagramEdge {