import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { Tooltip, TooltipContent, TooltipTrigger, } from '@/components/ui/tooltip'; import { IModalProps } from '@/interfaces/common'; import { useGetNodeDescription, useGetNodeName } from '@/pages/data-flow/hooks'; import useGraphStore from '@/pages/data-flow/store'; import { Position } from '@xyflow/react'; import { t } from 'i18next'; import { PropsWithChildren, createContext, memo, useContext, useEffect, useMemo, useRef, } from 'react'; import { Operator, SingleOperators } from '../../../constant'; import { AgentInstanceContext, HandleContext } from '../../../context'; import OperatorIcon from '../../../operator-icon'; type OperatorItemProps = { operators: Operator[]; isCustomDropdown?: boolean; mousePosition?: { x: number; y: number }; }; const HideModalContext = createContext['showModal']>(() => {}); const OnNodeCreatedContext = createContext< ((newNodeId: string) => void) | undefined >(undefined); function OperatorItemList({ operators, isCustomDropdown = false, mousePosition, }: OperatorItemProps) { const { addCanvasNode } = useContext(AgentInstanceContext); const handleContext = useContext(HandleContext); const hideModal = useContext(HideModalContext); const onNodeCreated = useContext(OnNodeCreatedContext); const getNodeName = useGetNodeName(); const getNodeDescription = useGetNodeDescription(); const handleClick = (operator: Operator): React.MouseEventHandler => (e) => { const contextData = handleContext || { nodeId: '', id: '', type: 'source' as const, position: Position.Right, isFromConnectionDrag: true, }; const mockEvent = mousePosition ? { clientX: mousePosition.x, clientY: mousePosition.y, } : e; const newNodeId = addCanvasNode(operator, contextData)(mockEvent); if (onNodeCreated && newNodeId) { onNodeCreated(newNodeId); } hideModal?.(); }; const renderOperatorItem = (operator: Operator) => { const commonContent = (
{getNodeName(operator)}
); return ( {isCustomDropdown ? (
  • {commonContent}
  • ) : ( hideModal?.()} > {getNodeName(operator)} )}

    {getNodeDescription(operator)}

    ); }; return ; } // Limit the number of operators of a certain type on the canvas to only one function useRestrictSingleOperatorOnCanvas() { const list: Operator[] = []; const { findNodeByName } = useGraphStore((state) => state); SingleOperators.forEach((operator) => { if (!findNodeByName(operator)) { list.push(operator); } }); return list; } function AccordionOperators({ isCustomDropdown = false, mousePosition, nodeId, }: { isCustomDropdown?: boolean; mousePosition?: { x: number; y: number }; nodeId?: string; }) { const singleOperators = useRestrictSingleOperatorOnCanvas(); const { getOperatorTypeFromId } = useGraphStore((state) => state); const operators = useMemo(() => { let list = [...singleOperators]; if (getOperatorTypeFromId(nodeId) === Operator.Extractor) { const Splitters = [Operator.HierarchicalMerger, Operator.Splitter]; list = list.filter((x) => !Splitters.includes(x)); // The Context Generator node can only be followed by a Tokenizer and a Context Generator. } list.push(Operator.Extractor); return list; }, [getOperatorTypeFromId, nodeId, singleOperators]); return ( ); } type NextStepDropdownProps = PropsWithChildren & IModalProps & { position?: { x: number; y: number }; onNodeCreated?: (newNodeId: string) => void; nodeId?: string; }; export function InnerNextStepDropdown({ children, hideModal, position, onNodeCreated, nodeId, }: NextStepDropdownProps) { const dropdownRef = useRef(null); useEffect(() => { if (position && hideModal) { const handleKeyDown = (event: KeyboardEvent) => { if (event.key === 'Escape') { hideModal(); } }; document.addEventListener('keydown', handleKeyDown); return () => { document.removeEventListener('keydown', handleKeyDown); }; } }, [position, hideModal]); if (position) { return (
    e.stopPropagation()} >
    {t('flow.nextStep')}
    ); } return ( { if (!open && hideModal) { hideModal(); } }} > {children} e.stopPropagation()} className="w-[300px] font-semibold" > {t('flow.nextStep')} ); } export const NextStepDropdown = memo(InnerNextStepDropdown);