Skip to content

Commit 73a276b

Browse files
author
Eric Wheeler
committed
feat: add limit filter to history view
Added a limit filter dropdown to the history view that allows users to control how many results are displayed. The filter: - Defaults to 50 items - Offers options for 50, 100, 200, 500, 1000 items or all results - Shows loading spinner when changing limits - Integrates with existing workspace and sort filters - Maintains consistent search options across operations Signed-off-by: Eric Wheeler <[email protected]>
1 parent b156e90 commit 73a276b

File tree

3 files changed

+100
-21
lines changed

3 files changed

+100
-21
lines changed

webview-ui/src/components/history/HistoryView.tsx

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ const HistoryView = memo(({ onDone }: HistoryViewProps) => {
4949
workspaceItems,
5050
workspacePath,
5151
setWorkspacePath,
52-
} = useTaskSearch({ workspacePath: WORKSPACE_CURRENT })
52+
resultLimit,
53+
setResultLimit,
54+
} = useTaskSearch({ workspacePath: WORKSPACE_CURRENT, limit: 50 })
5355
const { t } = useAppTranslation()
5456

5557
const [deleteTaskId, setDeleteTaskId] = useState<string | null>(null)
@@ -174,12 +176,15 @@ const HistoryView = memo(({ onDone }: HistoryViewProps) => {
174176
setIsFilterActive={setIsFilterActive}
175177
t={t}
176178
/>
177-
<SortSelector
178-
sortOption={sortOption}
179-
setSortOption={setSortOption}
180-
searchQuery={searchQuery}
181-
t={t}
182-
/>
179+
<div className="flex gap-2 flex-1">
180+
<SortSelector
181+
sortOption={sortOption}
182+
setSortOption={setSortOption}
183+
searchQuery={searchQuery}
184+
t={t}
185+
/>
186+
<LimitSelector resultLimit={resultLimit} setResultLimit={setResultLimit} t={t} />
187+
</div>
183188
</div>
184189

185190
{/* Select all control in selection mode */}
@@ -589,4 +594,68 @@ const SortSelector = memo(
589594
},
590595
)
591596

597+
// Memoized limit selector component
598+
const LimitSelector = memo(
599+
({
600+
resultLimit,
601+
setResultLimit,
602+
t,
603+
}: {
604+
resultLimit: number | undefined
605+
setResultLimit: (value: number | undefined) => void
606+
t: any
607+
}) => {
608+
return (
609+
<Select
610+
value={resultLimit?.toString() || "all"}
611+
onValueChange={(value) => setResultLimit(value === "all" ? undefined : parseInt(value, 10))}>
612+
<SelectTrigger className="flex-1">
613+
<SelectValue>
614+
{t("history:limit.prefix")}{" "}
615+
{resultLimit ? t(`history:limit.${resultLimit}`) : t("history:limit.all")}
616+
</SelectValue>
617+
</SelectTrigger>
618+
<SelectContent className="max-h-[80vh] overflow-auto">
619+
<SelectItem value="50" data-testid="select-limit-50">
620+
<div className="flex items-center gap-2">
621+
<span className="codicon codicon-list-filter" />
622+
{t("history:limit.50")}
623+
</div>
624+
</SelectItem>
625+
<SelectItem value="100" data-testid="select-limit-100">
626+
<div className="flex items-center gap-2">
627+
<span className="codicon codicon-list-filter" />
628+
{t("history:limit.100")}
629+
</div>
630+
</SelectItem>
631+
<SelectItem value="200" data-testid="select-limit-200">
632+
<div className="flex items-center gap-2">
633+
<span className="codicon codicon-list-filter" />
634+
{t("history:limit.200")}
635+
</div>
636+
</SelectItem>
637+
<SelectItem value="500" data-testid="select-limit-500">
638+
<div className="flex items-center gap-2">
639+
<span className="codicon codicon-list-filter" />
640+
{t("history:limit.500")}
641+
</div>
642+
</SelectItem>
643+
<SelectItem value="1000" data-testid="select-limit-1000">
644+
<div className="flex items-center gap-2">
645+
<span className="codicon codicon-list-filter" />
646+
{t("history:limit.1000")}
647+
</div>
648+
</SelectItem>
649+
<SelectItem value="all" data-testid="select-limit-all">
650+
<div className="flex items-center gap-2">
651+
<span className="codicon codicon-list-unfiltered" />
652+
{t("history:limit.all")}
653+
</div>
654+
</SelectItem>
655+
</SelectContent>
656+
</Select>
657+
)
658+
},
659+
)
660+
592661
export default HistoryView

webview-ui/src/components/history/useTaskSearch.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ export const useTaskSearch = (options: HistorySearchOptions = {}) => {
2626
const [lastNonRelevantSort, setLastNonRelevantSort] = useState<HistorySortOption | null>("newest")
2727
const [workspaceItems, setWorkspaceItems] = useState<HistoryWorkspaceItem[]>([])
2828
const [workspacePath, setWorkspacePath] = useState<string | undefined>(options.workspacePath)
29+
const [resultLimit, setResultLimit] = useState<number | undefined>(options.limit)
2930
const currentRequestId = useRef<string>("")
3031

31-
// Wrap setWorkspacePath to set loading state when workspace changes
32+
// Wrap state setters to set loading state when values change
3233
const setWorkspacePathWithLoading = useCallback(
3334
(path: string) => {
3435
if (path !== workspacePath) {
@@ -39,6 +40,11 @@ export const useTaskSearch = (options: HistorySearchOptions = {}) => {
3940
[workspacePath],
4041
)
4142

43+
const setResultLimitWithLoading = useCallback((limit: number | undefined) => {
44+
setLoading(true)
45+
setResultLimit(limit)
46+
}, [])
47+
4248
// Debounced search query setter
4349
const debouncedSetSearchQuery = useCallback((query: string) => {
4450
if (searchTimeoutRef.current) {
@@ -118,14 +124,7 @@ export const useTaskSearch = (options: HistorySearchOptions = {}) => {
118124

119125
vscode.postMessage({
120126
type: "getHistoryItems",
121-
historySearchOptions: {
122-
searchQuery,
123-
sortOption,
124-
// If workspacePath is undefined, show all workspaces
125-
// Otherwise, use the specified workspacePath (which could be empty string for "(unknown)")
126-
workspacePath,
127-
limit: options.limit,
128-
},
127+
historySearchOptions: searchOptions,
129128
requestId: refreshRequestId,
130129
})
131130
}
@@ -138,10 +137,10 @@ export const useTaskSearch = (options: HistorySearchOptions = {}) => {
138137
const searchOptions: HistorySearchOptions = {
139138
searchQuery,
140139
sortOption,
141-
// If workspacePath is undefined, show all workspaces
142-
// Otherwise, use the specified workspacePath (which could be empty string for "(unknown)")
140+
// If workspacePath is undefined, so current workspace
141+
// Otherwise, use the specified workspacePath
143142
workspacePath,
144-
limit: options.limit,
143+
limit: resultLimit,
145144
}
146145

147146
// Generate a new request ID for this search
@@ -160,7 +159,7 @@ export const useTaskSearch = (options: HistorySearchOptions = {}) => {
160159
}
161160
// Intentionally excluding tasks from deps to prevent infinite loop and flickering
162161
// eslint-disable-next-line react-hooks/exhaustive-deps
163-
}, [searchQuery, sortOption, workspacePath, cwd, options.limit])
162+
}, [searchQuery, sortOption, workspacePath, cwd, resultLimit])
164163

165164
return {
166165
tasks,
@@ -175,5 +174,7 @@ export const useTaskSearch = (options: HistorySearchOptions = {}) => {
175174
workspaceItems,
176175
workspacePath,
177176
setWorkspacePath: setWorkspacePathWithLoading,
177+
resultLimit,
178+
setResultLimit: setResultLimitWithLoading,
178179
}
179180
}

webview-ui/src/i18n/locales/en/history.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@
4545
"mostTokens": "Most Tokens",
4646
"mostRelevant": "Most Relevant"
4747
},
48-
"viewAllHistory": "View all tasks"
48+
"viewAllHistory": "View all tasks",
49+
"limit": {
50+
"prefix": "Limit:",
51+
"50": "50",
52+
"100": "100",
53+
"200": "200",
54+
"500": "500",
55+
"1000": "1000",
56+
"all": "All"
57+
},
4958
"noItemsFound": "No items found"
5059
}

0 commit comments

Comments
 (0)