fix(network): persist group node type, size, and child parentId on save/load
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 <noreply@anthropic.com>
This commit is contained in:
@@ -22,12 +22,20 @@ class DeviceProperties(BaseModel):
|
|||||||
status: str = Field(default="unknown", pattern=r"^(unknown|online|offline|degraded)$")
|
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):
|
class DiagramNode(BaseModel):
|
||||||
id: str
|
id: str
|
||||||
type: str
|
type: str
|
||||||
label: str
|
label: str
|
||||||
position: Position
|
position: Position
|
||||||
properties: DeviceProperties = Field(default_factory=DeviceProperties)
|
properties: DeviceProperties = Field(default_factory=DeviceProperties)
|
||||||
|
nodeType: str | None = None
|
||||||
|
style: NodeStyle | None = None
|
||||||
|
parentId: str | None = None
|
||||||
|
|
||||||
|
|
||||||
class DiagramEdge(BaseModel):
|
class DiagramEdge(BaseModel):
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ function DiagramEditorInner() {
|
|||||||
type: 'device',
|
type: 'device',
|
||||||
position: n.position,
|
position: n.position,
|
||||||
style: n.style || { width: 120, height: 120 },
|
style: n.style || { width: 120, height: 120 },
|
||||||
|
...(n.parentId ? { parentId: n.parentId, extent: 'parent' as const } : {}),
|
||||||
data: {
|
data: {
|
||||||
label: n.label,
|
label: n.label,
|
||||||
deviceType: n.type,
|
deviceType: n.type,
|
||||||
@@ -247,6 +248,7 @@ function DiagramEditorInner() {
|
|||||||
type: 'device' as const,
|
type: 'device' as const,
|
||||||
position: n.position,
|
position: n.position,
|
||||||
style: n.style || { width: 120, height: 120 },
|
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,
|
data: { label: n.label, deviceType: n.type, properties: n.properties } satisfies DeviceNodeData,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -297,6 +299,7 @@ function DiagramEditorInner() {
|
|||||||
position: n.position,
|
position: n.position,
|
||||||
properties: data.properties,
|
properties: data.properties,
|
||||||
style: { width: dw, height: dh },
|
style: { width: dw, height: dh },
|
||||||
|
...(n.parentId ? { parentId: n.parentId } : {}),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, [getNodes])
|
}, [getNodes])
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export interface DiagramNode {
|
|||||||
properties: DeviceProperties
|
properties: DeviceProperties
|
||||||
nodeType?: string
|
nodeType?: string
|
||||||
style?: { width?: number; height?: number } | null
|
style?: { width?: number; height?: number } | null
|
||||||
|
parentId?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DiagramEdge {
|
export interface DiagramEdge {
|
||||||
|
|||||||
Reference in New Issue
Block a user