mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
Created state edge detection on edge connect
This commit is contained in:
+21
-10
@@ -5,6 +5,7 @@ import { getBlock } from '@/blocks'
|
||||
import { resolveOutputType } from '@/blocks/utils'
|
||||
import { WorkflowStoreWithHistory, pushHistory, withHistory } from './middleware'
|
||||
import { Position, SubBlockState } from './types'
|
||||
import { detectCycle } from './utils'
|
||||
|
||||
const initialState = {
|
||||
blocks: {},
|
||||
@@ -179,18 +180,28 @@ export const useWorkflowStore = create<WorkflowStoreWithHistory>()(
|
||||
},
|
||||
|
||||
addEdge: (edge: Edge) => {
|
||||
// First create the new edge
|
||||
const newEdge = {
|
||||
id: edge.id || crypto.randomUUID(),
|
||||
source: edge.source,
|
||||
target: edge.target,
|
||||
sourceHandle: edge.sourceHandle,
|
||||
targetHandle: edge.targetHandle,
|
||||
}
|
||||
|
||||
// Create temporary edges array with the new edge
|
||||
const newEdges = [...get().edges, newEdge]
|
||||
|
||||
// Check for cycles starting from the source node
|
||||
const { hasCycle, path } = detectCycle(newEdges, edge.source)
|
||||
|
||||
if (hasCycle) {
|
||||
console.log('Loop detected through nodes:', path.join(' → '))
|
||||
}
|
||||
|
||||
const newState = {
|
||||
blocks: { ...get().blocks },
|
||||
edges: [
|
||||
...get().edges,
|
||||
{
|
||||
id: edge.id || crypto.randomUUID(),
|
||||
source: edge.source,
|
||||
target: edge.target,
|
||||
sourceHandle: edge.sourceHandle,
|
||||
targetHandle: edge.targetHandle,
|
||||
},
|
||||
],
|
||||
edges: newEdges,
|
||||
}
|
||||
|
||||
set(newState)
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import { Edge } from 'reactflow'
|
||||
|
||||
/**
|
||||
* Performs a depth-first search to detect cycles in the graph
|
||||
* @param edges - List of all edges in the graph
|
||||
* @param startNode - Starting node for cycle detection
|
||||
* @returns boolean indicating if a cycle was detected and the path of the cycle if found
|
||||
*/
|
||||
export function detectCycle(edges: Edge[], startNode: string): { hasCycle: boolean; path: string[] } {
|
||||
const visited = new Set<string>()
|
||||
const recursionStack = new Set<string>()
|
||||
const pathMap = new Map<string, string>()
|
||||
|
||||
function dfs(node: string): boolean {
|
||||
// Add to both visited and recursion stack
|
||||
visited.add(node)
|
||||
recursionStack.add(node)
|
||||
|
||||
// Get all neighbors of current node
|
||||
const neighbors = edges
|
||||
.filter(edge => edge.source === node)
|
||||
.map(edge => edge.target)
|
||||
|
||||
for (const neighbor of neighbors) {
|
||||
// If not visited, explore that path
|
||||
if (!visited.has(neighbor)) {
|
||||
pathMap.set(neighbor, node)
|
||||
if (dfs(neighbor)) return true
|
||||
}
|
||||
// If the neighbor is in recursion stack, we found a cycle
|
||||
else if (recursionStack.has(neighbor)) {
|
||||
// Record the last edge of the cycle
|
||||
pathMap.set(neighbor, node)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from recursion stack when backtracking
|
||||
recursionStack.delete(node)
|
||||
return false
|
||||
}
|
||||
|
||||
// Perform DFS and construct cycle path if found
|
||||
const hasCycle = dfs(startNode)
|
||||
|
||||
// If cycle found, construct the path
|
||||
const cyclePath: string[] = []
|
||||
if (hasCycle) {
|
||||
let current = startNode
|
||||
do {
|
||||
cyclePath.unshift(current)
|
||||
current = pathMap.get(current)!
|
||||
} while (current !== startNode && current !== undefined)
|
||||
|
||||
if (current === startNode) {
|
||||
cyclePath.unshift(startNode)
|
||||
}
|
||||
}
|
||||
|
||||
return { hasCycle, path: cyclePath }
|
||||
}
|
||||
Reference in New Issue
Block a user