mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-13 07:29:02 +08:00
fix: node connect self (#3194)
This commit is contained in:
parent
3c3fb3cd3f
commit
86707928d4
@ -301,6 +301,8 @@ export const useNodesInteractions = () => {
|
|||||||
target,
|
target,
|
||||||
targetHandle,
|
targetHandle,
|
||||||
}) => {
|
}) => {
|
||||||
|
if (source === target)
|
||||||
|
return
|
||||||
if (getNodesReadOnly())
|
if (getNodesReadOnly())
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -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) => {
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user