diff --git a/frontend/src/utils/__tests__/importYaml.test.ts b/frontend/src/utils/__tests__/importYaml.test.ts index 2f69f68..74a385d 100644 --- a/frontend/src/utils/__tests__/importYaml.test.ts +++ b/frontend/src/utils/__tests__/importYaml.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, vi } from 'vitest' +import { describe, it, expect, vi, beforeEach } from 'vitest' import { parseYamlToCanvas } from '../importYaml' import type { Node, Edge } from '@xyflow/react' import type { NodeData, EdgeData } from '@/types' @@ -73,6 +73,38 @@ describe('parseYamlToCanvas', () => { expect(nodes[0].data.show_hardware).toBeUndefined() }) + it('links edges have bottom→top-t handles', () => { + const yaml = ` +- nodeType: switch + label: "SW" + links: + - label: "SRV" + linkType: ethernet +- nodeType: server + label: "SRV" +` + const { edges } = parseYamlToCanvas(yaml, empty, emptyEdges) + expect(edges).toHaveLength(1) + expect(edges[0].sourceHandle).toBe('bottom') + expect(edges[0].targetHandle).toBe('top-t') + }) + + it('cluster edges have cluster-right→cluster-left handles', () => { + const yaml = ` +- nodeType: proxmox + label: "PVE1" + clusterR: + label: "PVE2" + linkType: ethernet +- nodeType: proxmox + label: "PVE2" +` + const { edges } = parseYamlToCanvas(yaml, empty, emptyEdges) + expect(edges).toHaveLength(1) + expect(edges[0].sourceHandle).toBe('cluster-right') + expect(edges[0].targetHandle).toBe('cluster-left') + }) + it('parent relationship sets parentId and creates an edge', () => { const yaml = ` - nodeType: proxmox diff --git a/frontend/src/utils/importYaml.ts b/frontend/src/utils/importYaml.ts index fdd7241..16b7678 100644 --- a/frontend/src/utils/importYaml.ts +++ b/frontend/src/utils/importYaml.ts @@ -34,16 +34,16 @@ export function parseYamlToCanvas( const yamlNodes: YamlNode[] = [] for (const entry of entries) { - const raw = entry as Record + const entryRecord = entry as Record - if (!raw.nodeType || typeof raw.nodeType !== 'string') { + if (!entryRecord.nodeType || typeof entryRecord.nodeType !== 'string') { throw new Error(`Each YAML entry must have a "nodeType" string field`) } - if (!raw.label || typeof raw.label !== 'string') { + if (!entryRecord.label || typeof entryRecord.label !== 'string') { throw new Error(`Each YAML entry must have a "label" string field`) } - const yn = raw as unknown as YamlNode + const yn = entryRecord as unknown as YamlNode // Skip if a node with this label already exists on the canvas if (labelToId.has(yn.label)) { @@ -95,6 +95,8 @@ export function parseYamlToCanvas( sourceId: string, targetId: string, conn: YamlNodeConnection, + sourceHandle = 'bottom', + targetHandle = 'top-t', ) { const key = `${sourceId}|${targetId}` const reverseKey = `${targetId}|${sourceId}` @@ -105,6 +107,8 @@ export function parseYamlToCanvas( id: generateUUID(), source: sourceId, target: targetId, + sourceHandle, + targetHandle, type: edgeType, data: { type: edgeType, @@ -126,8 +130,8 @@ export function parseYamlToCanvas( node.data = { ...node.data, parent_id: parentId } node.parentId = parentId node.extent = 'parent' - // Also create an edge - addEdgeIfNew(parentId, node.id, yn.parent) + // Also create an edge (parent bottom → child top) + addEdgeIfNew(parentId, node.id, yn.parent, 'bottom', 'top-t') } } @@ -137,7 +141,7 @@ export function parseYamlToCanvas( if (!targetId) { console.warn(`[importYaml] links label not found: "${link.label}" — skipping`) } else { - addEdgeIfNew(node.id, targetId, link) + addEdgeIfNew(node.id, targetId, link, 'bottom', 'top-t') } } } @@ -147,7 +151,7 @@ export function parseYamlToCanvas( if (!targetId) { console.warn(`[importYaml] clusterR label not found: "${yn.clusterR.label}" — skipping`) } else { - addEdgeIfNew(node.id, targetId, yn.clusterR) + addEdgeIfNew(node.id, targetId, yn.clusterR, 'cluster-right', 'cluster-left') } } @@ -156,7 +160,7 @@ export function parseYamlToCanvas( if (!sourceId) { console.warn(`[importYaml] clusterL label not found: "${yn.clusterL.label}" — skipping`) } else { - addEdgeIfNew(sourceId, node.id, yn.clusterL) + addEdgeIfNew(sourceId, node.id, yn.clusterL, 'cluster-right', 'cluster-left') } } }