### What problem does this PR solve? Feat: Solved the conflict between the Handle click and drag events of the canvas node #3221 ### Type of change - [x] New Feature (non-breaking change which adds functionality)tags/v0.20.0
| DropdownMenuLabel, | DropdownMenuLabel, | ||||
| DropdownMenuTrigger, | DropdownMenuTrigger, | ||||
| } from '@/components/ui/dropdown-menu'; | } from '@/components/ui/dropdown-menu'; | ||||
| import { IModalProps } from '@/interfaces/common'; | |||||
| import { Operator } from '@/pages/agent/constant'; | import { Operator } from '@/pages/agent/constant'; | ||||
| import { AgentInstanceContext, HandleContext } from '@/pages/agent/context'; | import { AgentInstanceContext, HandleContext } from '@/pages/agent/context'; | ||||
| import OperatorIcon from '@/pages/agent/operator-icon'; | import OperatorIcon from '@/pages/agent/operator-icon'; | ||||
| import { PropsWithChildren, useContext } from 'react'; | |||||
| import { PropsWithChildren, createContext, useContext } from 'react'; | |||||
| type OperatorItemProps = { operators: Operator[] }; | type OperatorItemProps = { operators: Operator[] }; | ||||
| const HideModalContext = createContext<IModalProps<any>['showModal']>(() => {}); | |||||
| function OperatorItemList({ operators }: OperatorItemProps) { | function OperatorItemList({ operators }: OperatorItemProps) { | ||||
| const { addCanvasNode } = useContext(AgentInstanceContext); | const { addCanvasNode } = useContext(AgentInstanceContext); | ||||
| const { nodeId, id, type, position } = useContext(HandleContext); | const { nodeId, id, type, position } = useContext(HandleContext); | ||||
| const hideModal = useContext(HideModalContext); | |||||
| return ( | return ( | ||||
| <ul className="space-y-2"> | <ul className="space-y-2"> | ||||
| id, | id, | ||||
| position, | position, | ||||
| })} | })} | ||||
| onSelect={() => hideModal?.()} | |||||
| > | > | ||||
| <OperatorIcon name={x}></OperatorIcon> | <OperatorIcon name={x}></OperatorIcon> | ||||
| {x} | {x} | ||||
| ); | ); | ||||
| } | } | ||||
| export function NextStepDropdown({ children }: PropsWithChildren) { | |||||
| export function NextStepDropdown({ | |||||
| children, | |||||
| hideModal, | |||||
| }: PropsWithChildren & IModalProps<any>) { | |||||
| return ( | return ( | ||||
| <DropdownMenu> | |||||
| <DropdownMenu open onOpenChange={hideModal}> | |||||
| <DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger> | <DropdownMenuTrigger asChild>{children}</DropdownMenuTrigger> | ||||
| <DropdownMenuContent | <DropdownMenuContent | ||||
| onClick={(e) => e.stopPropagation()} | onClick={(e) => e.stopPropagation()} | ||||
| className="w-[300px] font-semibold" | className="w-[300px] font-semibold" | ||||
| > | > | ||||
| <DropdownMenuLabel>Next Step</DropdownMenuLabel> | <DropdownMenuLabel>Next Step</DropdownMenuLabel> | ||||
| <AccordionOperators></AccordionOperators> | |||||
| <HideModalContext.Provider value={hideModal}> | |||||
| <AccordionOperators></AccordionOperators> | |||||
| </HideModalContext.Provider> | |||||
| </DropdownMenuContent> | </DropdownMenuContent> | ||||
| </DropdownMenu> | </DropdownMenu> | ||||
| ); | ); | 
| import { useSetModalState } from '@/hooks/common-hooks'; | |||||
| import { cn } from '@/lib/utils'; | import { cn } from '@/lib/utils'; | ||||
| import { Handle, HandleProps } from '@xyflow/react'; | import { Handle, HandleProps } from '@xyflow/react'; | ||||
| import { Plus } from 'lucide-react'; | import { Plus } from 'lucide-react'; | ||||
| nodeId, | nodeId, | ||||
| ...props | ...props | ||||
| }: HandleProps & { nodeId: string }) { | }: HandleProps & { nodeId: string }) { | ||||
| const { visible, hideModal, showModal } = useSetModalState(); | |||||
| const value = useMemo( | const value = useMemo( | ||||
| () => ({ | () => ({ | ||||
| nodeId, | nodeId, | ||||
| return ( | return ( | ||||
| <HandleContext.Provider value={value}> | <HandleContext.Provider value={value}> | ||||
| <NextStepDropdown> | |||||
| <Handle | |||||
| {...props} | |||||
| className={cn( | |||||
| 'inline-flex justify-center items-center !bg-background-checked !size-4 !rounded-sm !border-none ', | |||||
| className, | |||||
| )} | |||||
| onClick={(e) => { | |||||
| e.stopPropagation(); | |||||
| }} | |||||
| > | |||||
| <Plus className="size-3 pointer-events-none" /> | |||||
| </Handle> | |||||
| </NextStepDropdown> | |||||
| <Handle | |||||
| {...props} | |||||
| className={cn( | |||||
| 'inline-flex justify-center items-center !bg-background-checked !size-4 !rounded-sm !border-none ', | |||||
| className, | |||||
| )} | |||||
| onClick={(e) => { | |||||
| e.stopPropagation(); | |||||
| showModal(); | |||||
| }} | |||||
| > | |||||
| <Plus className="size-3 pointer-events-none" /> | |||||
| {visible && ( | |||||
| <NextStepDropdown hideModal={hideModal}> | |||||
| <span></span> | |||||
| </NextStepDropdown> | |||||
| )} | |||||
| </Handle> | |||||
| </HandleContext.Provider> | </HandleContext.Provider> | ||||
| ); | ); | ||||
| } | } | 
| import { memo } from 'react'; | import { memo } from 'react'; | ||||
| import { NodeHandleId } from '../../constant'; | import { NodeHandleId } from '../../constant'; | ||||
| import { CommonHandle } from './handle'; | import { CommonHandle } from './handle'; | ||||
| import { LeftHandleStyle, RightHandleStyle } from './handle-icon'; | |||||
| import { LeftHandleStyle } from './handle-icon'; | |||||
| import styles from './index.less'; | import styles from './index.less'; | ||||
| import NodeHeader from './node-header'; | import NodeHeader from './node-header'; | ||||
| import { NodeWrapper } from './node-wrapper'; | import { NodeWrapper } from './node-wrapper'; | ||||
| nodeId={id} | nodeId={id} | ||||
| id={NodeHandleId.End} | id={NodeHandleId.End} | ||||
| ></CommonHandle> | ></CommonHandle> | ||||
| <CommonHandle | |||||
| {/* <CommonHandle | |||||
| type="source" | type="source" | ||||
| position={Position.Right} | position={Position.Right} | ||||
| isConnectable={isConnectable} | isConnectable={isConnectable} | ||||
| id={NodeHandleId.Start} | id={NodeHandleId.Start} | ||||
| nodeId={id} | nodeId={id} | ||||
| isConnectableEnd={false} | isConnectableEnd={false} | ||||
| ></CommonHandle> | |||||
| ></CommonHandle> */} | |||||
| <NodeHeader | <NodeHeader | ||||
| id={id} | id={id} | ||||
| name={data.name} | name={data.name} |