Skip to content

Commit

Permalink
fix: node connect self (#3194)
Browse files Browse the repository at this point in the history
  • Loading branch information
zxhlyh committed Apr 9, 2024
1 parent 3c3fb3c commit 8670792
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 5 deletions.
2 changes: 2 additions & 0 deletions web/app/components/workflow/hooks/use-nodes-interactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,8 @@ export const useNodesInteractions = () => {
target,
targetHandle,
}) => {
if (source === target)
return
if (getNodesReadOnly())
return

Expand Down
27 changes: 23 additions & 4 deletions web/app/components/workflow/hooks/use-workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,8 +160,10 @@ export const useWorkflow = () => {

if (incomers.length) {
incomers.forEach((node) => {
callback(node)
traverse(node, callback)
if (!list.find(n => node.id === n.id)) {
callback(node)
traverse(node, callback)
}
})
}
}
Expand Down Expand Up @@ -272,7 +274,10 @@ export const useWorkflow = () => {
}, [isVarUsedInNodes])

const isValidConnection = useCallback(({ source, target }: Connection) => {
const { getNodes } = store.getState()
const {
edges,
getNodes,
} = store.getState()
const nodes = getNodes()
const sourceNode: Node = nodes.find(node => node.id === source)!
const targetNode: Node = nodes.find(node => node.id === target)!
Expand All @@ -287,7 +292,21 @@ export const useWorkflow = () => {
return false
}

return true
const hasCycle = (node: Node, visited = new Set()) => {
if (visited.has(node.id))
return false

visited.add(node.id)

for (const outgoer of getOutgoers(node, nodes, edges)) {
if (outgoer.id === source)
return true
if (hasCycle(outgoer, visited))
return true
}
}

return !hasCycle(targetNode)
}, [store, nodesExtraData])

const formatTimeFromNow = useCallback((time: number) => {
Expand Down
61 changes: 60 additions & 1 deletion web/app/components/workflow/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,60 @@ import type { ToolNodeType } from './nodes/tool/types'
import { CollectionType } from '@/app/components/tools/types'
import { toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema'

const WHITE = 'WHITE'
const GRAY = 'GRAY'
const BLACK = 'BLACK'

const isCyclicUtil = (nodeId: string, color: Record<string, string>, adjaList: Record<string, string[]>, stack: string[]) => {
color[nodeId] = GRAY
stack.push(nodeId)

for (let i = 0; i < adjaList[nodeId].length; ++i) {
const childId = adjaList[nodeId][i]

if (color[childId] === GRAY) {
stack.push(childId)
return true
}
if (color[childId] === WHITE && isCyclicUtil(childId, color, adjaList, stack))
return true
}
color[nodeId] = BLACK
if (stack.length > 0 && stack[stack.length - 1] === nodeId)
stack.pop()
return false
}

const getCycleEdges = (nodes: Node[], edges: Edge[]) => {
const adjaList: Record<string, string[]> = {}
const color: Record<string, string> = {}
const stack: string[] = []

for (const node of nodes) {
color[node.id] = WHITE
adjaList[node.id] = []
}

for (const edge of edges)
adjaList[edge.source].push(edge.target)

for (let i = 0; i < nodes.length; i++) {
if (color[nodes[i].id] === WHITE)
isCyclicUtil(nodes[i].id, color, adjaList, stack)
}

const cycleEdges = []
if (stack.length > 0) {
const cycleNodes = new Set(stack)
for (const edge of edges) {
if (cycleNodes.has(edge.source) && cycleNodes.has(edge.target))
cycleEdges.push(edge)
}
}

return cycleEdges
}

export const initialNodes = (nodes: Node[], edges: Edge[]) => {
const firstNode = nodes[0]

Expand All @@ -35,6 +89,7 @@ export const initialNodes = (nodes: Node[], edges: Edge[]) => {
}
})
}

return nodes.map((node) => {
node.type = 'custom'

Expand Down Expand Up @@ -75,7 +130,11 @@ export const initialEdges = (edges: Edge[], nodes: Node[]) => {

return acc
}, {} as Record<string, Node>)
return edges.map((edge) => {

const cycleEdges = getCycleEdges(nodes, edges)
return edges.filter((edge) => {
return !cycleEdges.find(cycEdge => cycEdge.source === edge.source && cycEdge.target === edge.target)
}).map((edge) => {
edge.type = 'custom'

if (!edge.sourceHandle)
Expand Down

0 comments on commit 8670792

Please sign in to comment.