From 38759b229de5171a794546b931b0d3664e4b78da Mon Sep 17 00:00:00 2001 From: RockChinQ Date: Sat, 6 Jun 2026 08:11:59 -0400 Subject: [PATCH] feat(plugin-market): show per-format extension counts in type filter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirror the LangBot Space marketplace: the advanced-filter type options (plugin / MCP / skill) now display their live extension count, e.g. "插件 (74)". Counts are fetched on mount via three lightweight searchMarketplaceExtensions calls (page_size=1) reading total per type. The all-formats option intentionally shows no count. --- .../plugin-market/PluginMarketComponent.tsx | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/web/src/app/home/plugins/components/plugin-market/PluginMarketComponent.tsx b/web/src/app/home/plugins/components/plugin-market/PluginMarketComponent.tsx index aceca127..03c7b49d 100644 --- a/web/src/app/home/plugins/components/plugin-market/PluginMarketComponent.tsx +++ b/web/src/app/home/plugins/components/plugin-market/PluginMarketComponent.tsx @@ -124,6 +124,8 @@ function MarketPageContent({ const [hasMore, setHasMore] = useState(true); const [currentPage, setCurrentPage] = useState(1); const [total, setTotal] = useState(0); + // Per-format extension counts shown next to the type filter options. + const [typeCounts, setTypeCounts] = useState>({}); const [sortOption, setSortOption] = useState( () => loadMarketFilters().sortOption ?? 'install_count_desc', ); @@ -320,6 +322,7 @@ function MarketPageContent({ fetchPlugins(1, false, true); fetchAvailableTags(); fetchRecommendationLists(); + fetchTypeCounts(); })(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -359,6 +362,32 @@ function MarketPageContent({ } }; + // 获取各扩展格式的数量(用于筛选器标签上的计数) + const fetchTypeCounts = async () => { + const types = ['plugin', 'mcp', 'skill']; + try { + const results = await Promise.all( + types.map((type) => + getCloudServiceClientSync() + .searchMarketplaceExtensions({ + page: 1, + page_size: 1, + type_filter: type, + }) + .then((res) => res.total) + .catch(() => 0), + ), + ); + const counts: Record = {}; + types.forEach((type, i) => { + counts[type] = results[i]; + }); + setTypeCounts(counts); + } catch (error) { + console.error('Failed to fetch extension type counts:', error); + } + }; + // 搜索功能 const handleSearch = useCallback( (query: string) => { @@ -682,6 +711,7 @@ function MarketPageContent({ > {extensionTypeOptions.map((option) => { const Icon = option.icon; + const count = typeCounts[option.value]; return ( {Icon && } {option.label} + {typeof count === 'number' && ( + + ({count}) + + )} ); })}