mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
component details matched tags showing correctly
This commit is contained in:
parent
c0672358c7
commit
8eec97af25
5 changed files with 92 additions and 69 deletions
|
|
@ -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 ===")
|
||||
|
|
|
|||
|
|
@ -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", () => {
|
||||
|
|
|
|||
|
|
@ -163,39 +163,14 @@ export const PackageManagerItemCard: React.FC<PackageManagerItemCardProps> = ({
|
|||
{groupedItems && (
|
||||
<ExpandableSection
|
||||
title="Component Details"
|
||||
badge={
|
||||
filters.search
|
||||
? (() => {
|
||||
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}>
|
||||
<div className="space-y-4">
|
||||
{Object.entries(groupedItems).map(([type, group]) => (
|
||||
<TypeGroup key={type} type={type} items={group.items} searchTerm={filters.search} />
|
||||
<TypeGroup key={type} type={type} items={group.items} />
|
||||
))}
|
||||
</div>
|
||||
</ExpandableSection>
|
||||
|
|
|
|||
|
|
@ -8,12 +8,15 @@ interface TypeGroupProps {
|
|||
description?: string
|
||||
metadata?: any
|
||||
path?: string
|
||||
matchInfo?: {
|
||||
matched: boolean
|
||||
matchReason?: Record<string, boolean>
|
||||
}
|
||||
}>
|
||||
className?: string
|
||||
searchTerm?: string
|
||||
}
|
||||
|
||||
export const TypeGroup: React.FC<TypeGroupProps> = ({ type, items, className, searchTerm }) => {
|
||||
export const TypeGroup: React.FC<TypeGroupProps> = ({ type, items, className }) => {
|
||||
const getTypeLabel = (type: string) => {
|
||||
switch (type) {
|
||||
case "mode":
|
||||
|
|
@ -33,41 +36,31 @@ export const TypeGroup: React.FC<TypeGroupProps> = ({ 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 (
|
||||
<div className={cn("mb-4", className)}>
|
||||
<h4 className="text-sm font-medium text-vscode-foreground mb-2">{getTypeLabel(type)}</h4>
|
||||
<ol className="list-decimal list-inside space-y-1">
|
||||
{items.map((item, index) => {
|
||||
const matches = itemMatchesSearch(item)
|
||||
return (
|
||||
<li
|
||||
key={`${item.path || index}`}
|
||||
className={cn(
|
||||
"text-sm pl-1",
|
||||
matches ? "text-vscode-foreground font-medium" : "text-vscode-foreground",
|
||||
)}
|
||||
title={item.path}>
|
||||
<span className={cn("font-medium", matches ? "text-vscode-textLink" : "")}>
|
||||
{item.name}
|
||||
{items.map((item, index) => (
|
||||
<li
|
||||
key={`${item.path || index}`}
|
||||
className={cn(
|
||||
"text-sm pl-1",
|
||||
item.matchInfo?.matched ? "text-vscode-foreground font-medium" : "text-vscode-foreground",
|
||||
)}
|
||||
title={item.path}>
|
||||
<span className={cn("font-medium", item.matchInfo?.matched ? "text-vscode-textLink" : "")}>
|
||||
{item.name}
|
||||
</span>
|
||||
{item.description && (
|
||||
<span className="text-vscode-descriptionForeground"> - {item.description}</span>
|
||||
)}
|
||||
{item.matchInfo?.matched && (
|
||||
<span className="ml-2 text-xs bg-vscode-badge-background text-vscode-badge-foreground px-1 py-0.5 rounded">
|
||||
match
|
||||
</span>
|
||||
{item.description && (
|
||||
<span className="text-vscode-descriptionForeground"> - {item.description}</span>
|
||||
)}
|
||||
{matches && (
|
||||
<span className="ml-2 text-xs bg-vscode-badge-background text-vscode-badge-foreground px-1 py-0.5 rounded">
|
||||
match
|
||||
</span>
|
||||
)}
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,10 @@ export interface GroupedItems {
|
|||
description?: string
|
||||
metadata?: any
|
||||
path?: string
|
||||
matchInfo?: {
|
||||
matched: boolean
|
||||
matchReason?: Record<string, boolean>
|
||||
}
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue