@@ -802,9 +778,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
onChange={(e) => {
setCachedStateField("fuzzyMatchThreshold", parseFloat(e.target.value))
}}
- style={{
- ...sliderStyle,
- }}
+ className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
/>
{Math.round((fuzzyMatchThreshold || 1) * 100)}%
diff --git a/webview-ui/src/components/settings/TemperatureControl.tsx b/webview-ui/src/components/settings/TemperatureControl.tsx
index 422356bf69..cbafcc5520 100644
--- a/webview-ui/src/components/settings/TemperatureControl.tsx
+++ b/webview-ui/src/components/settings/TemperatureControl.tsx
@@ -1,5 +1,6 @@
import { VSCodeCheckbox } from "@vscode/webview-ui-toolkit/react"
import { useEffect, useState } from "react"
+import { useDebounce } from "react-use"
interface TemperatureControlProps {
value: number | undefined
@@ -9,13 +10,13 @@ interface TemperatureControlProps {
export const TemperatureControl = ({ value, onChange, maxValue = 1 }: TemperatureControlProps) => {
const [isCustomTemperature, setIsCustomTemperature] = useState(value !== undefined)
- const [inputValue, setInputValue] = useState(value?.toString() ?? "0")
-
+ const [inputValue, setInputValue] = useState(value)
+ useDebounce(() => onChange(inputValue), 50, [onChange, inputValue])
// Sync internal state with prop changes when switching profiles
useEffect(() => {
const hasCustomTemperature = value !== undefined
setIsCustomTemperature(hasCustomTemperature)
- setInputValue(value?.toString() ?? "0")
+ setInputValue(value)
}, [value])
return (
@@ -26,9 +27,9 @@ export const TemperatureControl = ({ value, onChange, maxValue = 1 }: Temperatur
const isChecked = e.target.checked
setIsCustomTemperature(isChecked)
if (!isChecked) {
- onChange(undefined) // Unset the temperature
- } else if (value !== undefined) {
- onChange(value) // Use the value from apiConfiguration, if set
+ setInputValue(undefined) // Unset the temperature
+ } else {
+ setInputValue(value ?? 0) // Use the value from apiConfiguration, if set
}
}}>
Use custom temperature
@@ -48,27 +49,15 @@ export const TemperatureControl = ({ value, onChange, maxValue = 1 }: Temperatur
}}>
setInputValue(e.target.value)}
- onBlur={(e) => {
- const newValue = parseFloat(e.target.value)
- if (!isNaN(newValue) && newValue >= 0 && newValue <= maxValue) {
- onChange(newValue)
- setInputValue(newValue.toString())
- } else {
- setInputValue(value?.toString() ?? "0") // Reset to last valid value
- }
- }}
- style={{
- width: "60px",
- padding: "4px 8px",
- border: "1px solid var(--vscode-input-border)",
- background: "var(--vscode-input-background)",
- color: "var(--vscode-input-foreground)",
- }}
+ className="h-2 focus:outline-0 w-4/5 accent-vscode-button-background"
+ onChange={(e) => setInputValue(parseFloat(e.target.value))}
/>
+ {inputValue}
Higher values make output more random, lower values make it more deterministic.
diff --git a/webview-ui/src/components/settings/__tests__/TemperatureControl.test.tsx b/webview-ui/src/components/settings/__tests__/TemperatureControl.test.tsx
index d178cfafbc..95d0babfdb 100644
--- a/webview-ui/src/components/settings/__tests__/TemperatureControl.test.tsx
+++ b/webview-ui/src/components/settings/__tests__/TemperatureControl.test.tsx
@@ -18,12 +18,12 @@ describe("TemperatureControl", () => {
const checkbox = screen.getByRole("checkbox")
expect(checkbox).toBeChecked()
- const input = screen.getByRole("textbox")
+ const input = screen.getByRole("slider")
expect(input).toBeInTheDocument()
expect(input).toHaveValue("0.7")
})
- it("updates when checkbox is toggled", () => {
+ it("updates when checkbox is toggled", async () => {
const onChange = jest.fn()
render()
@@ -31,40 +31,50 @@ describe("TemperatureControl", () => {
// Uncheck - should clear temperature
fireEvent.click(checkbox)
+ // Waiting for debounce
+ await new Promise((x) => setTimeout(x, 100))
expect(onChange).toHaveBeenCalledWith(undefined)
// Check - should restore previous temperature
fireEvent.click(checkbox)
+ // Waiting for debounce
+ await new Promise((x) => setTimeout(x, 100))
expect(onChange).toHaveBeenCalledWith(0.7)
})
- it("updates temperature when input loses focus", () => {
+ it("updates temperature when input loses focus", async () => {
const onChange = jest.fn()
render()
- const input = screen.getByRole("textbox")
+ const input = screen.getByRole("slider")
fireEvent.change(input, { target: { value: "0.8" } })
fireEvent.blur(input)
+ // Waiting for debounce
+ await new Promise((x) => setTimeout(x, 100))
expect(onChange).toHaveBeenCalledWith(0.8)
})
- it("respects maxValue prop", () => {
+ it("respects maxValue prop", async () => {
const onChange = jest.fn()
render()
- const input = screen.getByRole("textbox")
+ const input = screen.getByRole("slider")
// Valid value within max
fireEvent.change(input, { target: { value: "1.8" } })
fireEvent.blur(input)
+ // Waiting for debounce
+ await new Promise((x) => setTimeout(x, 100))
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
+ expect(input).toHaveValue("2") // Clamped between 0 and 2
+ // Waiting for debounce
+ await new Promise((x) => setTimeout(x, 100))
+ expect(onChange).toHaveBeenCalledWith(2)
})
it("syncs checkbox state when value prop changes", () => {
diff --git a/webview-ui/src/components/ui/alert-dialog.tsx b/webview-ui/src/components/ui/alert-dialog.tsx
new file mode 100644
index 0000000000..7530cae54d
--- /dev/null
+++ b/webview-ui/src/components/ui/alert-dialog.tsx
@@ -0,0 +1,108 @@
+import * as React from "react"
+import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
+
+import { cn } from "@/lib/utils"
+import { buttonVariants } from "@/components/ui/button"
+
+const AlertDialog = AlertDialogPrimitive.Root
+
+const AlertDialogTrigger = AlertDialogPrimitive.Trigger
+
+const AlertDialogPortal = AlertDialogPrimitive.Portal
+
+const AlertDialogOverlay = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
+
+const AlertDialogContent = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+
+
+
+))
+AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
+
+const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes) => (
+
+)
+AlertDialogHeader.displayName = "AlertDialogHeader"
+
+const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes) => (
+
+)
+AlertDialogFooter.displayName = "AlertDialogFooter"
+
+const AlertDialogTitle = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
+
+const AlertDialogDescription = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName
+
+const AlertDialogAction = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
+
+const AlertDialogCancel = React.forwardRef<
+ React.ElementRef,
+ React.ComponentPropsWithoutRef
+>(({ className, ...props }, ref) => (
+
+))
+AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
+
+export {
+ AlertDialog,
+ AlertDialogPortal,
+ AlertDialogOverlay,
+ AlertDialogTrigger,
+ AlertDialogContent,
+ AlertDialogHeader,
+ AlertDialogFooter,
+ AlertDialogTitle,
+ AlertDialogDescription,
+ AlertDialogAction,
+ AlertDialogCancel,
+}
diff --git a/webview-ui/src/components/ui/button.tsx b/webview-ui/src/components/ui/button.tsx
index a9664ce06f..9f60dfedee 100644
--- a/webview-ui/src/components/ui/button.tsx
+++ b/webview-ui/src/components/ui/button.tsx
@@ -5,19 +5,22 @@ import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const buttonVariants = cva(
- "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer active:opacity-90",
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-xs text-base font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
- default: "text-primary-foreground bg-primary shadow hover:bg-primary/90",
- secondary: "text-secondary-foreground bg-secondary shadow-sm hover:bg-secondary/80",
+ default:
+ "border border-vscode-input-border bg-primary text-primary-foreground shadow hover:bg-primary/90 cursor-pointer",
+ destructive:
+ "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90 cursor-pointer",
outline:
- "text-secondary-foreground bg-vscode-editor-background border border-vscode-dropdown-border shadow-sm hover:bg-vscode-editor-background/50",
- ghost: "text-secondary-foreground hover:bg-accent hover:text-accent-foreground",
- link: "text-primary underline-offset-4 hover:underline",
- destructive: "text-destructive-foreground bg-destructive shadow-sm hover:bg-destructive/90",
+ "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground cursor-pointer",
+ secondary:
+ "border border-vscode-input-border bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80 cursor-pointer",
+ ghost: "hover:bg-accent hover:text-accent-foreground cursor-pointer",
+ link: "text-primary underline-offset-4 hover:underline cursor-pointer",
combobox:
- "text-secondary-foreground bg-vscode-input-background border border-vscode-input-border hover:bg-vscode-input-background/80",
+ "text-vscode-font-size font-normal text-popover-foreground bg-vscode-input-background border border-vscode-dropdown-border hover:bg-vscode-input-background/80 cursor-pointer",
},
size: {
default: "h-7 px-3",
diff --git a/webview-ui/src/components/ui/comfirm-dialog.tsx b/webview-ui/src/components/ui/comfirm-dialog.tsx
deleted file mode 100644
index 35d8f999cc..0000000000
--- a/webview-ui/src/components/ui/comfirm-dialog.tsx
+++ /dev/null
@@ -1,58 +0,0 @@
-import { Dialog, DialogContent, DialogTitle } from "./dialog"
-import { VSCodeButton } from "@vscode/webview-ui-toolkit/react"
-import { useCallback } from "react"
-
-export interface ConfirmDialogProps {
- show: boolean
- icon: string
- title?: string
- message: string
- onResult: (confirm: boolean) => void
- onClose: () => void
-}
-export const ConfirmDialog = ({ onResult, onClose, icon, show, title, message }: ConfirmDialogProps) => {
- const onCloseConfirmDialog = useCallback(
- (confirm: boolean) => {
- onResult(confirm)
- onClose()
- },
- [onClose, onResult],
- )
- return (
-
- )
-}
-
-export default ConfirmDialog
diff --git a/webview-ui/src/components/ui/command.tsx b/webview-ui/src/components/ui/command.tsx
index 9580351139..99e987599c 100644
--- a/webview-ui/src/components/ui/command.tsx
+++ b/webview-ui/src/components/ui/command.tsx
@@ -43,7 +43,7 @@ const CommandInput = React.forwardRef<
diff --git a/webview-ui/src/components/ui/input.tsx b/webview-ui/src/components/ui/input.tsx
index 511cefee89..77bea85dad 100644
--- a/webview-ui/src/components/ui/input.tsx
+++ b/webview-ui/src/components/ui/input.tsx
@@ -8,7 +8,7 @@ const Input = React.forwardRef>(