From 29d7023faedd007a0abbf815b0050ba48e990603 Mon Sep 17 00:00:00 2001 From: lyzno1 Date: Thu, 16 Oct 2025 17:46:44 +0800 Subject: [PATCH] - Update all-tools.tsx so provider search results keep only relevant items: full list retained when the provider matches; otherwise the provider is cloned with just matching tools. - Mirror the same filtering strategy for Start-tab trigger plugins in trigger-plugin/list.tsx, ensuring only matching events render when searching. --- .../workflow/block-selector/all-tools.tsx | 37 +++++++++++-- .../block-selector/trigger-plugin/list.tsx | 54 ++++++++++++++----- 2 files changed, 72 insertions(+), 19 deletions(-) diff --git a/web/app/components/workflow/block-selector/all-tools.tsx b/web/app/components/workflow/block-selector/all-tools.tsx index 0f7222ab90..d275e49379 100644 --- a/web/app/components/workflow/block-selector/all-tools.tsx +++ b/web/app/components/workflow/block-selector/all-tools.tsx @@ -85,14 +85,41 @@ const AllTools = ({ if (activeTab === ToolTypeEnum.MCP) mergedTools = mcpTools - if (!hasFilter) + const normalizedSearch = searchText.trim().toLowerCase() + + if (!hasFilter || !normalizedSearch) return mergedTools.filter(toolWithProvider => toolWithProvider.tools.length > 0) - return mergedTools.filter((toolWithProvider) => { - return isMatchingKeywords(toolWithProvider.name, searchText) || toolWithProvider.tools.some((tool) => { - return tool.label[language].toLowerCase().includes(searchText.toLowerCase()) || tool.name.toLowerCase().includes(searchText.toLowerCase()) + return mergedTools.reduce((acc, toolWithProvider) => { + const providerLabel = toolWithProvider.label?.[language] || '' + const providerMatches = isMatchingKeywords(toolWithProvider.name, normalizedSearch) + || (providerLabel && isMatchingKeywords(providerLabel, normalizedSearch)) + + if (providerMatches) { + if (toolWithProvider.tools.length > 0) + acc.push(toolWithProvider) + return acc + } + + const matchedTools = toolWithProvider.tools.filter((tool) => { + const toolLabel = tool.label?.[language] || '' + const toolDescription = typeof tool.description === 'object' ? tool.description?.[language] : '' + return ( + (toolLabel && toolLabel.toLowerCase().includes(normalizedSearch)) + || tool.name.toLowerCase().includes(normalizedSearch) + || (typeof toolDescription === 'string' && toolDescription.toLowerCase().includes(normalizedSearch)) + ) }) - }) + + if (matchedTools.length > 0) { + acc.push({ + ...toolWithProvider, + tools: matchedTools, + }) + } + + return acc + }, []) }, [activeTab, buildInTools, customTools, workflowTools, mcpTools, searchText, language, hasFilter]) const { diff --git a/web/app/components/workflow/block-selector/trigger-plugin/list.tsx b/web/app/components/workflow/block-selector/trigger-plugin/list.tsx index 38f546e884..a2e6d19a1a 100644 --- a/web/app/components/workflow/block-selector/trigger-plugin/list.tsx +++ b/web/app/components/workflow/block-selector/trigger-plugin/list.tsx @@ -3,7 +3,7 @@ import { memo, useEffect, useMemo } from 'react' import { useAllTriggerPlugins } from '@/service/use-triggers' import TriggerPluginItem from './item' import type { BlockEnum } from '../../types' -import type { TriggerDefaultValue } from '../types' +import type { TriggerDefaultValue, TriggerWithProvider } from '../types' import { useGetLanguage } from '@/context/i18n' type TriggerPluginListProps = { @@ -21,23 +21,49 @@ const TriggerPluginList = ({ const { data: triggerPluginsData } = useAllTriggerPlugins() const language = useGetLanguage() + const normalizedSearch = searchText.trim().toLowerCase() const triggerPlugins = useMemo(() => { - // Follow exact same pattern as tools - return (triggerPluginsData || []).filter((triggerWithProvider) => { - if (triggerWithProvider.events.length === 0) return false + const plugins = triggerPluginsData || [] - // Filter by search text - if (searchText) { - const matchesSearch = triggerWithProvider.name.toLowerCase().includes(searchText.toLowerCase()) - || triggerWithProvider.events.some(event => - event.label[language].toLowerCase().includes(searchText.toLowerCase()), - ) - if (!matchesSearch) return false + if (!normalizedSearch) + return plugins.filter(triggerWithProvider => triggerWithProvider.events.length > 0) + + return plugins.reduce((acc, triggerWithProvider) => { + if (triggerWithProvider.events.length === 0) + return acc + + const providerLabel = triggerWithProvider.label?.[language] || '' + const providerMatches = triggerWithProvider.name.toLowerCase().includes(normalizedSearch) + || (providerLabel && providerLabel.toLowerCase().includes(normalizedSearch)) + + if (providerMatches) { + acc.push(triggerWithProvider) + return acc } - return true - }) - }, [triggerPluginsData, searchText, language]) + const matchedEvents = triggerWithProvider.events.filter((event) => { + const rawLabel = event.label?.[language] + const eventLabel = typeof rawLabel === 'string' ? rawLabel.toLowerCase() : '' + const rawDescription = event.description?.[language] + const eventDescription = typeof rawDescription === 'string' ? rawDescription.toLowerCase() : '' + + return ( + eventLabel.includes(normalizedSearch) + || event.name.toLowerCase().includes(normalizedSearch) + || eventDescription.includes(normalizedSearch) + ) + }) + + if (matchedEvents.length > 0) { + acc.push({ + ...triggerWithProvider, + events: matchedEvents, + }) + } + + return acc + }, []) + }, [triggerPluginsData, normalizedSearch, language]) const hasContent = triggerPlugins.length > 0