fix: node connect self (#3194)

This commit is contained in:
zxhlyh 2024-04-09 12:24:41 +08:00 committed by GitHub
parent 3c3fb3cd3f
commit 86707928d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 85 additions and 5 deletions

View File

@ -301,6 +301,8 @@ export const useNodesInteractions = () => {
target, target,
targetHandle, targetHandle,
}) => { }) => {
if (source === target)
return
if (getNodesReadOnly()) if (getNodesReadOnly())
return return

View File

@ -160,8 +160,10 @@ export const useWorkflow = () => {
if (incomers.length) { if (incomers.length) {
incomers.forEach((node) => { incomers.forEach((node) => {
if (!list.find(n => node.id === n.id)) {
callback(node) callback(node)
traverse(node, callback) traverse(node, callback)
}
}) })
} }
} }
@ -272,7 +274,10 @@ export const useWorkflow = () => {
}, [isVarUsedInNodes]) }, [isVarUsedInNodes])
const isValidConnection = useCallback(({ source, target }: Connection) => { const isValidConnection = useCallback(({ source, target }: Connection) => {
const { getNodes } = store.getState() const {
edges,
getNodes,
} = store.getState()
const nodes = getNodes() const nodes = getNodes()
const sourceNode: Node = nodes.find(node => node.id === source)! const sourceNode: Node = nodes.find(node => node.id === source)!
const targetNode: Node = nodes.find(node => node.id === target)! const targetNode: Node = nodes.find(node => node.id === target)!
@ -287,7 +292,21 @@ export const useWorkflow = () => {
return false return false
} }
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 return true
if (hasCycle(outgoer, visited))
return true
}
}
return !hasCycle(targetNode)
}, [store, nodesExtraData]) }, [store, nodesExtraData])
const formatTimeFromNow = useCallback((time: number) => { const formatTimeFromNow = useCallback((time: number) => {

View File

@ -24,6 +24,60 @@ import type { ToolNodeType } from './nodes/tool/types'
import { CollectionType } from '@/app/components/tools/types' import { CollectionType } from '@/app/components/tools/types'
import { toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema' 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[]) => { export const initialNodes = (nodes: Node[], edges: Edge[]) => {
const firstNode = nodes[0] const firstNode = nodes[0]
@ -35,6 +89,7 @@ export const initialNodes = (nodes: Node[], edges: Edge[]) => {
} }
}) })
} }
return nodes.map((node) => { return nodes.map((node) => {
node.type = 'custom' node.type = 'custom'
@ -75,7 +130,11 @@ export const initialEdges = (edges: Edge[], nodes: Node[]) => {
return acc return acc
}, {} as Record<string, Node>) }, {} 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' edge.type = 'custom'
if (!edge.sourceHandle) if (!edge.sourceHandle)