'use client' import type { OffsetOptions, Placement, } from '@floating-ui/react' import type { FC } from 'react' import type { Node } from 'reactflow' import type { ToolValue } from '@/app/components/workflow/block-selector/types' import type { NodeOutPutVar } from '@/app/components/workflow/types' import Link from 'next/link' import * as React from 'react' import { useTranslation } from 'react-i18next' import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger, } from '@/app/components/base/portal-to-follow-elem' import { CollectionType } from '@/app/components/tools/types' import { cn } from '@/utils/classnames' import { ToolAuthorizationSection, ToolBaseForm, ToolItem, ToolSettingsPanel, ToolTrigger, } from './components' import { useToolSelectorState } from './hooks/use-tool-selector-state' type Props = { disabled?: boolean placement?: Placement offset?: OffsetOptions scope?: string value?: ToolValue selectedTools?: ToolValue[] onSelect: (tool: ToolValue) => void onSelectMultiple?: (tool: ToolValue[]) => void isEdit?: boolean onDelete?: () => void supportEnableSwitch?: boolean supportAddCustomTool?: boolean trigger?: React.ReactNode controlledState?: boolean onControlledStateChange?: (state: boolean) => void panelShowState?: boolean onPanelShowStateChange?: (state: boolean) => void nodeOutputVars: NodeOutPutVar[] availableNodes: Node[] nodeId?: string } const ToolSelector: FC = ({ value, selectedTools, isEdit, disabled, placement = 'left', offset = 4, onSelect, onSelectMultiple, onDelete, scope, supportEnableSwitch, trigger, controlledState, onControlledStateChange, panelShowState, onPanelShowStateChange, nodeOutputVars, availableNodes, nodeId = '', }) => { const { t } = useTranslation() // Use custom hook for state management const state = useToolSelectorState({ value, onSelect, onSelectMultiple }) const { isShow, setIsShow, isShowChooseTool, setIsShowChooseTool, currType, setCurrType, currentProvider, currentTool, settingsFormSchemas, paramsFormSchemas, showTabSlider, userSettingsOnly, reasoningConfigOnly, manifestIcon, inMarketPlace, manifest, handleSelectTool, handleSelectMultipleTool, handleDescriptionChange, handleSettingsFormChange, handleParamsFormChange, handleEnabledChange, handleAuthorizationItemClick, handleInstall, getSettingsValue, } = state const handleTriggerClick = () => { if (disabled) return setIsShow(true) } // Determine portal open state based on controlled vs uncontrolled mode const portalOpen = trigger ? controlledState : isShow const onPortalOpenChange = trigger ? onControlledStateChange : setIsShow // Build error tooltip content const renderErrorTip = () => (

{currentTool ? t('detailPanel.toolSelector.uninstalledTitle', { ns: 'plugin' }) : t('detailPanel.toolSelector.unsupportedTitle', { ns: 'plugin' })}

{currentTool ? t('detailPanel.toolSelector.uninstalledContent', { ns: 'plugin' }) : t('detailPanel.toolSelector.unsupportedContent', { ns: 'plugin' })}

{t('detailPanel.toolSelector.uninstalledLink', { ns: 'plugin' })}

) return ( { if (!currentProvider || !currentTool) return handleTriggerClick() }} > {trigger} {/* Default trigger - no value */} {!trigger && !value?.provider_name && ( )} {/* Default trigger - with value */} {!trigger && value?.provider_name && ( )}
{/* Header */}
{t(`detailPanel.toolSelector.${isEdit ? 'toolSetting' : 'title'}`, { ns: 'plugin' })}
{/* Base form: tool picker + description */} {/* Authorization section */} {/* Settings panel */}
) } export default React.memo(ToolSelector)