From 4f27090289cdeef273f0a72faba04c48d8bc4f2f Mon Sep 17 00:00:00 2001 From: balibabu Date: Tue, 31 Mar 2026 14:44:47 +0800 Subject: [PATCH] Fix: Unable to reconnect after deleting the connection between begin and parser #13868 (#13869) ### What problem does this PR solve? Fix: Unable to reconnect after deleting the connection between begin and parser #13868 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue) --- web/src/pages/agent/canvas/node/handle.tsx | 14 ++++++++++++-- web/src/pages/agent/constant/index.tsx | 1 + web/src/pages/agent/store.ts | 11 ++++++++--- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/web/src/pages/agent/canvas/node/handle.tsx b/web/src/pages/agent/canvas/node/handle.tsx index 642db55db7..d26d31e11c 100644 --- a/web/src/pages/agent/canvas/node/handle.tsx +++ b/web/src/pages/agent/canvas/node/handle.tsx @@ -18,10 +18,20 @@ export function CommonHandle({ const { visible, hideModal, showModal } = useSetModalState(); const { canShowDropdown, setActiveDropdown, clearActiveDropdown } = useDropdownManager(); - const { hasChildNode } = useGraphStore((state) => state); + const { hasDownstreamNode, hasUpstreamNode } = useGraphStore( + (state) => state, + ); const isPipeline = useIsPipeline(); - const isConnectable = !(isPipeline && hasChildNode(nodeId)); // Using useMemo will cause isConnectable to not be updated when the subsequent connection line is deleted + let isConnectable = true; + + if (isPipeline) { + if (props.type === 'source') { + isConnectable = !hasDownstreamNode(nodeId); + } else if (props.type === 'target') { + isConnectable = !hasUpstreamNode(nodeId); + } + } const value = useMemo( () => ({ diff --git a/web/src/pages/agent/constant/index.tsx b/web/src/pages/agent/constant/index.tsx index 0c919e1beb..835b850877 100644 --- a/web/src/pages/agent/constant/index.tsx +++ b/web/src/pages/agent/constant/index.tsx @@ -692,6 +692,7 @@ export const RestrictedUpstreamMap = { [Operator.Loop]: [Operator.Begin], [Operator.LoopStart]: [Operator.Begin], [Operator.ExitLoop]: [Operator.Begin], + [Operator.PDFGenerator]: [Operator.Begin], }; export const NodeMap = { diff --git a/web/src/pages/agent/store.ts b/web/src/pages/agent/store.ts index 83919e3695..7afc9c7941 100644 --- a/web/src/pages/agent/store.ts +++ b/web/src/pages/agent/store.ts @@ -115,7 +115,8 @@ export type RFState = { ) => void; // Deleting a condition of a classification operator will delete the related edge findAgentToolNodeById: (id: string | null) => string | undefined; selectNodeIds: (nodeIds: string[]) => void; - hasChildNode: (nodeId: string) => boolean; + hasDownstreamNode: (nodeId: string) => boolean; + hasUpstreamNode: (nodeId: string) => boolean; }; // this is our useStore hook that we can use in our components to get parts of the store and call actions @@ -469,7 +470,7 @@ const useGraphStore = create()( const { updateNodeForm, edges, getOperatorTypeFromId } = get(); if (sourceHandle) { // A handle will connect to multiple downstream nodes - let currentHandleTargets = edges + const currentHandleTargets = edges .filter( (x) => x.source === source && @@ -647,10 +648,14 @@ const useGraphStore = create()( })), ); }, - hasChildNode: (nodeId) => { + hasDownstreamNode: (nodeId) => { const { edges } = get(); return edges.some((edge) => edge.source === nodeId); }, + hasUpstreamNode: (nodeId) => { + const { edges } = get(); + return edges.some((edge) => edge.target === nodeId); + }, })), { name: 'graph', trace: true }, ),