Browse Source

Change input from a slider to a text input

Matt Rubens 11 months ago
parent
commit
be9a90489a

+ 31 - 22
webview-ui/src/components/settings/TemperatureControl.tsx

@@ -9,21 +9,17 @@ interface TemperatureControlProps {
 
 
 export const TemperatureControl = ({ value, onChange, maxValue = 1 }: TemperatureControlProps) => {
 export const TemperatureControl = ({ value, onChange, maxValue = 1 }: TemperatureControlProps) => {
 	const [isCustomTemperature, setIsCustomTemperature] = useState(value !== undefined)
 	const [isCustomTemperature, setIsCustomTemperature] = useState(value !== undefined)
+	const [inputValue, setInputValue] = useState(value?.toString() ?? "0")
 
 
 	// Sync internal state with prop changes when switching profiles
 	// Sync internal state with prop changes when switching profiles
 	useEffect(() => {
 	useEffect(() => {
 		const hasCustomTemperature = value !== undefined
 		const hasCustomTemperature = value !== undefined
 		setIsCustomTemperature(hasCustomTemperature)
 		setIsCustomTemperature(hasCustomTemperature)
+		setInputValue(value?.toString() ?? "0")
 	}, [value])
 	}, [value])
 
 
 	return (
 	return (
-		<div
-			style={{
-				marginTop: 10,
-				marginBottom: 15,
-				paddingLeft: 10,
-				borderLeft: "2px solid var(--vscode-button-background)",
-			}}>
+		<div>
 			<VSCodeCheckbox
 			<VSCodeCheckbox
 				checked={isCustomTemperature}
 				checked={isCustomTemperature}
 				onChange={(e: any) => {
 				onChange={(e: any) => {
@@ -39,31 +35,44 @@ export const TemperatureControl = ({ value, onChange, maxValue = 1 }: Temperatur
 			</VSCodeCheckbox>
 			</VSCodeCheckbox>
 
 
 			<p style={{ fontSize: "12px", marginTop: "5px", color: "var(--vscode-descriptionForeground)" }}>
 			<p style={{ fontSize: "12px", marginTop: "5px", color: "var(--vscode-descriptionForeground)" }}>
-				Controls randomness in the model's responses. Higher values make output more random, lower values make
-				it more deterministic.
+				Controls randomness in the model's responses.
 			</p>
 			</p>
 
 
 			{isCustomTemperature && (
 			{isCustomTemperature && (
-				<div>
+				<div
+					style={{
+						marginTop: 5,
+						marginBottom: 10,
+						paddingLeft: 10,
+						borderLeft: "2px solid var(--vscode-button-background)",
+					}}>
 					<div style={{ display: "flex", alignItems: "center", gap: "5px" }}>
 					<div style={{ display: "flex", alignItems: "center", gap: "5px" }}>
-						<input aria-label="Temperature control range input"
-							type="range"
-							min="0"
-							max={maxValue}
-							step="0.05"
-							value={value ?? 0}
-							onChange={(e) => {
+						<input
+							aria-label="Temperature control text input"
+							type="text"
+							value={inputValue}
+							onChange={(e) => setInputValue(e.target.value)}
+							onBlur={(e) => {
 								const newValue = parseFloat(e.target.value)
 								const newValue = parseFloat(e.target.value)
-								onChange(isNaN(newValue) ? undefined : newValue)
+								if (!isNaN(newValue) && newValue >= 0 && newValue <= maxValue) {
+									onChange(newValue)
+									setInputValue(newValue.toString())
+								} else {
+									setInputValue(value?.toString() ?? "0") // Reset to last valid value
+								}
 							}}
 							}}
 							style={{
 							style={{
-								flexGrow: 1,
-								accentColor: "var(--vscode-button-background)",
-								height: "2px",
+								width: "60px",
+								padding: "4px 8px",
+								border: "1px solid var(--vscode-input-border)",
+								background: "var(--vscode-input-background)",
+								color: "var(--vscode-input-foreground)",
 							}}
 							}}
 						/>
 						/>
-						<span style={{ minWidth: "45px", textAlign: "left" }}>{value?.toFixed(2)}</span>
 					</div>
 					</div>
+					<p style={{ fontSize: "12px", marginTop: "8px", color: "var(--vscode-descriptionForeground)" }}>
+						Higher values make output more random, lower values make it more deterministic.
+					</p>
 				</div>
 				</div>
 			)}
 			)}
 		</div>
 		</div>

+ 20 - 9
webview-ui/src/components/settings/__tests__/TemperatureControl.test.tsx

@@ -8,7 +8,7 @@ describe("TemperatureControl", () => {
 
 
 		const checkbox = screen.getByRole("checkbox")
 		const checkbox = screen.getByRole("checkbox")
 		expect(checkbox).not.toBeChecked()
 		expect(checkbox).not.toBeChecked()
-		expect(screen.queryByRole("slider")).not.toBeInTheDocument()
+		expect(screen.queryByRole("textbox")).not.toBeInTheDocument()
 	})
 	})
 
 
 	it("renders with custom temperature enabled", () => {
 	it("renders with custom temperature enabled", () => {
@@ -18,9 +18,9 @@ describe("TemperatureControl", () => {
 		const checkbox = screen.getByRole("checkbox")
 		const checkbox = screen.getByRole("checkbox")
 		expect(checkbox).toBeChecked()
 		expect(checkbox).toBeChecked()
 
 
-		const slider = screen.getByRole("slider")
-		expect(slider).toBeInTheDocument()
-		expect(slider).toHaveValue("0.7")
+		const input = screen.getByRole("textbox")
+		expect(input).toBeInTheDocument()
+		expect(input).toHaveValue("0.7")
 	})
 	})
 
 
 	it("updates when checkbox is toggled", () => {
 	it("updates when checkbox is toggled", () => {
@@ -38,12 +38,13 @@ describe("TemperatureControl", () => {
 		expect(onChange).toHaveBeenCalledWith(0.7)
 		expect(onChange).toHaveBeenCalledWith(0.7)
 	})
 	})
 
 
-	it("updates temperature when slider changes", () => {
+	it("updates temperature when input loses focus", () => {
 		const onChange = jest.fn()
 		const onChange = jest.fn()
 		render(<TemperatureControl value={0.7} onChange={onChange} />)
 		render(<TemperatureControl value={0.7} onChange={onChange} />)
 
 
-		const slider = screen.getByRole("slider")
-		fireEvent.change(slider, { target: { value: "0.8" } })
+		const input = screen.getByRole("textbox")
+		fireEvent.change(input, { target: { value: "0.8" } })
+		fireEvent.blur(input)
 
 
 		expect(onChange).toHaveBeenCalledWith(0.8)
 		expect(onChange).toHaveBeenCalledWith(0.8)
 	})
 	})
@@ -52,8 +53,18 @@ describe("TemperatureControl", () => {
 		const onChange = jest.fn()
 		const onChange = jest.fn()
 		render(<TemperatureControl value={1.5} onChange={onChange} maxValue={2} />)
 		render(<TemperatureControl value={1.5} onChange={onChange} maxValue={2} />)
 
 
-		const slider = screen.getByRole("slider")
-		expect(slider).toHaveAttribute("max", "2")
+		const input = screen.getByRole("textbox")
+
+		// Valid value within max
+		fireEvent.change(input, { target: { value: "1.8" } })
+		fireEvent.blur(input)
+		expect(onChange).toHaveBeenCalledWith(1.8)
+
+		// Invalid value above max
+		fireEvent.change(input, { target: { value: "2.5" } })
+		fireEvent.blur(input)
+		expect(input).toHaveValue("1.5") // Should revert to original value
+		expect(onChange).toHaveBeenCalledTimes(1) // Should not call onChange for invalid value
 	})
 	})
 
 
 	it("syncs checkbox state when value prop changes", () => {
 	it("syncs checkbox state when value prop changes", () => {