feat(history): move retention settings to history view with gear icon popover

- Add Settings gear icon in HistoryView header with popover for retention settings
- Retention dropdown allows configuring auto-delete task history (never, 3-90 days)
- Settings are saved immediately via vscode.postMessage updateSettings
- Remove retention settings from About.tsx (Settings View)
- Update About.tsx props and tests to remove taskHistoryRetention
This commit is contained in:
Hannes Rudolph 2026-01-26 17:08:56 -07:00
parent 69b6ba5712
commit 739f6c1989
5 changed files with 86 additions and 56 deletions

View file

@ -162,6 +162,7 @@ vi.mock("../utils/autoImportSettings", () => ({
// Avoid filesystem access during activation by stubbing background purge
vi.mock("../utils/task-history-retention", () => ({
startBackgroundRetentionPurge: vi.fn(),
startBackgroundCheckpointPurge: vi.fn(),
}))
// Ensure storage base path resolves to provided path to avoid touching VS Code config

View file

@ -1,14 +1,21 @@
import React, { memo, useState, useMemo } from "react"
import { ArrowLeft } from "lucide-react"
import { ArrowLeft, Settings } from "lucide-react"
import { DeleteTaskDialog } from "./DeleteTaskDialog"
import { BatchDeleteTaskDialog } from "./BatchDeleteTaskDialog"
import { Virtuoso } from "react-virtuoso"
import { TASK_HISTORY_RETENTION_OPTIONS, type TaskHistoryRetentionSetting } from "@roo-code/types"
import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
import { vscode } from "@/utils/vscode"
import { useExtensionState } from "@/context/ExtensionStateContext"
import {
Button,
Checkbox,
Popover,
PopoverContent,
PopoverTrigger,
Select,
SelectContent,
SelectItem,
@ -41,6 +48,7 @@ const HistoryView = ({ onDone }: HistoryViewProps) => {
showAllWorkspaces,
setShowAllWorkspaces,
} = useTaskSearch()
const { taskHistoryRetention } = useExtensionState()
const { t } = useAppTranslation()
// Use grouped tasks hook
@ -51,6 +59,19 @@ const HistoryView = ({ onDone }: HistoryViewProps) => {
const [isSelectionMode, setIsSelectionMode] = useState(false)
const [selectedTaskIds, setSelectedTaskIds] = useState<string[]>([])
const [showBatchDeleteDialog, setShowBatchDeleteDialog] = useState<boolean>(false)
const [isRetentionPopoverOpen, setIsRetentionPopoverOpen] = useState(false)
// Normalize retention setting to ensure it's valid
const normalizedRetention: TaskHistoryRetentionSetting = TASK_HISTORY_RETENTION_OPTIONS.includes(
taskHistoryRetention as TaskHistoryRetentionSetting,
)
? (taskHistoryRetention as TaskHistoryRetentionSetting)
: "never"
// Handle retention setting change
const handleRetentionChange = (value: TaskHistoryRetentionSetting) => {
vscode.postMessage({ type: "updateSettings", updatedSettings: { taskHistoryRetention: value } })
}
// Get subtask count for a task
const getSubtaskCount = useMemo(() => {
@ -116,20 +137,67 @@ const HistoryView = ({ onDone }: HistoryViewProps) => {
</Button>
<h3 className="text-vscode-foreground m-0">{t("history:history")}</h3>
</div>
<StandardTooltip
content={
isSelectionMode ? `${t("history:exitSelectionMode")}` : `${t("history:enterSelectionMode")}`
}>
<Button
variant={isSelectionMode ? "primary" : "secondary"}
onClick={toggleSelectionMode}
data-testid="toggle-selection-mode-button">
<span
className={`codicon ${isSelectionMode ? "codicon-check-all" : "codicon-checklist"} mr-1`}
/>
{isSelectionMode ? t("history:exitSelection") : t("history:selectionMode")}
</Button>
</StandardTooltip>
<div className="flex items-center gap-2">
<Popover open={isRetentionPopoverOpen} onOpenChange={setIsRetentionPopoverOpen}>
<StandardTooltip content={t("settings:aboutRetention.label")}>
<PopoverTrigger asChild>
<Button variant="ghost" size="icon" data-testid="history-retention-settings-button">
<Settings className="size-4" />
</Button>
</PopoverTrigger>
</StandardTooltip>
<PopoverContent className="w-72" align="end">
<div className="space-y-3">
<h4 className="font-medium text-sm">{t("settings:aboutRetention.label")}</h4>
<Select
value={normalizedRetention}
onValueChange={(value: TaskHistoryRetentionSetting) => {
handleRetentionChange(value)
}}>
<SelectTrigger className="w-full">
<SelectValue placeholder={t("settings:common.select")} />
</SelectTrigger>
<SelectContent>
<SelectItem value="never">
{t("settings:aboutRetention.options.never")}
</SelectItem>
<SelectItem value="90">
{t("settings:aboutRetention.options.90")}
</SelectItem>
<SelectItem value="60">
{t("settings:aboutRetention.options.60")}
</SelectItem>
<SelectItem value="30">
{t("settings:aboutRetention.options.30")}
</SelectItem>
<SelectItem value="7">{t("settings:aboutRetention.options.7")}</SelectItem>
<SelectItem value="3">{t("settings:aboutRetention.options.3")}</SelectItem>
</SelectContent>
</Select>
<p className="text-vscode-descriptionForeground text-xs">
{t("settings:aboutRetention.description")}
</p>
<p className="text-red-500 text-xs">{t("settings:aboutRetention.warning")}</p>
</div>
</PopoverContent>
</Popover>
<StandardTooltip
content={
isSelectionMode
? `${t("history:exitSelectionMode")}`
: `${t("history:enterSelectionMode")}`
}>
<Button
variant={isSelectionMode ? "primary" : "secondary"}
onClick={toggleSelectionMode}
data-testid="toggle-selection-mode-button">
<span
className={`codicon ${isSelectionMode ? "codicon-check-all" : "codicon-checklist"} mr-1`}
/>
{isSelectionMode ? t("history:exitSelection") : t("history:selectionMode")}
</Button>
</StandardTooltip>
</div>
</div>
<div className="flex flex-col gap-2">
<VSCodeTextField

View file

@ -16,13 +16,13 @@ import {
} from "lucide-react"
import { VSCodeCheckbox, VSCodeLink } from "@vscode/webview-ui-toolkit/react"
import type { TelemetrySetting, TaskHistoryRetentionSetting } from "@roo-code/types"
import type { TelemetrySetting } from "@roo-code/types"
import { Package } from "@roo/package"
import { vscode } from "@/utils/vscode"
import { cn } from "@/lib/utils"
import { Button, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui"
import { Button } from "@/components/ui"
import { SectionHeader } from "./SectionHeader"
import { Section } from "./Section"
@ -37,8 +37,6 @@ type AboutProps = HTMLAttributes<HTMLDivElement> & {
setTelemetrySetting: (setting: TelemetrySetting) => void
debug?: boolean
setDebug?: (debug: boolean) => void
taskHistoryRetention: TaskHistoryRetentionSetting
setTaskHistoryRetention: (value: TaskHistoryRetentionSetting) => void
taskHistorySize?: TaskHistorySize
}
@ -47,8 +45,6 @@ export const About = ({
setTelemetrySetting,
debug,
setDebug,
taskHistoryRetention,
setTaskHistoryRetention,
taskHistorySize,
className,
...props
@ -195,37 +191,6 @@ export const About = ({
</Section>
<Section className="space-y-0">
<SearchableSetting
settingId="about-task-history-retention"
section="about"
label={t("settings:aboutRetention.label")}
className="mt-4">
<h3>{t("settings:aboutRetention.label")}</h3>
<div className="mt-2">
<Select
value={taskHistoryRetention}
onValueChange={(value: TaskHistoryRetentionSetting) => {
setTaskHistoryRetention(value)
}}>
<SelectTrigger className="w-64">
<SelectValue placeholder={t("settings:common.select")} />
</SelectTrigger>
<SelectContent>
<SelectItem value="never">{t("settings:aboutRetention.options.never")}</SelectItem>
<SelectItem value="90">{t("settings:aboutRetention.options.90")}</SelectItem>
<SelectItem value="60">{t("settings:aboutRetention.options.60")}</SelectItem>
<SelectItem value="30">{t("settings:aboutRetention.options.30")}</SelectItem>
<SelectItem value="7">{t("settings:aboutRetention.options.7")}</SelectItem>
<SelectItem value="3">{t("settings:aboutRetention.options.3")}</SelectItem>
</SelectContent>
</Select>
<div className="text-vscode-descriptionForeground text-sm mt-1">
{t("settings:aboutRetention.description")}
</div>
<div className="text-red-500 text-sm mt-1">{t("settings:aboutRetention.warning")}</div>
</div>
</SearchableSetting>
<SearchableSetting
settingId="about-task-history-count"
section="about"

View file

@ -974,8 +974,6 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone, t
setTelemetrySetting={setTelemetrySetting}
debug={cachedState.debug}
setDebug={setDebug}
taskHistoryRetention={normalizedTaskHistoryRetention}
setTaskHistoryRetention={(value) => setCachedStateField("taskHistoryRetention", value)}
taskHistorySize={taskHistorySize}
/>
)}

View file

@ -31,8 +31,6 @@ describe("About", () => {
const defaultProps: ComponentProps<typeof About> = {
telemetrySetting: "enabled" as const,
setTelemetrySetting: vi.fn(),
taskHistoryRetention: "never",
setTaskHistoryRetention: vi.fn(),
}
beforeEach(() => {