Feat: A pipeline's child node can only have one node #9869 (#10695)

### What problem does this PR solve?

Feat: A pipeline's child node can only have one node #9869
### Type of change


- [x] New Feature (non-breaking change which adds functionality)
This commit is contained in:
balibabu
2025-10-21 13:55:46 +08:00
committed by GitHub
parent 594bf485d4
commit 41a647fe32
3 changed files with 18 additions and 3 deletions

View File

@ -1533,8 +1533,8 @@ This delimiter is used to split the input text into several text pieces echo of
'Your users will see this welcome message at the beginning.', 'Your users will see this welcome message at the beginning.',
modeTip: 'The mode defines how the workflow is initiated.', modeTip: 'The mode defines how the workflow is initiated.',
mode: 'Mode', mode: 'Mode',
conversational: 'conversational', conversational: 'Conversational',
task: 'task', task: 'Task',
beginInputTip: beginInputTip:
'By defining input parameters, this content can be accessed by other components in subsequent processes.', 'By defining input parameters, this content can be accessed by other components in subsequent processes.',
query: 'Query variables', query: 'Query variables',

View File

@ -5,6 +5,8 @@ import { Plus } from 'lucide-react';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { NodeHandleId } from '../../constant'; import { NodeHandleId } from '../../constant';
import { HandleContext } from '../../context'; import { HandleContext } from '../../context';
import { useIsPipeline } from '../../hooks/use-is-pipeline';
import useGraphStore from '../../store';
import { useDropdownManager } from '../context'; import { useDropdownManager } from '../context';
import { NextStepDropdown } from './dropdown/next-step-dropdown'; import { NextStepDropdown } from './dropdown/next-step-dropdown';
@ -14,9 +16,12 @@ export function CommonHandle({
...props ...props
}: HandleProps & { nodeId: string }) { }: HandleProps & { nodeId: string }) {
const { visible, hideModal, showModal } = useSetModalState(); const { visible, hideModal, showModal } = useSetModalState();
const { canShowDropdown, setActiveDropdown, clearActiveDropdown } = const { canShowDropdown, setActiveDropdown, clearActiveDropdown } =
useDropdownManager(); useDropdownManager();
const { hasChildNode } = 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
const value = useMemo( const value = useMemo(
() => ({ () => ({
@ -33,6 +38,7 @@ export function CommonHandle({
<HandleContext.Provider value={value}> <HandleContext.Provider value={value}>
<Handle <Handle
{...props} {...props}
isConnectable={isConnectable}
className={cn( className={cn(
'inline-flex justify-center items-center !bg-accent-primary !border-none group-hover:!size-4 group-hover:!rounded-sm', 'inline-flex justify-center items-center !bg-accent-primary !border-none group-hover:!size-4 group-hover:!rounded-sm',
className, className,
@ -40,6 +46,10 @@ export function CommonHandle({
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
if (!isConnectable) {
return;
}
if (!canShowDropdown()) { if (!canShowDropdown()) {
return; return;
} }

View File

@ -89,6 +89,7 @@ export type RFState = {
) => void; // Deleting a condition of a classification operator will delete the related edge ) => void; // Deleting a condition of a classification operator will delete the related edge
findAgentToolNodeById: (id: string | null) => string | undefined; findAgentToolNodeById: (id: string | null) => string | undefined;
selectNodeIds: (nodeIds: string[]) => void; selectNodeIds: (nodeIds: string[]) => void;
hasChildNode: (nodeId: string) => boolean;
}; };
// this is our useStore hook that we can use in our components to get parts of the store and call actions // this is our useStore hook that we can use in our components to get parts of the store and call actions
@ -527,6 +528,10 @@ const useGraphStore = create<RFState>()(
})), })),
); );
}, },
hasChildNode: (nodeId) => {
const { edges } = get();
return edges.some((edge) => edge.source === nodeId);
},
})), })),
{ name: 'graph', trace: true }, { name: 'graph', trace: true },
), ),