From 5cb268e99bf5068f4e80efa03c39d5d485c99533 Mon Sep 17 00:00:00 2001 From: lyzno1 Date: Wed, 22 Oct 2025 12:14:05 +0800 Subject: [PATCH] feat: suggestions ui --- .../workflow/block-selector/all-tools.tsx | 4 +- .../block-selector/featured-tools.tsx | 117 +++++++++++++----- 2 files changed, 86 insertions(+), 35 deletions(-) diff --git a/web/app/components/workflow/block-selector/all-tools.tsx b/web/app/components/workflow/block-selector/all-tools.tsx index d86795826a..e071c665ae 100644 --- a/web/app/components/workflow/block-selector/all-tools.tsx +++ b/web/app/components/workflow/block-selector/all-tools.tsx @@ -153,7 +153,7 @@ const AllTools = ({ data: recommendedPlugins = [], isLoading: isLoadingRecommended, } = useRecommendedMarketplacePlugins({ - enabled: enable_marketplace, + enabled: enable_marketplace && !isInRAGPipeline, }) const recommendedPluginIds = useMemo( () => recommendedPlugins.map(plugin => plugin.plugin_id), @@ -193,6 +193,7 @@ const AllTools = ({ && activeTab === ToolTypeEnum.All && !hasFilter && !isLoadingRecommended + && !isInRAGPipeline && recommendedPlugins.length > 0 return ( @@ -241,6 +242,7 @@ const AllTools = ({ canChooseMCPTool={canChooseMCPTool} installedPluginIds={installedPluginIds} loadingInstalledStatus={loadingRecommendedInstallStatus} + isLoading={isLoadingRecommended} onInstallSuccess={async () => { invalidateBuiltInTools() await installedCheck.refetch() diff --git a/web/app/components/workflow/block-selector/featured-tools.tsx b/web/app/components/workflow/block-selector/featured-tools.tsx index ba58a34f89..1ae3d9fe22 100644 --- a/web/app/components/workflow/block-selector/featured-tools.tsx +++ b/web/app/components/workflow/block-selector/featured-tools.tsx @@ -10,8 +10,11 @@ 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, RiArrowUpSLine, RiLoader2Line } from '@remixicon/react' +import { RiArrowDownSLine, RiArrowRightSLine, RiArrowUpSLine, RiLoader2Line } 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' const MAX_RECOMMENDED_COUNT = 15 const INITIAL_VISIBLE_COUNT = 5 @@ -24,6 +27,7 @@ type FeaturedToolsProps = { canChooseMCPTool?: boolean installedPluginIds: Set loadingInstalledStatus: boolean + isLoading?: boolean onInstallSuccess?: () => void } @@ -33,6 +37,8 @@ function isToolSelected(tool: Tool, provider: ToolWithProvider, selectedTools?: 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 = ({ plugins, providerMap, @@ -41,12 +47,15 @@ const FeaturedTools = ({ canChooseMCPTool, installedPluginIds, loadingInstalledStatus, + isLoading = false, onInstallSuccess, }: FeaturedToolsProps) => { const { t } = useTranslation() const language = useGetLanguage() const [visibleCount, setVisibleCount] = useState(INITIAL_VISIBLE_COUNT) const [installingIdentifier, setInstallingIdentifier] = useState(null) + const [isCollapsed, setIsCollapsed] = useState(false) + const installMutation = useInstallPackageFromMarketPlace({ onSuccess: () => { onInstallSuccess?.() @@ -56,6 +65,20 @@ const FeaturedTools = ({ }, }) + useEffect(() => { + if (typeof window === 'undefined') + return + const stored = window.localStorage.getItem(STORAGE_KEY) + if (stored !== null) + setIsCollapsed(stored === 'true') + }, []) + + useEffect(() => { + if (typeof window === 'undefined') + return + window.localStorage.setItem(STORAGE_KEY, String(isCollapsed)) + }, [isCollapsed]) + useEffect(() => { setVisibleCount(INITIAL_VISIBLE_COUNT) }, [plugins]) @@ -65,43 +88,69 @@ const FeaturedTools = ({ [plugins, visibleCount], ) - if (!visiblePlugins.length) - return null - const showMore = visibleCount < Math.min(MAX_RECOMMENDED_COUNT, plugins.length) + const isMutating = installMutation.isPending + const showEmptyState = !isLoading && !visiblePlugins.length return (
-
- {t('workflow.tabs.featuredTools')} -
-
- {visiblePlugins.map(plugin => renderFeaturedToolItem({ - plugin, - providerMap, - installedPluginIds, - installMutationPending: installMutation.isPending, - installingIdentifier, - loadingInstalledStatus, - canChooseMCPTool, - onSelect, - selectedTools, - language, - installPlugin: installMutation.mutate, - setInstallingIdentifier, - }))} -
- {showMore && ( - + + + {!isCollapsed && ( + <> + {isLoading && ( +
+ +
+ )} + + {showEmptyState && ( +

+ + {t('workflow.tabs.noFeaturedPlugins')} + +

+ )} + + {!isLoading && visiblePlugins.length > 0 && ( +
+ {visiblePlugins.map(plugin => renderFeaturedToolItem({ + plugin, + providerMap, + installedPluginIds, + installMutationPending: isMutating, + installingIdentifier, + loadingInstalledStatus, + canChooseMCPTool, + onSelect, + selectedTools, + language, + installPlugin: installMutation.mutate, + setInstallingIdentifier, + }))} +
+ )} + + {!isLoading && visiblePlugins.length > 0 && showMore && ( + + )} + )}
)