From 8eec97af2584a6f7242964e8e230ee30edced34b Mon Sep 17 00:00:00 2001 From: Smartsheet-JB-Brown Date: Tue, 15 Apr 2025 13:09:04 -0700 Subject: [PATCH] component details matched tags showing correctly --- .../PackageManagerViewStateManager.ts | 16 ++++-- .../PackageManagerViewStateManager.test.ts | 46 +++++++++++++++ .../components/PackageManagerItemCard.tsx | 37 ++---------- .../package-manager/components/TypeGroup.tsx | 57 ++++++++----------- .../package-manager/utils/grouping.ts | 5 ++ 5 files changed, 92 insertions(+), 69 deletions(-) diff --git a/webview-ui/src/components/package-manager/PackageManagerViewStateManager.ts b/webview-ui/src/components/package-manager/PackageManagerViewStateManager.ts index 5ceb670739..de1c35fc68 100644 --- a/webview-ui/src/components/package-manager/PackageManagerViewStateManager.ts +++ b/webview-ui/src/components/package-manager/PackageManagerViewStateManager.ts @@ -260,26 +260,30 @@ export class PackageManagerViewStateManager { } case "UPDATE_FILTERS": { - const { filters } = transition.payload as TransitionPayloads["UPDATE_FILTERS"] + const { filters = {} } = (transition.payload as TransitionPayloads["UPDATE_FILTERS"]) || {} console.log("=== UPDATE_FILTERS Started ===", { currentFilters: this.state.filters, newFilters: filters, }) + // Create new filters object, preserving existing filters unless explicitly changed + const updatedFilters = { + type: filters.type ?? this.state.filters.type, + search: filters.search ?? this.state.filters.search, + tags: filters.tags ?? this.state.filters.tags, + } + // Update state with new filters this.state = { ...this.state, - filters: { - ...this.state.filters, - ...filters, - }, + filters: updatedFilters, } this.notifyStateChange() // Send filter request immediately vscode.postMessage({ type: "filterPackageManagerItems", - filters: this.state.filters, + filters: updatedFilters, } as WebviewMessage) console.log("=== UPDATE_FILTERS Finished ===") diff --git a/webview-ui/src/components/package-manager/__tests__/PackageManagerViewStateManager.test.ts b/webview-ui/src/components/package-manager/__tests__/PackageManagerViewStateManager.test.ts index 2ec48fbe79..a54d15dbf2 100644 --- a/webview-ui/src/components/package-manager/__tests__/PackageManagerViewStateManager.test.ts +++ b/webview-ui/src/components/package-manager/__tests__/PackageManagerViewStateManager.test.ts @@ -445,6 +445,52 @@ describe("PackageManagerViewStateManager", () => { }, }) }) + + it("should maintain filter criteria when search is cleared", async () => { + // Reset mock before test + ;(vscode.postMessage as jest.Mock).mockClear() + + // First set a type filter + await manager.transition({ + type: "UPDATE_FILTERS", + payload: { + filters: { type: "mode" }, + }, + }) + + // Then add a search term + await manager.transition({ + type: "UPDATE_FILTERS", + payload: { + filters: { search: "test" }, + }, + }) + + // Clear the search term + await manager.transition({ + type: "UPDATE_FILTERS", + payload: { + filters: { search: "" }, + }, + }) + + // Should maintain type filter when search is cleared + expect(vscode.postMessage).toHaveBeenLastCalledWith({ + type: "filterPackageManagerItems", + filters: { + type: "mode", + search: "", + tags: [], + }, + }) + + const state = manager.getState() + expect(state.filters).toEqual({ + type: "mode", + search: "", + tags: [], + }) + }) }) describe("Message Handling", () => { diff --git a/webview-ui/src/components/package-manager/components/PackageManagerItemCard.tsx b/webview-ui/src/components/package-manager/components/PackageManagerItemCard.tsx index 2a2348f77b..8d1ba57484 100644 --- a/webview-ui/src/components/package-manager/components/PackageManagerItemCard.tsx +++ b/webview-ui/src/components/package-manager/components/PackageManagerItemCard.tsx @@ -163,39 +163,14 @@ export const PackageManagerItemCard: React.FC = ({ {groupedItems && ( { - const matchCount = - item.items?.filter( - (subItem) => - (subItem.metadata?.name || "") - .toLowerCase() - .includes(filters.search.toLowerCase()) || - (subItem.metadata?.description || "") - .toLowerCase() - .includes(filters.search.toLowerCase()), - ).length || 0 - return matchCount > 0 - ? `${matchCount} match${matchCount !== 1 ? "es" : ""}` - : undefined - })() - : undefined - } - defaultExpanded={ - !!filters.search && - (item.items?.some( - (subItem) => - (subItem.metadata?.name || "").toLowerCase().includes(filters.search.toLowerCase()) || - (subItem.metadata?.description || "") - .toLowerCase() - .includes(filters.search.toLowerCase()), - ) || - false) - }> + badge={(() => { + const matchCount = item.items?.filter((subItem) => subItem.matchInfo?.matched).length ?? 0 + return matchCount > 0 ? `${matchCount} match${matchCount !== 1 ? "es" : ""}` : undefined + })()} + defaultExpanded={item.items?.some((subItem) => subItem.matchInfo?.matched) ?? false}>
{Object.entries(groupedItems).map(([type, group]) => ( - + ))}
diff --git a/webview-ui/src/components/package-manager/components/TypeGroup.tsx b/webview-ui/src/components/package-manager/components/TypeGroup.tsx index 33a4cde7f6..32e9affb14 100644 --- a/webview-ui/src/components/package-manager/components/TypeGroup.tsx +++ b/webview-ui/src/components/package-manager/components/TypeGroup.tsx @@ -8,12 +8,15 @@ interface TypeGroupProps { description?: string metadata?: any path?: string + matchInfo?: { + matched: boolean + matchReason?: Record + } }> className?: string - searchTerm?: string } -export const TypeGroup: React.FC = ({ type, items, className, searchTerm }) => { +export const TypeGroup: React.FC = ({ type, items, className }) => { const getTypeLabel = (type: string) => { switch (type) { case "mode": @@ -33,41 +36,31 @@ export const TypeGroup: React.FC = ({ type, items, className, se return null } - // Check if an item matches the search term - const itemMatchesSearch = (item: { name: string; description?: string }) => { - if (!searchTerm) return false - const term = searchTerm.toLowerCase() - return item.name.toLowerCase().includes(term) || (item.description || "").toLowerCase().includes(term) - } - return (

{getTypeLabel(type)}

    - {items.map((item, index) => { - const matches = itemMatchesSearch(item) - return ( -
  1. - - {item.name} + {items.map((item, index) => ( +
  2. + + {item.name} + + {item.description && ( + - {item.description} + )} + {item.matchInfo?.matched && ( + + match - {item.description && ( - - {item.description} - )} - {matches && ( - - match - - )} -
  3. - ) - })} + )} + + ))}
) diff --git a/webview-ui/src/components/package-manager/utils/grouping.ts b/webview-ui/src/components/package-manager/utils/grouping.ts index 11c8b641f5..0567fd8adc 100644 --- a/webview-ui/src/components/package-manager/utils/grouping.ts +++ b/webview-ui/src/components/package-manager/utils/grouping.ts @@ -8,6 +8,10 @@ export interface GroupedItems { description?: string metadata?: any path?: string + matchInfo?: { + matched: boolean + matchReason?: Record + } }> } } @@ -39,6 +43,7 @@ export function groupItemsByType(items: PackageManagerItem["items"] = []): Group description: item.metadata?.description, metadata: item.metadata, path: item.path, + matchInfo: item.matchInfo, }) return groups