@@ -602,29 +602,30 @@ const deleteNodeById = async (nodeId) => {
602602 if (!nodeId) {
603603 return
604604 }
605- const snapshot = snapshotYamlContent()
606- if (!snapshot ?.graph) {
605+ const source = yamlContent.value
606+ if (!source ?.graph) {
607607 return
608608 }
609- const nodesArr = Array.isArray(snapshot.graph.nodes) ? snapshot.graph.nodes : []
610- const edgesArr = Array.isArray(snapshot.graph.edges) ? snapshot.graph.edges : []
609+ const sourceGraph = source.graph
610+ const nodesArr = Array.isArray(sourceGraph.nodes) ? sourceGraph.nodes : []
611+ const edgesArr = Array.isArray(sourceGraph.edges) ? sourceGraph.edges : []
611612
612613 // Remove the node and its related edges
613614 const nextNodes = nodesArr.filter(node => node?.id !== nodeId)
614615 const nextEdges = edgesArr.filter(edge => edge?.from !== nodeId && edge?.to !== nodeId)
615616
616617 // Remove node ID from graph.start/end
617- const nextStart = Array.isArray(snapshot.graph .start)
618- ? snapshot.graph .start.filter(id => id !== nodeId)
619- : snapshot.graph .start
620- const nextEnd = Array.isArray(snapshot.graph .end)
621- ? snapshot.graph .end.filter(id => id !== nodeId)
622- : snapshot.graph .end
618+ const nextStart = Array.isArray(sourceGraph .start)
619+ ? sourceGraph .start.filter(id => id !== nodeId)
620+ : sourceGraph .start
621+ const nextEnd = Array.isArray(sourceGraph .end)
622+ ? sourceGraph .end.filter(id => id !== nodeId)
623+ : sourceGraph .end
623624
624625 const nextSnapshot = {
625- ...snapshot ,
626+ ...source ,
626627 graph: {
627- ...snapshot.graph ,
628+ ...sourceGraph ,
628629 nodes: nextNodes,
629630 edges: nextEdges,
630631 start: nextStart,
@@ -647,13 +648,14 @@ const deleteEdgeByEndpoints = async (fromId, toId) => {
647648 if (!fromId || !toId) {
648649 return
649650 }
650- const snapshot = snapshotYamlContent()
651- if (!snapshot ?.graph || !Array.isArray(snapshot .graph.edges)) {
651+ const source = yamlContent.value
652+ if (!source ?.graph || !Array.isArray(source .graph.edges)) {
652653 return
653654 }
655+ const sourceGraph = source.graph
654656
655657 let removed = false
656- const nextEdges = snapshot.graph .edges.filter(edge => {
658+ const nextEdges = sourceGraph .edges.filter(edge => {
657659 if (!removed && edge?.from === fromId && edge?.to === toId) {
658660 removed = true
659661 return false
@@ -662,11 +664,11 @@ const deleteEdgeByEndpoints = async (fromId, toId) => {
662664 })
663665
664666 // Delete from .start if edge is from Start Node
665- let nextStart = snapshot.graph .start
667+ let nextStart = sourceGraph .start
666668 if (fromId === START_NODE_ID) {
667- nextStart = Array.isArray(snapshot.graph .start)
668- ? snapshot.graph .start.filter(id => id !== toId)
669- : snapshot.graph .start
669+ nextStart = Array.isArray(sourceGraph .start)
670+ ? sourceGraph .start.filter(id => id !== toId)
671+ : sourceGraph .start
670672
671673 // Empty start node array is not allowed
672674 const startArray = Array.isArray(nextStart) ? nextStart : []
@@ -677,9 +679,9 @@ const deleteEdgeByEndpoints = async (fromId, toId) => {
677679 }
678680
679681 const nextSnapshot = {
680- ...snapshot ,
682+ ...source ,
681683 graph: {
682- ...snapshot.graph ,
684+ ...sourceGraph ,
683685 edges: nextEdges,
684686 start: nextStart
685687 }
@@ -888,6 +890,11 @@ const updateNodesAndEdgesFromYaml = (preserveExistingLayout = false) => {
888890
889891 const currentNodes = nodes.value || []
890892 const currentEdges = edges.value || []
893+ const defaultCenterPosition = getCentralPosition()
894+ const getDefaultCenterPosition = () => ({
895+ x: defaultCenterPosition.x,
896+ y: defaultCenterPosition.y
897+ })
891898
892899 const existingNodeById = preserveExistingLayout
893900 ? new Map(currentNodes.map(node => [node.id, node]))
@@ -947,8 +954,9 @@ const updateNodesAndEdgesFromYaml = (preserveExistingLayout = false) => {
947954 }
948955 }
949956
950- while (q.length) {
951- const id = q.shift()
957+ let queueIndex = 0
958+ while (queueIndex < q.length) {
959+ const id = q[queueIndex++]
952960 const baseLevel = levelById.get(id) || 0
953961 const neighbors = adj.get(id) || new Set()
954962 for (const nb of neighbors) {
@@ -1033,7 +1041,7 @@ const updateNodesAndEdgesFromYaml = (preserveExistingLayout = false) => {
10331041 }
10341042 }
10351043
1036- const pos = positions.get(id) || getCentralPosition ()
1044+ const pos = positions.get(id) || getDefaultCenterPosition ()
10371045 return {
10381046 id,
10391047 type: 'workflow-node',
@@ -1051,7 +1059,7 @@ const updateNodesAndEdgesFromYaml = (preserveExistingLayout = false) => {
10511059 id: yamlNode.id,
10521060 type: 'workflow-node',
10531061 label: yamlNode.id,
1054- position: getCentralPosition (),
1062+ position: getDefaultCenterPosition (),
10551063 data: yamlNode
10561064 }))
10571065 nodes.value = nextNodes
@@ -1097,13 +1105,13 @@ const updateNodesAndEdgesFromYaml = (preserveExistingLayout = false) => {
10971105 // Place start node to the left of the leftmost column
10981106 const yamlNodesInGraph = (nodes.value || []).filter(n => n && n.id !== START_NODE_ID)
10991107 if (yamlNodesInGraph.length) {
1100- const xs = yamlNodesInGraph.map(n => (n?.position && typeof n.position.x === 'number') ? n.position.x : getCentralPosition() .x)
1108+ const xs = yamlNodesInGraph.map(n => (n?.position && typeof n.position.x === 'number') ? n.position.x : defaultCenterPosition .x)
11011109 const minX = Math.min(...xs)
11021110 // Find nodes in that left column
11031111 const tol = 1
11041112 const leftColumn = yamlNodesInGraph.filter(n => Math.abs((n?.position?.x || 0) - minX) <= tol)
1105- const ys = leftColumn.map(n => (n?.position && typeof n.position.y === 'number') ? n.position.y : getCentralPosition() .y)
1106- const avgY = ys.length ? ys.reduce((a, b) => a + b, 0) / ys.length : getCentralPosition() .y
1113+ const ys = leftColumn.map(n => (n?.position && typeof n.position.y === 'number') ? n.position.y : defaultCenterPosition .y)
1114+ const avgY = ys.length ? ys.reduce((a, b) => a + b, 0) / ys.length : defaultCenterPosition .y
11071115 const startXOffset = -100
11081116 const startYOffset = 80
11091117 startNode = {
@@ -1118,7 +1126,7 @@ const updateNodesAndEdgesFromYaml = (preserveExistingLayout = false) => {
11181126 id: START_NODE_ID,
11191127 type: 'start-node',
11201128 label: 'Start',
1121- position: getCentralPosition (),
1129+ position: getDefaultCenterPosition (),
11221130 data: { id: START_NODE_ID, label: 'Start' }
11231131 }
11241132 }
@@ -1128,7 +1136,7 @@ const updateNodesAndEdgesFromYaml = (preserveExistingLayout = false) => {
11281136 id: START_NODE_ID,
11291137 type: 'start-node',
11301138 label: 'Start',
1131- position: getCentralPosition (),
1139+ position: getDefaultCenterPosition (),
11321140 data: { id: START_NODE_ID, label: 'Start' }
11331141 }
11341142 }
@@ -1167,13 +1175,14 @@ const updateNodesAndEdgesFromYaml = (preserveExistingLayout = false) => {
11671175 }).filter(Boolean)
11681176
11691177 // Combine YAML edges with visual start edges (preserve any existing non-yaml edges)
1178+ const nextYamlEdgeIdSet = new Set(nextYamlEdges.map(edge => edge.id))
11701179 edges.value = [
11711180 // keep any existing edges that are not YAML edges (e.g., visual-only) when preserving layout
11721181 // but always exclude previous Start edges so they are replaced by the newly computed ones
11731182 ...(preserveExistingLayout ? currentEdges.filter(e => {
11741183 const k = `${e.source}-${e.target}`
11751184 // drop if it's a YAML-defined edge or a previous Start edge
1176- const isYamlEdge = nextYamlEdges.some(ne => ne.id === k)
1185+ const isYamlEdge = nextYamlEdgeIdSet.has( k)
11771186 const isStartEdge = e.source === START_NODE_ID
11781187 // Also drop if it looks like a YAML edge (has data.from/to) but isn't in nextYamlEdges (stale)
11791188 const isStaleYamlEdge = e.data?.from && e.data?.to
@@ -1292,8 +1301,6 @@ const updateVueFlowNodeId = (oldId, newId) => {
12921301}
12931302
12941303// FormGenerator integration
1295- const snapshotYamlContent = () => cloneDeep(yamlContent.value ?? null)
1296-
12971304// Build YAML without specific node (shallow clone path to avoid full deep-clone on editor open)
12981305const buildYamlWithoutNode = (nodeId) => {
12991306 const source = yamlContent.value
@@ -1376,17 +1383,18 @@ const buildYamlWithoutGraph = () => {
13761383const autoAddStartEdge = async (nextNodeId) => {
13771384 const workflowNodes = (yamlContent.value?.graph?.nodes || []).filter(node => node?.id !== START_NODE_ID)
13781385 if (workflowNodes.length === 1 && workflowNodes[0]?.id === nextNodeId) {
1379- const snapshot = snapshotYamlContent()
1380- if (!snapshot?.graph) {
1381- snapshot.graph = {}
1382- }
1383- if (!Array.isArray(snapshot.graph.start)) {
1384- snapshot.graph.start = []
1385- }
1386- if (!snapshot.graph.start.includes(nextNodeId)) {
1387- // Add node
1388- snapshot.graph.start.push(nextNodeId)
1389- const ok = await persistYamlSnapshot(snapshot)
1386+ const source = yamlContent.value
1387+ const sourceGraph = source?.graph && typeof source.graph === 'object' ? source.graph : {}
1388+ const currentStart = Array.isArray(sourceGraph.start) ? sourceGraph.start : []
1389+ if (!currentStart.includes(nextNodeId)) {
1390+ const nextSnapshot = {
1391+ ...source,
1392+ graph: {
1393+ ...sourceGraph,
1394+ start: [...currentStart, nextNodeId]
1395+ }
1396+ }
1397+ const ok = await persistYamlSnapshot(nextSnapshot)
13901398 if (ok) {
13911399 await loadYamlFile()
13921400 syncVueNodesAndEdgesData()
@@ -1644,25 +1652,30 @@ const onConnect = async (connection) => {
16441652 // Special handling for StartNode connections
16451653 if (connection.source === START_NODE_ID) {
16461654 // Add target node to graph.start array instead of opening FormGenerator
1647- const snapshot = snapshotYamlContent()
1648- if (!snapshot ?.graph) {
1655+ const source = yamlContent.value
1656+ if (!source ?.graph) {
16491657 setTimeout(() => {
16501658 isCreatingConnection.value = false
16511659 }, 10)
16521660 return
16531661 }
1662+ const sourceGraph = source.graph
16541663
16551664 // Ensure graph.start exists as an array
1656- if (!Array.isArray(snapshot.graph.start)) {
1657- snapshot.graph.start = []
1658- }
1665+ const currentStart = Array.isArray(sourceGraph.start) ? sourceGraph.start : []
16591666
16601667 // Add target node to start array if not already present
1661- if (!snapshot.graph.start.includes(connection.target)) {
1662- snapshot.graph.start.push(connection.target)
1668+ if (!currentStart.includes(connection.target)) {
1669+ const nextSnapshot = {
1670+ ...source,
1671+ graph: {
1672+ ...sourceGraph,
1673+ start: [...currentStart, connection.target]
1674+ }
1675+ }
16631676
16641677 // Persist the updated YAML
1665- const ok = await persistYamlSnapshot(snapshot )
1678+ const ok = await persistYamlSnapshot(nextSnapshot )
16661679 if (ok) {
16671680 await loadYamlFile()
16681681 syncVueNodesAndEdgesData()
0 commit comments