From 7d9f4e2f0cc6657050612521879cd490f2c28ea6 Mon Sep 17 00:00:00 2001 From: mbeaulne Date: Mon, 29 Jun 2026 13:31:32 -0400 Subject: [PATCH] Simplify editor source filter tooltips --- .../DashboardComponentsV2SourceFilter.tsx | 51 ++++++++++++++++--- .../ComponentSearchV2Content.test.tsx | 49 ++++++++++++++++++ .../components/ComponentSearchV2Content.tsx | 12 +++++ .../components/componentSearchV2Logic.ts | 9 ++++ .../Editor/hooks/useComponentSearchV2State.ts | 45 +++++++++++++--- 5 files changed, 152 insertions(+), 14 deletions(-) diff --git a/src/routes/Dashboard/DashboardComponentsV2SourceFilter.tsx b/src/routes/Dashboard/DashboardComponentsV2SourceFilter.tsx index 7d39a2d84..1ebb65b07 100644 --- a/src/routes/Dashboard/DashboardComponentsV2SourceFilter.tsx +++ b/src/routes/Dashboard/DashboardComponentsV2SourceFilter.tsx @@ -1,6 +1,7 @@ import { Button } from "@/components/ui/button"; import { Icon } from "@/components/ui/icon"; import { BlockStack, InlineStack } from "@/components/ui/layout"; +import { QuickTooltip } from "@/components/ui/tooltip"; import { Paragraph, Text } from "@/components/ui/typography"; import { cn } from "@/lib/utils"; import type { @@ -27,6 +28,16 @@ const SOURCE_FILTER_LABEL_BY_KIND: Record< user: "User generated", }; +const SOURCE_FILTER_TOOLTIP_BY_KIND: Record< + ComponentSearchSource["kind"], + string +> = { + standard: "Standard", + published: "Published", + registered: "Registered", + user: "User", +}; + export interface SourceFilterOption { source: ComponentSearchSource; count: number; @@ -79,6 +90,7 @@ interface SourceFilterBarProps { disabledSourceKeys: string[]; onToggle: (sourceKey: string) => void; onEnableAll: () => void; + display?: "full" | "icons"; } export const SourceFilterBar = ({ @@ -86,6 +98,7 @@ export const SourceFilterBar = ({ disabledSourceKeys, onToggle, onEnableAll, + display = "full", }: SourceFilterBarProps) => { const disabled = new Set(disabledSourceKeys); const activeCount = options.filter( @@ -103,16 +116,20 @@ export const SourceFilterBar = ({ {options.map(({ source, count }) => { const key = sourceFilterKey(source); const active = !disabled.has(key); - return ( + const label = `${source.label} source (${count} component${count === 1 ? "" : "s"})`; + const button = ( ); + + if (display === "icons") { + return ( + + {button} + + ); + } + + return button; })} {activeCount < options.length && ( {isReranking && } + void; clearRerank: () => void; + toggleSourceFilter: (sourceKey: string) => void; + enableAllSources: () => void; } export function registeredSource( diff --git a/src/routes/v2/pages/Editor/hooks/useComponentSearchV2State.ts b/src/routes/v2/pages/Editor/hooks/useComponentSearchV2State.ts index b61a63c0c..c18aec362 100644 --- a/src/routes/v2/pages/Editor/hooks/useComponentSearchV2State.ts +++ b/src/routes/v2/pages/Editor/hooks/useComponentSearchV2State.ts @@ -17,6 +17,10 @@ import { LibraryDB, type StoredLibrary, } from "@/providers/ComponentLibraryProvider/libraries/storage"; +import { + createSourceFilterOptions, + filterIndexByDisabledSourceKeys, +} from "@/routes/Dashboard/DashboardComponentsV2SourceFilter"; import { buildAiCandidateMatches, buildLexicalMatches, @@ -195,10 +199,20 @@ export function useComponentSearchV2State( }), ); + const [disabledSourceKeys, setDisabledSourceKeys] = useState([]); + const sourceFilterOptions = createSourceFilterOptions(index); + const filteredIndex = filterIndexByDisabledSourceKeys( + index, + disabledSourceKeys, + ); + const canUseEmbeddingSearch = aiConfig.apiBase.trim().length > 0; const trimmedQuery = query.trim(); - const lexicalMatches = buildLexicalMatches(index, trimmedQuery); - const aiCandidateMatches = buildAiCandidateMatches(index, trimmedQuery); + const lexicalMatches = buildLexicalMatches(filteredIndex, trimmedQuery); + const aiCandidateMatches = buildAiCandidateMatches( + filteredIndex, + trimmedQuery, + ); const { mutate, reset: resetRerank, @@ -225,7 +239,7 @@ export function useComponentSearchV2State( setRerankedFor(null); setRerankBaseMatches([]); embeddingAbortControllerRef.current?.abort(); - }, [query, resetRerank]); + }, [query, disabledSourceKeys, resetRerank]); useEffect(() => { return () => embeddingAbortControllerRef.current?.abort(); @@ -297,7 +311,7 @@ export function useComponentSearchV2State( const effectiveLimit = limit || LEXICAL_RESULT_LIMIT; const embeddingMatches = canUseEmbeddings ? await buildEmbeddingMatches({ - sourceIndex: index, + sourceIndex: filteredIndex, limit: effectiveLimit, }) : []; @@ -335,6 +349,16 @@ export function useComponentSearchV2State( }); }; + const toggleSourceFilter = (sourceKey: string) => { + setDisabledSourceKeys((current) => + current.includes(sourceKey) + ? current.filter((key) => key !== sourceKey) + : [...current, sourceKey], + ); + }; + + const enableAllSources = () => setDisabledSourceKeys([]); + const rerankMatchByDigest = buildRerankMatchByDigest( rerankData, isRerankActive, @@ -347,11 +371,18 @@ export function useComponentSearchV2State( return { results, - browseFolders: buildResultFolders({ results, standardLibrary }), - searchSuggestions: buildComponentSearchSuggestions(index, { + browseFolders: buildResultFolders({ + results, + standardLibrary: disabledSourceKeys.includes("standard") + ? undefined + : standardLibrary, + }), + searchSuggestions: buildComponentSearchSuggestions(filteredIndex, { includeSources: false, query: trimmedQuery, }), + sourceFilterOptions, + disabledSourceKeys, isLoading: isLoadingStandardLibrary || isLoadingUserComponents || @@ -367,5 +398,7 @@ export function useComponentSearchV2State( isRerankActive, rerank, clearRerank, + toggleSourceFilter, + enableAllSources, }; }