feat: network diagrams — draw.io-style editor #139

Merged
chihlasm merged 31 commits from feat/network-diagrams into main 2026-04-14 05:44:27 +00:00
Showing only changes of commit f2c3bd7a9b - Show all commits

View File

@@ -28,6 +28,11 @@ import { toast } from '@/lib/toast'
import type { DeviceTypeResponse, DeviceProperties, AIGenerateResponse, DiagramEdge, DiagramNode } from '@/types' import type { DeviceTypeResponse, DeviceProperties, AIGenerateResponse, DiagramEdge, DiagramNode } from '@/types'
import type { DeviceNodeData } from '@/components/network/nodes/DeviceNode' import type { DeviceNodeData } from '@/components/network/nodes/DeviceNode'
function normalizeZOrder(nodes: Node[]): Node[] {
const sorted = [...nodes].sort((a, b) => ((a.zIndex ?? 0) - (b.zIndex ?? 0)))
return sorted.map((n, i) => ({ ...n, zIndex: i + 1 }))
}
type ContextMenuState = { type ContextMenuState = {
type: 'node' | 'canvas' type: 'node' | 'canvas'
position: { x: number; y: number } position: { x: number; y: number }
@@ -307,7 +312,7 @@ function DiagramEditorInner() {
connectionType: d.connectionType as string || 'ethernet', connectionType: d.connectionType as string || 'ethernet',
speed: d.speed as string || null, speed: d.speed as string || null,
notes: d.notes as string || null, notes: d.notes as string || null,
routing: d.routing as string || null, routing: (d.routing as DiagramEdge['routing']) || null,
} }
}) })
}, [edges]) }, [edges])
@@ -510,19 +515,20 @@ function DiagramEditorInner() {
const handleBringToFront = useCallback((nodeId: string) => { const handleBringToFront = useCallback((nodeId: string) => {
pushHistory(nodes, edges) pushHistory(nodes, edges)
setNodes(nds => { setNodes(prev => {
const maxZ = Math.max(0, ...nds.map(n => n.zIndex ?? 0)) const maxZ = Math.max(0, ...prev.map(n => n.zIndex ?? 0))
return nds.map(n => n.id === nodeId ? { ...n, zIndex: maxZ + 1 } : n) return normalizeZOrder(
prev.map(n => n.id === nodeId ? { ...n, zIndex: maxZ + 1 } : n)
)
}) })
setIsDirty(true) setIsDirty(true)
}, [nodes, edges, pushHistory, setNodes]) }, [nodes, edges, pushHistory, setNodes])
const handleSendToBack = useCallback((nodeId: string) => { const handleSendToBack = useCallback((nodeId: string) => {
pushHistory(nodes, edges) pushHistory(nodes, edges)
setNodes(nds => { setNodes(prev => normalizeZOrder(
const minZ = Math.min(0, ...nds.map(n => n.zIndex ?? 0)) prev.map(n => n.id === nodeId ? { ...n, zIndex: 0 } : n)
return nds.map(n => n.id === nodeId ? { ...n, zIndex: minZ - 1 } : n) ))
})
setIsDirty(true) setIsDirty(true)
}, [nodes, edges, pushHistory, setNodes]) }, [nodes, edges, pushHistory, setNodes])