From 94ea289c7516097b45474815b457d554a216d854 Mon Sep 17 00:00:00 2001 From: lyzno1 Date: Wed, 22 Oct 2025 12:46:07 +0800 Subject: [PATCH] fix: suggestions tools list --- .../workflow/block-selector/all-tools.tsx | 6 - .../block-selector/featured-tools.tsx | 283 ++++++------------ .../workflow/block-selector/tabs.tsx | 6 - .../workflow/block-selector/tool-picker.tsx | 6 - web/service/use-plugins.ts | 19 +- 5 files changed, 93 insertions(+), 227 deletions(-) diff --git a/web/app/components/workflow/block-selector/all-tools.tsx b/web/app/components/workflow/block-selector/all-tools.tsx index e7643dce55..d473ddb541 100644 --- a/web/app/components/workflow/block-selector/all-tools.tsx +++ b/web/app/components/workflow/block-selector/all-tools.tsx @@ -51,8 +51,6 @@ type AllToolsProps = { isInRAGPipeline?: boolean featuredPlugins?: Plugin[] featuredLoading?: boolean - featuredInstalledPluginIds?: Set - featuredInstallLoading?: boolean showFeatured?: boolean onFeaturedInstallSuccess?: () => Promise | void } @@ -77,8 +75,6 @@ const AllTools = ({ isInRAGPipeline = false, featuredPlugins = [], featuredLoading = false, - featuredInstalledPluginIds = new Set(), - featuredInstallLoading = false, showFeatured = false, onFeaturedInstallSuccess, }: AllToolsProps) => { @@ -231,8 +227,6 @@ const AllTools = ({ onSelect={onSelect} selectedTools={selectedTools} canChooseMCPTool={canChooseMCPTool} - installedPluginIds={featuredInstalledPluginIds} - loadingInstalledStatus={featuredInstallLoading} isLoading={featuredLoading} onInstallSuccess={async () => { await onFeaturedInstallSuccess?.() diff --git a/web/app/components/workflow/block-selector/featured-tools.tsx b/web/app/components/workflow/block-selector/featured-tools.tsx index 1ae3d9fe22..e65b99f21c 100644 --- a/web/app/components/workflow/block-selector/featured-tools.tsx +++ b/web/app/components/workflow/block-selector/featured-tools.tsx @@ -6,15 +6,15 @@ import type { ToolDefaultValue, ToolValue } from './types' import type { Plugin } from '@/app/components/plugins/types' import { useGetLanguage } from '@/context/i18n' import Button from '@/app/components/base/button' -import ActionItem from './tool/action-item' -import type { Tool } from '@/app/components/tools/types' -import { CollectionType } from '@/app/components/tools/types' import BlockIcon from '../block-icon' -import { RiArrowDownSLine, RiArrowRightSLine, RiArrowUpSLine, RiLoader2Line } from '@remixicon/react' +import { RiArrowDownSLine, RiArrowRightSLine, RiLoader2Line, RiMoreLine } from '@remixicon/react' import { useInstallPackageFromMarketPlace } from '@/service/use-plugins' import Loading from '@/app/components/base/loading' import Link from 'next/link' import { getMarketplaceUrl } from '@/utils/var' +import { ToolTypeEnum } from './types' +import { ViewType } from './view-type-select' +import Tools from './tools' const MAX_RECOMMENDED_COUNT = 15 const INITIAL_VISIBLE_COUNT = 5 @@ -25,18 +25,10 @@ type FeaturedToolsProps = { onSelect: (type: BlockEnum, tool: ToolDefaultValue) => void selectedTools?: ToolValue[] canChooseMCPTool?: boolean - installedPluginIds: Set - loadingInstalledStatus: boolean isLoading?: boolean onInstallSuccess?: () => void } -function isToolSelected(tool: Tool, provider: ToolWithProvider, selectedTools?: ToolValue[]): boolean { - if (!selectedTools || !selectedTools.length) - return false - return selectedTools.some(item => (item.provider_name === provider.name || item.provider_name === provider.id) && item.tool_name === tool.name) -} - const STORAGE_KEY = 'workflow_tools_featured_collapsed' const FeaturedTools = ({ @@ -45,8 +37,6 @@ const FeaturedTools = ({ onSelect, selectedTools, canChooseMCPTool, - installedPluginIds, - loadingInstalledStatus, isLoading = false, onInstallSuccess, }: FeaturedToolsProps) => { @@ -88,9 +78,22 @@ const FeaturedTools = ({ [plugins, visibleCount], ) + const installedProviders = useMemo( + () => + visiblePlugins + .map(plugin => providerMap.get(plugin.plugin_id)) + .filter((provider): provider is ToolWithProvider => Boolean(provider)), + [visiblePlugins, providerMap], + ) + + const uninstalledPlugins = useMemo( + () => visiblePlugins.filter(plugin => !providerMap.has(plugin.plugin_id)), + [visiblePlugins, providerMap], + ) + const showMore = visibleCount < Math.min(MAX_RECOMMENDED_COUNT, plugins.length) const isMutating = installMutation.isPending - const showEmptyState = !isLoading && !visiblePlugins.length + const showEmptyState = !isLoading && visiblePlugins.length === 0 return (
@@ -119,36 +122,58 @@ const FeaturedTools = ({

)} - {!isLoading && visiblePlugins.length > 0 && ( -
- {visiblePlugins.map(plugin => renderFeaturedToolItem({ - plugin, - providerMap, - installedPluginIds, - installMutationPending: isMutating, - installingIdentifier, - loadingInstalledStatus, - canChooseMCPTool, - onSelect, - selectedTools, - language, - installPlugin: installMutation.mutate, - setInstallingIdentifier, - }))} -
+ {!showEmptyState && !isLoading && ( + <> + {installedProviders.length > 0 && ( + + )} + + {uninstalledPlugins.length > 0 && ( +
+ {uninstalledPlugins.map(plugin => ( + { + if (isMutating) + return + setInstallingIdentifier(plugin.latest_package_identifier) + installMutation.mutate(plugin.latest_package_identifier) + }} + t={t} + /> + ))} +
+ )} + )} {!isLoading && visiblePlugins.length > 0 && showMore && ( - +
+ +
+
+ {t('common.operation.more')} +
+
)} )} @@ -156,177 +181,51 @@ const FeaturedTools = ({ ) } -type FeaturedToolItemProps = { +type FeaturedToolUninstalledItemProps = { plugin: Plugin - provider: ToolWithProvider | undefined - isInstalled: boolean - installDisabled: boolean - canChooseMCPTool?: boolean - onSelect: (type: BlockEnum, tool: ToolDefaultValue) => void - selectedTools?: ToolValue[] language: string + installing: boolean onInstall: () => void - isInstalling: boolean + t: (key: string, options?: Record) => string } -function FeaturedToolItem({ +function FeaturedToolUninstalledItem({ plugin, - provider, - isInstalled, - installDisabled, - canChooseMCPTool, - onSelect, - selectedTools, language, + installing, onInstall, - isInstalling, -}: FeaturedToolItemProps) { - const { t } = useTranslation() - const [isExpanded, setExpanded] = useState(false) - const hasProvider = Boolean(provider) - const installCountLabel = t('plugin.install', { num: plugin.install_count?.toLocaleString() ?? 0 }) + t, +}: FeaturedToolUninstalledItemProps) { + const label = plugin.label?.[language] || plugin.name const description = typeof plugin.brief === 'object' ? plugin.brief[language] : plugin.brief - - useEffect(() => { - if (!hasProvider) - setExpanded(false) - }, [hasProvider]) - - let toggleLabel: string - if (!hasProvider) - toggleLabel = t('workflow.common.syncingData') - else if (isExpanded) - toggleLabel = t('workflow.tabs.hideActions') - else - toggleLabel = t('workflow.tabs.usePlugin') + const installCountLabel = t('plugin.install', { num: plugin.install_count?.toLocaleString() ?? 0 }) return ( -
-
+
+
-
-
-
- {plugin.label?.[language] || plugin.name} -
- {isInstalled && ( - - {t('workflow.tabs.installed')} - - )} -
-
- {description} -
-
- {installCountLabel} - {plugin.org && {t('workflow.tabs.pluginByAuthor', { author: plugin.org })}} -
-
-
- {!isInstalled && ( - - )} - {isInstalled && ( - +
+
{label}
+ {description && ( +
{description}
)}
- {isInstalled && hasProvider && isExpanded && ( -
- {provider.tools.map((tool) => { - const isSelected = isToolSelected(tool, provider, selectedTools) - const isMCPTool = provider.type === CollectionType.mcp - const disabled = isSelected || (!canChooseMCPTool && isMCPTool) - - return ( - - ) - })} -
- )} +
+ {installCountLabel} + +
) } -type RenderFeaturedToolParams = { - plugin: Plugin - providerMap: Map - installedPluginIds: Set - installMutationPending: boolean - installingIdentifier: string | null - loadingInstalledStatus: boolean - canChooseMCPTool?: boolean - onSelect: (type: BlockEnum, tool: ToolDefaultValue) => void - selectedTools?: ToolValue[] - language: string - installPlugin: (uniqueIdentifier: string) => void - setInstallingIdentifier: (identifier: string | null) => void -} - -function renderFeaturedToolItem({ - plugin, - providerMap, - installedPluginIds, - installMutationPending, - installingIdentifier, - loadingInstalledStatus, - canChooseMCPTool, - onSelect, - selectedTools, - language, - installPlugin, - setInstallingIdentifier, -}: RenderFeaturedToolParams) { - const provider = providerMap.get(plugin.plugin_id) - const isInstalled = installedPluginIds.has(plugin.plugin_id) - const isInstalling = installMutationPending && installingIdentifier === plugin.latest_package_identifier - - return ( - { - if (installMutationPending) - return - setInstallingIdentifier(plugin.latest_package_identifier) - installPlugin(plugin.latest_package_identifier) - }} - isInstalling={isInstalling} - /> - ) -} - export default FeaturedTools diff --git a/web/app/components/workflow/block-selector/tabs.tsx b/web/app/components/workflow/block-selector/tabs.tsx index 444ddcd419..17de4b74d2 100644 --- a/web/app/components/workflow/block-selector/tabs.tsx +++ b/web/app/components/workflow/block-selector/tabs.tsx @@ -61,9 +61,6 @@ const Tabs: FC = ({ const { plugins: featuredPlugins = [], isLoading: isFeaturedLoading, - installedIds: featuredInstalledIds, - installStatusLoading: featuredInstallLoading, - refetchInstallStatus: refetchFeaturedInstallStatus, } = useFeaturedToolsRecommendations(enable_marketplace && !inRAGPipeline) return ( @@ -142,12 +139,9 @@ const Tabs: FC = ({ isInRAGPipeline={inRAGPipeline} featuredPlugins={featuredPlugins} featuredLoading={isFeaturedLoading} - featuredInstalledPluginIds={featuredInstalledIds} - featuredInstallLoading={featuredInstallLoading} showFeatured={enable_marketplace && !inRAGPipeline} onFeaturedInstallSuccess={async () => { invalidateBuiltInTools() - await refetchFeaturedInstallStatus() }} /> ) diff --git a/web/app/components/workflow/block-selector/tool-picker.tsx b/web/app/components/workflow/block-selector/tool-picker.tsx index 809a7b1cc9..c438e45042 100644 --- a/web/app/components/workflow/block-selector/tool-picker.tsx +++ b/web/app/components/workflow/block-selector/tool-picker.tsx @@ -74,9 +74,6 @@ const ToolPicker: FC = ({ const { plugins: featuredPlugins = [], isLoading: isFeaturedLoading, - installedIds: featuredInstalledIds, - installStatusLoading: featuredInstallLoading, - refetchInstallStatus: refetchFeaturedInstallStatus, } = useFeaturedToolsRecommendations(enable_marketplace) const { builtinToolList, customToolList, workflowToolList } = useMemo(() => { @@ -193,12 +190,9 @@ const ToolPicker: FC = ({ onTagsChange={setTags} featuredPlugins={featuredPlugins} featuredLoading={isFeaturedLoading} - featuredInstalledPluginIds={featuredInstalledIds} - featuredInstallLoading={featuredInstallLoading} showFeatured={scope === 'all' && enable_marketplace} onFeaturedInstallSuccess={async () => { invalidateBuiltInTools() - await refetchFeaturedInstallStatus() }} />
diff --git a/web/service/use-plugins.ts b/web/service/use-plugins.ts index 8eb7cbb0da..5904da6d27 100644 --- a/web/service/use-plugins.ts +++ b/web/service/use-plugins.ts @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo } from 'react' +import { useCallback, useEffect } from 'react' import type { FormOption, ModelProvider, @@ -104,25 +104,10 @@ export const useFeaturedToolsRecommendations = (enabled: boolean, limit = 15) => enabled, limit, }) - const pluginIds = useMemo( - () => plugins.map(plugin => plugin.plugin_id), - [plugins], - ) - const installedCheck = useCheckInstalled({ - pluginIds, - enabled: enabled && pluginIds.length > 0, - }) - const installedIds = useMemo( - () => new Set(installedCheck.data?.plugins.map(plugin => plugin.plugin_id) ?? []), - [installedCheck.data], - ) - const installStatusLoading = installedCheck.isLoading || installedCheck.isRefetching + return { plugins, isLoading, - installedIds, - installStatusLoading, - refetchInstallStatus: installedCheck.refetch, } }