diff --git a/web/app/components/app/configuration/config/agent/agent-tools/index.tsx b/web/app/components/app/configuration/config/agent/agent-tools/index.tsx index a54db2140e..e4a0e9737f 100644 --- a/web/app/components/app/configuration/config/agent/agent-tools/index.tsx +++ b/web/app/components/app/configuration/config/agent/agent-tools/index.tsx @@ -132,6 +132,7 @@ const AgentTools: FC = () => { disabled={false} supportAddCustomTool onSelect={handleSelectTool} + selectedTools={tools} /> )} @@ -161,7 +162,7 @@ const AgentTools: FC = () => { )} > {item.provider_type === CollectionType.builtIn ? item.provider_name.split('/').pop() : item.tool_label} - {item.tool_name} + {item.tool_label} {!item.isDeleted && (
@@ -329,6 +328,7 @@ function Form< scope={scope} disabled={readonly} value={value[variable]} + // selectedTools={value[variable] ? [value[variable]] : []} onSelect={item => handleFormChange(variable, item as any)} onDelete={() => handleFormChange(variable, null as any)} /> diff --git a/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx b/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx index 33375e60ec..4374f5cdca 100644 --- a/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx +++ b/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx @@ -9,7 +9,7 @@ import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-sele import ActionButton from '@/app/components/base/action-button' import Tooltip from '@/app/components/base/tooltip' import Divider from '@/app/components/base/divider' -import type { ToolValue } from '@/app/components/plugins/plugin-detail-panel/tool-selector' +import type { ToolValue } from '@/app/components/workflow/block-selector/types' import cn from '@/utils/classnames' type Props = { @@ -85,7 +85,7 @@ const MultipleToolSelector = ({ popupContent={tooltip} needsDelay > -
+
)} {supportCollapse && ( @@ -119,6 +119,7 @@ const MultipleToolSelector = ({ handleConfigure(item, index)} onDelete={() => handleDelete(index)} supportEnableSwitch diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx index 8e9966e8b8..b7773b2a6b 100644 --- a/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx +++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx @@ -35,7 +35,7 @@ import { import { useInvalidateInstalledPluginList } from '@/service/use-plugins' import { usePluginInstalledCheck } from '@/app/components/plugins/plugin-detail-panel/tool-selector/hooks' import { CollectionType } from '@/app/components/tools/types' -import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types' +import type { ToolDefaultValue, ToolValue } from '@/app/components/workflow/block-selector/types' import type { OffsetOptions, Placement, @@ -43,20 +43,13 @@ import type { import { MARKETPLACE_API_PREFIX } from '@/config' import cn from '@/utils/classnames' -export type ToolValue = { - provider_name: string - tool_name: string - parameters?: Record - enabled?: boolean - extra?: Record -} - type Props = { disabled?: boolean placement?: Placement offset?: OffsetOptions scope?: string value?: ToolValue + selectedTools?: ToolValue[] onSelect: (tool: { provider_name: string tool_name: string @@ -72,6 +65,7 @@ type Props = { } const ToolSelector: FC = ({ value, + selectedTools, disabled, placement = 'left', offset = 4, @@ -113,6 +107,7 @@ const ToolSelector: FC = ({ provider_name: tool.provider_id, type: tool.provider_type, tool_name: tool.tool_name, + tool_label: tool.tool_label, parameters: paramValues, enabled: tool.is_team_authorization, extra: { @@ -215,7 +210,7 @@ const ToolSelector: FC = ({ open={isShow} icon={currentProvider?.icon || manifestIcon} providerName={value.provider_name} - toolName={value.tool_name} + toolLabel={value.tool_label || value.tool_name} showSwitch={supportEnableSwitch} switchValue={value.enabled} onSwitchChange={handleEnabledChange} @@ -264,6 +259,7 @@ const ToolSelector: FC = ({ supportAddCustomTool onSelect={handleSelectTool} scope={scope} + selectedTools={selectedTools} />
diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/tool-item.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/tool-item.tsx index 3e32e66929..e99d06508d 100644 --- a/web/app/components/plugins/plugin-detail-panel/tool-selector/tool-item.tsx +++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/tool-item.tsx @@ -21,7 +21,7 @@ import cn from '@/utils/classnames' type Props = { icon?: any providerName?: string - toolName?: string + toolLabel?: string showSwitch?: boolean switchValue?: boolean onSwitchChange?: (value: boolean) => void @@ -41,7 +41,7 @@ const ToolItem = ({ open, icon, providerName, - toolName, + toolLabel, showSwitch, switchValue, onSwitchChange, @@ -83,7 +83,7 @@ const ToolItem = ({ )}
{providerNameText}
-
{toolName}
+
{toolLabel}
{!noAuth && !isError && !uninstalled && !versionMismatch && ( diff --git a/web/app/components/workflow/block-selector/all-tools.tsx b/web/app/components/workflow/block-selector/all-tools.tsx index 909a350a9f..6f287e2f4f 100644 --- a/web/app/components/workflow/block-selector/all-tools.tsx +++ b/web/app/components/workflow/block-selector/all-tools.tsx @@ -8,6 +8,7 @@ import type { OnSelectBlock, ToolWithProvider, } from '../types' +import type { ToolValue } from './types' import { ToolTypeEnum } from './types' import Tools from './tools' import { useToolTabs } from './hooks' @@ -32,6 +33,7 @@ type AllToolsProps = { supportAddCustomTool?: boolean onAddedCustomTool?: () => void onShowAddCustomCollectionModal?: () => void + selectedTools?: ToolValue[] } const AllTools = ({ className, @@ -44,6 +46,7 @@ const AllTools = ({ customTools, supportAddCustomTool, onShowAddCustomCollectionModal, + selectedTools, }: AllToolsProps) => { const language = useGetLanguage() const tabs = useToolTabs() @@ -138,6 +141,7 @@ const AllTools = ({ onSelect={onSelect} viewType={activeView} hasSearchText={!!searchText} + selectedTools={selectedTools} /> {/* Plugins from marketplace */} void supportAddCustomTool?: boolean scope?: string + selectedTools?: ToolValue[] } const ToolPicker: FC = ({ @@ -47,6 +48,7 @@ const ToolPicker: FC = ({ onSelect, supportAddCustomTool, scope = 'all', + selectedTools, }) => { const { t } = useTranslation() const [searchText, setSearchText] = useState('') @@ -160,6 +162,7 @@ const ToolPicker: FC = ({ supportAddCustomTool={supportAddCustomTool} onAddedCustomTool={handleAddedCustomTool} onShowAddCustomCollectionModal={showEditCustomCollectionModal} + selectedTools={selectedTools} />
diff --git a/web/app/components/workflow/block-selector/tool/action-item.tsx b/web/app/components/workflow/block-selector/tool/action-item.tsx index 8b8e76c69b..411faccb3a 100644 --- a/web/app/components/workflow/block-selector/tool/action-item.tsx +++ b/web/app/components/workflow/block-selector/tool/action-item.tsx @@ -8,10 +8,15 @@ import Tooltip from '@/app/components/base/tooltip' import type { Tool } from '@/app/components/tools/types' import { useGetLanguage } from '@/context/i18n' import BlockIcon from '../../block-icon' +import cn from '@/utils/classnames' +import { useTranslation } from 'react-i18next' +import { RiCheckLine } from '@remixicon/react' +import Badge from '@/app/components/base/badge' type Props = { provider: ToolWithProvider payload: Tool + disabled?: boolean onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void } @@ -19,7 +24,10 @@ const ToolItem: FC = ({ provider, payload, onSelect, + disabled, }) => { + const { t } = useTranslation() + const language = useGetLanguage() return ( @@ -42,8 +50,9 @@ const ToolItem: FC = ({ >
{ + if (disabled) return const params: Record = {} if (payload.parameters) { payload.parameters.forEach((item) => { @@ -64,7 +73,15 @@ const ToolItem: FC = ({ }) }} > -
{payload.label[language]}
+
{payload.label[language]}
+ {disabled && + +
{t('tools.addToolModal.added')}
+
+ }
) diff --git a/web/app/components/workflow/block-selector/tool/tool-list-flat-view/list.tsx b/web/app/components/workflow/block-selector/tool/tool-list-flat-view/list.tsx index 04622cabff..ef671ca1f8 100644 --- a/web/app/components/workflow/block-selector/tool/tool-list-flat-view/list.tsx +++ b/web/app/components/workflow/block-selector/tool/tool-list-flat-view/list.tsx @@ -3,7 +3,7 @@ import type { FC } from 'react' import React from 'react' import type { ToolWithProvider } from '../../../types' import type { BlockEnum } from '../../../types' -import type { ToolDefaultValue } from '../../types' +import type { ToolDefaultValue, ToolValue } from '../../types' import Tool from '../tool' import { ViewType } from '../../view-type-select' import { useMemo } from 'react' @@ -15,6 +15,7 @@ type Props = { onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void letters: string[] toolRefs: any + selectedTools?: ToolValue[] } const ToolViewFlatView: FC = ({ @@ -24,6 +25,7 @@ const ToolViewFlatView: FC = ({ hasSearchText, onSelect, toolRefs, + selectedTools, }) => { const firstLetterToolIds = useMemo(() => { const res: Record = {} @@ -51,6 +53,7 @@ const ToolViewFlatView: FC = ({ isShowLetterIndex={isShowLetterIndex} hasSearchText={hasSearchText} onSelect={onSelect} + selectedTools={selectedTools} />
))} diff --git a/web/app/components/workflow/block-selector/tool/tool-list-tree-view/item.tsx b/web/app/components/workflow/block-selector/tool/tool-list-tree-view/item.tsx index af75754190..65afef8ba9 100644 --- a/web/app/components/workflow/block-selector/tool/tool-list-tree-view/item.tsx +++ b/web/app/components/workflow/block-selector/tool/tool-list-tree-view/item.tsx @@ -5,13 +5,14 @@ import type { ToolWithProvider } from '../../../types' import Tool from '../tool' import type { BlockEnum } from '../../../types' import { ViewType } from '../../view-type-select' -import type { ToolDefaultValue } from '../../types' +import type { ToolDefaultValue, ToolValue } from '../../types' type Props = { groupName: string toolList: ToolWithProvider[] hasSearchText: boolean onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void + selectedTools?: ToolValue[] } const Item: FC = ({ @@ -19,6 +20,7 @@ const Item: FC = ({ toolList, hasSearchText, onSelect, + selectedTools, }) => { return (
@@ -34,6 +36,7 @@ const Item: FC = ({ isShowLetterIndex={false} hasSearchText={hasSearchText} onSelect={onSelect} + selectedTools={selectedTools} /> ))}
diff --git a/web/app/components/workflow/block-selector/tool/tool-list-tree-view/list.tsx b/web/app/components/workflow/block-selector/tool/tool-list-tree-view/list.tsx index a8fd34b98a..f3f98279c8 100644 --- a/web/app/components/workflow/block-selector/tool/tool-list-tree-view/list.tsx +++ b/web/app/components/workflow/block-selector/tool/tool-list-tree-view/list.tsx @@ -3,7 +3,7 @@ import type { FC } from 'react' import React, { useCallback } from 'react' import type { ToolWithProvider } from '../../../types' import type { BlockEnum } from '../../../types' -import type { ToolDefaultValue } from '../../types' +import type { ToolDefaultValue, ToolValue } from '../../types' import Item from './item' import { useTranslation } from 'react-i18next' import { AGENT_GROUP_NAME, CUSTOM_GROUP_NAME, WORKFLOW_GROUP_NAME } from '../../index-bar' @@ -12,12 +12,14 @@ type Props = { payload: Record hasSearchText: boolean onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void + selectedTools?: ToolValue[] } const ToolListTreeView: FC = ({ payload, hasSearchText, onSelect, + selectedTools, }) => { const { t } = useTranslation() const getI18nGroupName = useCallback((name: string) => { @@ -44,6 +46,7 @@ const ToolListTreeView: FC = ({ toolList={payload[groupName]} hasSearchText={hasSearchText} onSelect={onSelect} + selectedTools={selectedTools} /> ))} diff --git a/web/app/components/workflow/block-selector/tool/tool.tsx b/web/app/components/workflow/block-selector/tool/tool.tsx index c997ec304a..0711c0e1a4 100644 --- a/web/app/components/workflow/block-selector/tool/tool.tsx +++ b/web/app/components/workflow/block-selector/tool/tool.tsx @@ -4,10 +4,11 @@ import React, { useEffect, useMemo } from 'react' import cn from '@/utils/classnames' import { RiArrowDownSLine, RiArrowRightSLine } from '@remixicon/react' import { useGetLanguage } from '@/context/i18n' +import type { Tool as ToolType } from '../../../tools/types' import { CollectionType } from '../../../tools/types' import type { ToolWithProvider } from '../../types' import { BlockEnum } from '../../types' -import type { ToolDefaultValue } from '../types' +import type { ToolDefaultValue, ToolValue } from '../types' import { ViewType } from '../view-type-select' import ActonItem from './action-item' import BlockIcon from '../../block-icon' @@ -20,6 +21,7 @@ type Props = { isShowLetterIndex: boolean hasSearchText: boolean onSelect: (type: BlockEnum, tool?: ToolDefaultValue) => void + selectedTools?: ToolValue[] } const Tool: FC = ({ @@ -29,6 +31,7 @@ const Tool: FC = ({ isShowLetterIndex, hasSearchText, onSelect, + selectedTools, }) => { const { t } = useTranslation() const language = useGetLanguage() @@ -36,6 +39,10 @@ const Tool: FC = ({ const actions = payload.tools const hasAction = true // Now always support actions const [isFold, setFold] = React.useState(true) + const getIsDisabled = (tool: ToolType) => { + if (!selectedTools || !selectedTools.length) return false + return selectedTools.some(selectedTool => selectedTool.provider_name === payload.name && selectedTool.tool_name === tool.name) + } useEffect(() => { if (hasSearchText && isFold) { setFold(false) @@ -116,6 +123,7 @@ const Tool: FC = ({ provider={payload} payload={action} onSelect={onSelect} + disabled={getIsDisabled(action)} /> )) )} diff --git a/web/app/components/workflow/block-selector/tools.tsx b/web/app/components/workflow/block-selector/tools.tsx index 5b5d1da20b..94374be9b8 100644 --- a/web/app/components/workflow/block-selector/tools.tsx +++ b/web/app/components/workflow/block-selector/tools.tsx @@ -6,7 +6,7 @@ import { import { useTranslation } from 'react-i18next' import type { BlockEnum, ToolWithProvider } from '../types' import IndexBar, { groupItems } from './index-bar' -import type { ToolDefaultValue } from './types' +import type { ToolDefaultValue, ToolValue } from './types' import { ViewType } from './view-type-select' import Empty from '@/app/components/tools/add-tool-modal/empty' import { useGetLanguage } from '@/context/i18n' @@ -22,6 +22,7 @@ type ToolsProps = { hasSearchText: boolean className?: string indexBarClassName?: string + selectedTools?: ToolValue[] } const Blocks = ({ showWorkflowEmpty, @@ -31,6 +32,7 @@ const Blocks = ({ hasSearchText, className, indexBarClassName, + selectedTools, }: ToolsProps) => { const { t } = useTranslation() const language = useGetLanguage() @@ -105,12 +107,14 @@ const Blocks = ({ isShowLetterIndex={isShowLetterIndex} hasSearchText={hasSearchText} onSelect={onSelect} + selectedTools={selectedTools} /> ) : ( ) )} diff --git a/web/app/components/workflow/block-selector/types.ts b/web/app/components/workflow/block-selector/types.ts index 787c3fbff1..48679801ec 100644 --- a/web/app/components/workflow/block-selector/types.ts +++ b/web/app/components/workflow/block-selector/types.ts @@ -30,3 +30,12 @@ export type ToolDefaultValue = { paramSchemas: Record[] output_schema: Record } + +export type ToolValue = { + provider_name: string + tool_name: string + tool_label: string + parameters?: Record + enabled?: boolean + extra?: Record +}