Browse Source

Create new context management section in settings

Matt Rubens 11 months ago
parent
commit
a679c95412

+ 1 - 74
webview-ui/src/components/settings/AdvancedSettings.tsx

@@ -13,29 +13,16 @@ import { Section } from "./Section"
 
 type AdvancedSettingsProps = HTMLAttributes<HTMLDivElement> & {
 	rateLimitSeconds: number
-	terminalOutputLineLimit?: number
-	maxOpenTabsContext: number
 	diffEnabled?: boolean
 	fuzzyMatchThreshold?: number
-	showRooIgnoredFiles?: boolean
-	setCachedStateField: SetCachedStateField<
-		| "rateLimitSeconds"
-		| "terminalOutputLineLimit"
-		| "maxOpenTabsContext"
-		| "diffEnabled"
-		| "fuzzyMatchThreshold"
-		| "showRooIgnoredFiles"
-	>
+	setCachedStateField: SetCachedStateField<"rateLimitSeconds" | "diffEnabled" | "fuzzyMatchThreshold">
 	experiments: Record<ExperimentId, boolean>
 	setExperimentEnabled: SetExperimentEnabled
 }
 export const AdvancedSettings = ({
 	rateLimitSeconds,
-	terminalOutputLineLimit,
-	maxOpenTabsContext,
 	diffEnabled,
 	fuzzyMatchThreshold,
-	showRooIgnoredFiles,
 	setCachedStateField,
 	experiments,
 	setExperimentEnabled,
@@ -71,52 +58,6 @@ export const AdvancedSettings = ({
 					<p className="text-vscode-descriptionForeground text-sm mt-0">Minimum time between API requests.</p>
 				</div>
 
-				<div>
-					<div className="flex flex-col gap-2">
-						<span className="font-medium">Terminal output limit</span>
-						<div className="flex items-center gap-2">
-							<input
-								type="range"
-								min="100"
-								max="5000"
-								step="100"
-								value={terminalOutputLineLimit ?? 500}
-								onChange={(e) =>
-									setCachedStateField("terminalOutputLineLimit", parseInt(e.target.value))
-								}
-								className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
-							/>
-							<span style={{ ...sliderLabelStyle }}>{terminalOutputLineLimit ?? 500}</span>
-						</div>
-					</div>
-					<p className="text-vscode-descriptionForeground text-sm mt-0">
-						Maximum number of lines to include in terminal output when executing commands. When exceeded
-						lines will be removed from the middle, saving tokens.
-					</p>
-				</div>
-
-				<div>
-					<div className="flex flex-col gap-2">
-						<span className="font-medium">Open tabs context limit</span>
-						<div className="flex items-center gap-2">
-							<input
-								type="range"
-								min="0"
-								max="500"
-								step="1"
-								value={maxOpenTabsContext ?? 20}
-								onChange={(e) => setCachedStateField("maxOpenTabsContext", parseInt(e.target.value))}
-								className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
-							/>
-							<span style={{ ...sliderLabelStyle }}>{maxOpenTabsContext ?? 20}</span>
-						</div>
-					</div>
-					<p className="text-vscode-descriptionForeground text-sm mt-0">
-						Maximum number of VSCode open tabs to include in context. Higher values provide more context but
-						increase token usage.
-					</p>
-				</div>
-
 				<div>
 					<VSCodeCheckbox
 						checked={diffEnabled}
@@ -203,20 +144,6 @@ export const AdvancedSettings = ({
 						</div>
 					)}
 				</div>
-
-				<div>
-					<VSCodeCheckbox
-						checked={showRooIgnoredFiles}
-						onChange={(e: any) => {
-							setCachedStateField("showRooIgnoredFiles", e.target.checked)
-						}}>
-						<span className="font-medium">Show .rooignore'd files in lists and searches</span>
-					</VSCodeCheckbox>
-					<p className="text-vscode-descriptionForeground text-sm mt-0">
-						When enabled, files matching patterns in .rooignore will be shown in lists with a lock symbol.
-						When disabled, these files will be completely hidden from file lists and searches.
-					</p>
-				</div>
 			</Section>
 		</div>
 	)

+ 99 - 0
webview-ui/src/components/settings/ContextManagementSettings.tsx

@@ -0,0 +1,99 @@
+import { HTMLAttributes } from "react"
+import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
+import { Database } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+import { SetCachedStateField } from "./types"
+import { sliderLabelStyle } from "./styles"
+import { SectionHeader } from "./SectionHeader"
+import { Section } from "./Section"
+
+type ContextManagementSettingsProps = HTMLAttributes<HTMLDivElement> & {
+	terminalOutputLineLimit?: number
+	maxOpenTabsContext: number
+	showRooIgnoredFiles?: boolean
+	setCachedStateField: SetCachedStateField<"terminalOutputLineLimit" | "maxOpenTabsContext" | "showRooIgnoredFiles">
+}
+
+export const ContextManagementSettings = ({
+	terminalOutputLineLimit,
+	maxOpenTabsContext,
+	showRooIgnoredFiles,
+	setCachedStateField,
+	className,
+	...props
+}: ContextManagementSettingsProps) => {
+	return (
+		<div className={cn("flex flex-col gap-2", className)} {...props}>
+			<SectionHeader>
+				<div className="flex items-center gap-2">
+					<Database className="w-4" />
+					<div>Context Management</div>
+				</div>
+			</SectionHeader>
+
+			<Section>
+				<div>
+					<div className="flex flex-col gap-2">
+						<span className="font-medium">Terminal output limit</span>
+						<div className="flex items-center gap-2">
+							<input
+								type="range"
+								min="100"
+								max="5000"
+								step="100"
+								value={terminalOutputLineLimit ?? 500}
+								onChange={(e) =>
+									setCachedStateField("terminalOutputLineLimit", parseInt(e.target.value))
+								}
+								className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
+							/>
+							<span style={{ ...sliderLabelStyle }}>{terminalOutputLineLimit ?? 500}</span>
+						</div>
+					</div>
+					<p className="text-vscode-descriptionForeground text-sm mt-0">
+						Maximum number of lines to include in terminal output when executing commands. When exceeded
+						lines will be removed from the middle, saving tokens.
+					</p>
+				</div>
+
+				<div>
+					<div className="flex flex-col gap-2">
+						<span className="font-medium">Open tabs context limit</span>
+						<div className="flex items-center gap-2">
+							<input
+								type="range"
+								min="0"
+								max="500"
+								step="1"
+								value={maxOpenTabsContext ?? 20}
+								onChange={(e) => setCachedStateField("maxOpenTabsContext", parseInt(e.target.value))}
+								className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
+							/>
+							<span style={{ ...sliderLabelStyle }}>{maxOpenTabsContext ?? 20}</span>
+						</div>
+					</div>
+					<p className="text-vscode-descriptionForeground text-sm mt-0">
+						Maximum number of VSCode open tabs to include in context. Higher values provide more context but
+						increase token usage.
+					</p>
+				</div>
+
+				<div>
+					<VSCodeCheckbox
+						checked={showRooIgnoredFiles}
+						onChange={(e: any) => {
+							setCachedStateField("showRooIgnoredFiles", e.target.checked)
+						}}>
+						<span className="font-medium">Show .rooignore'd files in lists and searches</span>
+					</VSCodeCheckbox>
+					<p className="text-vscode-descriptionForeground text-sm mt-0">
+						When enabled, files matching patterns in .rooignore will be shown in lists with a lock symbol.
+						When disabled, these files will be completely hidden from file lists and searches.
+					</p>
+				</div>
+			</Section>
+		</div>
+	)
+}

+ 14 - 3
webview-ui/src/components/settings/SettingsView.tsx

@@ -11,6 +11,7 @@ import {
 	AlertTriangle,
 } from "lucide-react"
 
+import { Database } from "lucide-react"
 import { ExperimentId } from "../../../../src/shared/experiments"
 import { TelemetrySetting } from "../../../../src/shared/TelemetrySetting"
 import { ApiConfiguration } from "../../../../src/shared/api"
@@ -39,6 +40,7 @@ import { AutoApproveSettings } from "./AutoApproveSettings"
 import { BrowserSettings } from "./BrowserSettings"
 import { CheckpointSettings } from "./CheckpointSettings"
 import { NotificationSettings } from "./NotificationSettings"
+import { ContextManagementSettings } from "./ContextManagementSettings"
 import { AdvancedSettings } from "./AdvancedSettings"
 import { SettingsFooter } from "./SettingsFooter"
 import { Section } from "./Section"
@@ -230,6 +232,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
 	const browserRef = useRef<HTMLDivElement>(null)
 	const checkpointRef = useRef<HTMLDivElement>(null)
 	const notificationsRef = useRef<HTMLDivElement>(null)
+	const contextRef = useRef<HTMLDivElement>(null)
 	const advancedRef = useRef<HTMLDivElement>(null)
 	const experimentalRef = useRef<HTMLDivElement>(null)
 
@@ -242,6 +245,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
 			{ id: "browser", icon: SquareMousePointer, ref: browserRef },
 			{ id: "checkpoint", icon: GitBranch, ref: checkpointRef },
 			{ id: "notifications", icon: Bell, ref: notificationsRef },
+			{ id: "context", icon: Database, ref: contextRef },
 			{ id: "advanced", icon: Cog, ref: advancedRef },
 			{ id: "experimental", icon: FlaskConical, ref: experimentalRef },
 		],
@@ -255,6 +259,7 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
 			{ ref: browserRef, id: "browser" },
 			{ ref: checkpointRef, id: "checkpoint" },
 			{ ref: notificationsRef, id: "notifications" },
+			{ ref: contextRef, id: "context" },
 			{ ref: advancedRef, id: "advanced" },
 			{ ref: experimentalRef, id: "experimental" },
 		]
@@ -401,14 +406,20 @@ const SettingsView = forwardRef<SettingsViewRef, SettingsViewProps>(({ onDone },
 					/>
 				</div>
 
+				<div ref={contextRef}>
+					<ContextManagementSettings
+						terminalOutputLineLimit={terminalOutputLineLimit}
+						maxOpenTabsContext={maxOpenTabsContext}
+						showRooIgnoredFiles={showRooIgnoredFiles}
+						setCachedStateField={setCachedStateField}
+					/>
+				</div>
+
 				<div ref={advancedRef}>
 					<AdvancedSettings
 						rateLimitSeconds={rateLimitSeconds}
-						terminalOutputLineLimit={terminalOutputLineLimit}
-						maxOpenTabsContext={maxOpenTabsContext}
 						diffEnabled={diffEnabled}
 						fuzzyMatchThreshold={fuzzyMatchThreshold}
-						showRooIgnoredFiles={showRooIgnoredFiles}
 						setCachedStateField={setCachedStateField}
 						setExperimentEnabled={setExperimentEnabled}
 						experiments={experiments}

+ 58 - 0
webview-ui/src/components/settings/__tests__/ContextManagementSettings.test.tsx

@@ -0,0 +1,58 @@
+import { render, screen, fireEvent } from "@testing-library/react"
+import { ContextManagementSettings } from "../ContextManagementSettings"
+
+describe("ContextManagementSettings", () => {
+	const defaultProps = {
+		terminalOutputLineLimit: 500,
+		maxOpenTabsContext: 20,
+		showRooIgnoredFiles: false,
+		setCachedStateField: jest.fn(),
+	}
+
+	beforeEach(() => {
+		jest.clearAllMocks()
+	})
+
+	it("renders all controls", () => {
+		render(<ContextManagementSettings {...defaultProps} />)
+
+		// Terminal output limit
+		expect(screen.getByText("Terminal output limit")).toBeInTheDocument()
+		expect(screen.getByRole("slider", { name: /Terminal output limit/i })).toHaveValue("500")
+
+		// Open tabs context limit
+		expect(screen.getByText("Open tabs context limit")).toBeInTheDocument()
+		expect(screen.getByRole("slider", { name: /Open tabs context limit/i })).toHaveValue("20")
+
+		// Show .rooignore'd files
+		expect(screen.getByText("Show .rooignore'd files in lists and searches")).toBeInTheDocument()
+		expect(screen.getByRole("checkbox")).not.toBeChecked()
+	})
+
+	it("updates terminal output limit", () => {
+		render(<ContextManagementSettings {...defaultProps} />)
+
+		const slider = screen.getByRole("slider", { name: /Terminal output limit/i })
+		fireEvent.change(slider, { target: { value: "1000" } })
+
+		expect(defaultProps.setCachedStateField).toHaveBeenCalledWith("terminalOutputLineLimit", 1000)
+	})
+
+	it("updates open tabs context limit", () => {
+		render(<ContextManagementSettings {...defaultProps} />)
+
+		const slider = screen.getByRole("slider", { name: /Open tabs context limit/i })
+		fireEvent.change(slider, { target: { value: "50" } })
+
+		expect(defaultProps.setCachedStateField).toHaveBeenCalledWith("maxOpenTabsContext", 50)
+	})
+
+	it("updates show rooignored files setting", () => {
+		render(<ContextManagementSettings {...defaultProps} />)
+
+		const checkbox = screen.getByRole("checkbox")
+		fireEvent.click(checkbox)
+
+		expect(defaultProps.setCachedStateField).toHaveBeenCalledWith("showRooIgnoredFiles", true)
+	})
+})