mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
Fix settings dropdown issues
This commit is contained in:
parent
e5d764ccba
commit
ebacc14b48
5 changed files with 449 additions and 47 deletions
224
webview-ui/package-lock.json
generated
224
webview-ui/package-lock.json
generated
|
|
@ -15,6 +15,7 @@
|
|||
"@radix-ui/react-icons": "^1.3.2",
|
||||
"@radix-ui/react-popover": "^1.1.6",
|
||||
"@radix-ui/react-progress": "^1.1.2",
|
||||
"@radix-ui/react-select": "^2.1.6",
|
||||
"@radix-ui/react-separator": "^1.1.2",
|
||||
"@radix-ui/react-slider": "^1.2.3",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
|
|
@ -4688,6 +4689,229 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select": {
|
||||
"version": "2.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.1.6.tgz",
|
||||
"integrity": "sha512-T6ajELxRvTuAMWH0YmRJ1qez+x4/7Nq7QIx7zJ0VK3qaEWdnWpNbEDnmWldG1zBDwqrLy5aLMUWcoGirVj5kMg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/number": "1.1.0",
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
"@radix-ui/react-collection": "1.1.2",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-context": "1.1.1",
|
||||
"@radix-ui/react-direction": "1.1.0",
|
||||
"@radix-ui/react-dismissable-layer": "1.1.5",
|
||||
"@radix-ui/react-focus-guards": "1.1.1",
|
||||
"@radix-ui/react-focus-scope": "1.1.2",
|
||||
"@radix-ui/react-id": "1.1.0",
|
||||
"@radix-ui/react-popper": "1.2.2",
|
||||
"@radix-ui/react-portal": "1.1.4",
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-slot": "1.1.2",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||
"@radix-ui/react-use-controllable-state": "1.1.0",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0",
|
||||
"@radix-ui/react-use-previous": "1.1.0",
|
||||
"@radix-ui/react-visually-hidden": "1.1.2",
|
||||
"aria-hidden": "^1.2.4",
|
||||
"react-remove-scroll": "^2.6.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-arrow": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.2.tgz",
|
||||
"integrity": "sha512-G+KcpzXHq24iH0uGG/pF8LyzpFJYGD4RfLjCIBfGdSLXvjLHST31RUiRVrupIBMvIppMgSzQ6l66iAxl03tdlg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-collection": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.2.tgz",
|
||||
"integrity": "sha512-9z54IEKRxIa9VityapoEYMuByaG42iSy1ZXlY2KcuLSEtq8x4987/N6m15ppoMffgZX72gER2uHe1D9Y6Unlcw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-context": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-slot": "1.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-dismissable-layer": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.5.tgz",
|
||||
"integrity": "sha512-E4TywXY6UsXNRhFrECa5HAvE5/4BFcGyfTyK36gP+pAW1ed7UTK4vKwdr53gAJYwqbfCWC6ATvJa3J3R/9+Qrg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.1",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||
"@radix-ui/react-use-escape-keydown": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-focus-scope": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.2.tgz",
|
||||
"integrity": "sha512-zxwE80FCU7lcXUGWkdt6XpTTCKPitG1XKOwViTxHVKIJhZl9MvIl2dVHeZENCWD9+EdWv05wlaEkRXUykU27RA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-popper": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.2.tgz",
|
||||
"integrity": "sha512-Rvqc3nOpwseCyj/rgjlJDYAgyfw7OC1tTkKn2ivhaMGcYt8FSBlahHOZak2i3QwkRXUXgGgzeEe2RuqeEHuHgA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^2.0.0",
|
||||
"@radix-ui/react-arrow": "1.1.2",
|
||||
"@radix-ui/react-compose-refs": "1.1.1",
|
||||
"@radix-ui/react-context": "1.1.1",
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-use-callback-ref": "1.1.0",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0",
|
||||
"@radix-ui/react-use-rect": "1.1.0",
|
||||
"@radix-ui/react-use-size": "1.1.0",
|
||||
"@radix-ui/rect": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-portal": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.4.tgz",
|
||||
"integrity": "sha512-sn2O9k1rPFYVyKd5LAJfo96JlSGVFpa1fS6UuBJfrZadudiw5tAmru+n1x7aMRQ84qDM71Zh1+SzK5QwU0tJfA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-primitive": "2.0.2",
|
||||
"@radix-ui/react-use-layout-effect": "1.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select/node_modules/@radix-ui/react-primitive": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.2.tgz",
|
||||
"integrity": "sha512-Ec/0d38EIuvDF+GZjcMU/Ze6MxntVJYO/fRlCPhCaVUyPY9WTalHJw54tp9sXeJo3tlShWpy41vQRgLRGOuz+w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-slot": "1.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-separator": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.2.tgz",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
"@radix-ui/react-icons": "^1.3.2",
|
||||
"@radix-ui/react-popover": "^1.1.6",
|
||||
"@radix-ui/react-progress": "^1.1.2",
|
||||
"@radix-ui/react-select": "^2.1.6",
|
||||
"@radix-ui/react-separator": "^1.1.2",
|
||||
"@radix-ui/react-slider": "^1.2.3",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import { Checkbox, Dropdown, type DropdownOption } from "vscrui"
|
|||
import { VSCodeLink, VSCodeRadio, VSCodeRadioGroup, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
|
||||
import * as vscodemodels from "vscode"
|
||||
|
||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue, Button } from "@/components/ui"
|
||||
|
||||
import {
|
||||
ApiConfiguration,
|
||||
ModelInfo,
|
||||
|
|
@ -42,7 +44,6 @@ import { TemperatureControl } from "./TemperatureControl"
|
|||
import { validateApiConfiguration, validateModelId } from "@/utils/validate"
|
||||
import { ApiErrorMessage } from "./ApiErrorMessage"
|
||||
import { ThinkingBudget } from "./ThinkingBudget"
|
||||
import { Button } from "../ui"
|
||||
|
||||
const modelsByProvider: Record<string, Record<string, ModelInfo>> = {
|
||||
anthropic: anthropicModels,
|
||||
|
|
@ -54,6 +55,25 @@ const modelsByProvider: Record<string, Record<string, ModelInfo>> = {
|
|||
mistral: mistralModels,
|
||||
}
|
||||
|
||||
const providers = [
|
||||
{ value: "openrouter", label: "OpenRouter" },
|
||||
{ value: "anthropic", label: "Anthropic" },
|
||||
{ value: "gemini", label: "Google Gemini" },
|
||||
{ value: "deepseek", label: "DeepSeek" },
|
||||
{ value: "openai-native", label: "OpenAI" },
|
||||
{ value: "openai", label: "OpenAI Compatible" },
|
||||
{ value: "vertex", label: "GCP Vertex AI" },
|
||||
{ value: "bedrock", label: "AWS Bedrock" },
|
||||
{ value: "glama", label: "Glama" },
|
||||
{ value: "vscode-lm", label: "VS Code LM API" },
|
||||
{ value: "mistral", label: "Mistral" },
|
||||
{ value: "lmstudio", label: "LM Studio" },
|
||||
{ value: "ollama", label: "Ollama" },
|
||||
{ value: "unbound", label: "Unbound" },
|
||||
{ value: "requesty", label: "Requesty" },
|
||||
{ value: "human-relay", label: "Human Relay" },
|
||||
]
|
||||
|
||||
interface ApiOptionsProps {
|
||||
uriScheme: string | undefined
|
||||
apiConfiguration: ApiConfiguration
|
||||
|
|
@ -238,30 +258,22 @@ const ApiOptions = ({
|
|||
<label htmlFor="api-provider" className="font-medium">
|
||||
API Provider
|
||||
</label>
|
||||
<Dropdown
|
||||
id="api-provider"
|
||||
<Select
|
||||
value={selectedProvider}
|
||||
onChange={handleInputChange("apiProvider", dropdownEventTransform)}
|
||||
options={[
|
||||
{ value: "openrouter", label: "OpenRouter" },
|
||||
{ value: "anthropic", label: "Anthropic" },
|
||||
{ value: "gemini", label: "Google Gemini" },
|
||||
{ value: "deepseek", label: "DeepSeek" },
|
||||
{ value: "openai-native", label: "OpenAI" },
|
||||
{ value: "openai", label: "OpenAI Compatible" },
|
||||
{ value: "vertex", label: "GCP Vertex AI" },
|
||||
{ value: "bedrock", label: "AWS Bedrock" },
|
||||
{ value: "glama", label: "Glama" },
|
||||
{ value: "vscode-lm", label: "VS Code LM API" },
|
||||
{ value: "mistral", label: "Mistral" },
|
||||
{ value: "lmstudio", label: "LM Studio" },
|
||||
{ value: "ollama", label: "Ollama" },
|
||||
{ value: "unbound", label: "Unbound" },
|
||||
{ value: "requesty", label: "Requesty" },
|
||||
{ value: "human-relay", label: "Human Relay" },
|
||||
]}
|
||||
className="w-full"
|
||||
/>
|
||||
onValueChange={handleInputChange("apiProvider", dropdownEventTransform)}>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue placeholder="Select" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectGroup>
|
||||
{providers.map(({ value, label }) => (
|
||||
<SelectItem key={value} value={value}>
|
||||
{label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectGroup>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{errorMessage && <ApiErrorMessage errorMessage={errorMessage} />}
|
||||
|
|
@ -424,10 +436,10 @@ const ApiOptions = ({
|
|||
<>
|
||||
<VSCodeTextField
|
||||
value={apiConfiguration?.mistralApiKey || ""}
|
||||
style={{ width: "100%" }}
|
||||
type="password"
|
||||
onInput={handleInputChange("mistralApiKey")}
|
||||
placeholder="Enter API Key...">
|
||||
placeholder="Enter API Key..."
|
||||
className="w-full">
|
||||
<span className="font-medium">Mistral API Key</span>
|
||||
</VSCodeTextField>
|
||||
<div className="text-sm text-vscode-descriptionForeground -mt-2">
|
||||
|
|
@ -575,16 +587,16 @@ const ApiOptions = ({
|
|||
</div>
|
||||
<VSCodeTextField
|
||||
value={apiConfiguration?.vertexJsonCredentials || ""}
|
||||
style={{ width: "100%" }}
|
||||
onInput={handleInputChange("vertexJsonCredentials")}
|
||||
placeholder="Enter Credentials JSON...">
|
||||
placeholder="Enter Credentials JSON..."
|
||||
className="w-full">
|
||||
<span className="font-medium">Google Cloud Credentials</span>
|
||||
</VSCodeTextField>
|
||||
<VSCodeTextField
|
||||
value={apiConfiguration?.vertexKeyFile || ""}
|
||||
style={{ width: "100%" }}
|
||||
onInput={handleInputChange("vertexKeyFile")}
|
||||
placeholder="Enter Key File Path...">
|
||||
placeholder="Enter Key File Path..."
|
||||
className="w-full">
|
||||
<span className="font-medium">Google Cloud Key File Path</span>
|
||||
</VSCodeTextField>
|
||||
<VSCodeTextField
|
||||
|
|
@ -620,10 +632,10 @@ const ApiOptions = ({
|
|||
<>
|
||||
<VSCodeTextField
|
||||
value={apiConfiguration?.geminiApiKey || ""}
|
||||
style={{ width: "100%" }}
|
||||
type="password"
|
||||
onInput={handleInputChange("geminiApiKey")}
|
||||
placeholder="Enter API Key...">
|
||||
placeholder="Enter API Key..."
|
||||
className="w-full">
|
||||
<span className="font-medium">Gemini API Key</span>
|
||||
</VSCodeTextField>
|
||||
<div className="text-sm text-vscode-descriptionForeground -mt-2">
|
||||
|
|
@ -713,10 +725,13 @@ const ApiOptions = ({
|
|||
}
|
||||
type="text"
|
||||
style={{
|
||||
width: "100%",
|
||||
borderColor: (() => {
|
||||
const value = apiConfiguration?.openAiCustomModelInfo?.maxTokens
|
||||
if (!value) return "var(--vscode-input-border)"
|
||||
|
||||
if (!value) {
|
||||
return "var(--vscode-input-border)"
|
||||
}
|
||||
|
||||
return value > 0
|
||||
? "var(--vscode-charts-green)"
|
||||
: "var(--vscode-errorForeground)"
|
||||
|
|
@ -725,12 +740,14 @@ const ApiOptions = ({
|
|||
title="Maximum number of tokens the model can generate in a single response"
|
||||
onInput={handleInputChange("openAiCustomModelInfo", (e) => {
|
||||
const value = parseInt((e.target as HTMLInputElement).value)
|
||||
|
||||
return {
|
||||
...(apiConfiguration?.openAiCustomModelInfo || openAiModelInfoSaneDefaults),
|
||||
maxTokens: isNaN(value) ? undefined : value,
|
||||
}
|
||||
})}
|
||||
placeholder="e.g. 4096">
|
||||
placeholder="e.g. 4096"
|
||||
className="w-full">
|
||||
<span className="font-medium">Max Output Tokens</span>
|
||||
</VSCodeTextField>
|
||||
<div className="text-sm text-vscode-descriptionForeground">
|
||||
|
|
@ -748,10 +765,13 @@ const ApiOptions = ({
|
|||
}
|
||||
type="text"
|
||||
style={{
|
||||
width: "100%",
|
||||
borderColor: (() => {
|
||||
const value = apiConfiguration?.openAiCustomModelInfo?.contextWindow
|
||||
if (!value) return "var(--vscode-input-border)"
|
||||
|
||||
if (!value) {
|
||||
return "var(--vscode-input-border)"
|
||||
}
|
||||
|
||||
return value > 0
|
||||
? "var(--vscode-charts-green)"
|
||||
: "var(--vscode-errorForeground)"
|
||||
|
|
@ -761,6 +781,7 @@ const ApiOptions = ({
|
|||
onInput={handleInputChange("openAiCustomModelInfo", (e) => {
|
||||
const value = (e.target as HTMLInputElement).value
|
||||
const parsed = parseInt(value)
|
||||
|
||||
return {
|
||||
...(apiConfiguration?.openAiCustomModelInfo || openAiModelInfoSaneDefaults),
|
||||
contextWindow: isNaN(parsed)
|
||||
|
|
@ -768,7 +789,8 @@ const ApiOptions = ({
|
|||
: parsed,
|
||||
}
|
||||
})}
|
||||
placeholder="e.g. 128000">
|
||||
placeholder="e.g. 128000"
|
||||
className="w-full">
|
||||
<span className="font-medium">Context Window Size</span>
|
||||
</VSCodeTextField>
|
||||
<div className="text-sm text-vscode-descriptionForeground">
|
||||
|
|
@ -834,10 +856,13 @@ const ApiOptions = ({
|
|||
}
|
||||
type="text"
|
||||
style={{
|
||||
width: "100%",
|
||||
borderColor: (() => {
|
||||
const value = apiConfiguration?.openAiCustomModelInfo?.inputPrice
|
||||
if (!value && value !== 0) return "var(--vscode-input-border)"
|
||||
|
||||
if (!value && value !== 0) {
|
||||
return "var(--vscode-input-border)"
|
||||
}
|
||||
|
||||
return value >= 0
|
||||
? "var(--vscode-charts-green)"
|
||||
: "var(--vscode-errorForeground)"
|
||||
|
|
@ -846,12 +871,14 @@ const ApiOptions = ({
|
|||
onChange={handleInputChange("openAiCustomModelInfo", (e) => {
|
||||
const value = (e.target as HTMLInputElement).value
|
||||
const parsed = parseFloat(value)
|
||||
|
||||
return {
|
||||
...(apiConfiguration?.openAiCustomModelInfo ?? openAiModelInfoSaneDefaults),
|
||||
inputPrice: isNaN(parsed) ? openAiModelInfoSaneDefaults.inputPrice : parsed,
|
||||
}
|
||||
})}
|
||||
placeholder="e.g. 0.0001">
|
||||
placeholder="e.g. 0.0001"
|
||||
className="w-full">
|
||||
<div className="flex items-center gap-1">
|
||||
<span className="font-medium">Input Price</span>
|
||||
<i
|
||||
|
|
@ -872,10 +899,13 @@ const ApiOptions = ({
|
|||
}
|
||||
type="text"
|
||||
style={{
|
||||
width: "100%",
|
||||
borderColor: (() => {
|
||||
const value = apiConfiguration?.openAiCustomModelInfo?.outputPrice
|
||||
if (!value && value !== 0) return "var(--vscode-input-border)"
|
||||
|
||||
if (!value && value !== 0) {
|
||||
return "var(--vscode-input-border)"
|
||||
}
|
||||
|
||||
return value >= 0
|
||||
? "var(--vscode-charts-green)"
|
||||
: "var(--vscode-errorForeground)"
|
||||
|
|
@ -884,12 +914,14 @@ const ApiOptions = ({
|
|||
onChange={handleInputChange("openAiCustomModelInfo", (e) => {
|
||||
const value = (e.target as HTMLInputElement).value
|
||||
const parsed = parseFloat(value)
|
||||
|
||||
return {
|
||||
...(apiConfiguration?.openAiCustomModelInfo || openAiModelInfoSaneDefaults),
|
||||
outputPrice: isNaN(parsed) ? openAiModelInfoSaneDefaults.outputPrice : parsed,
|
||||
}
|
||||
})}
|
||||
placeholder="e.g. 0.0002">
|
||||
placeholder="e.g. 0.0002"
|
||||
className="w-full">
|
||||
<div className="flex items-center gap-1">
|
||||
<span className="font-medium">Output Price</span>
|
||||
<i
|
||||
|
|
@ -960,9 +992,9 @@ const ApiOptions = ({
|
|||
<div>
|
||||
<VSCodeTextField
|
||||
value={apiConfiguration?.lmStudioDraftModelId || ""}
|
||||
style={{ width: "100%" }}
|
||||
onInput={handleInputChange("lmStudioDraftModelId")}
|
||||
placeholder={"e.g. lmstudio-community/llama-3.2-1b-instruct"}>
|
||||
placeholder={"e.g. lmstudio-community/llama-3.2-1b-instruct"}
|
||||
className="w-full">
|
||||
<span className="font-medium">Draft Model ID</span>
|
||||
</VSCodeTextField>
|
||||
<div className="text-sm text-vscode-descriptionForeground">
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export * from "./popover"
|
|||
export * from "./progress"
|
||||
export * from "./separator"
|
||||
export * from "./slider"
|
||||
export * from "./select-dropdown"
|
||||
export * from "./select"
|
||||
export * from "./textarea"
|
||||
export * from "./tooltip"
|
||||
export * from "./select-dropdown"
|
||||
|
|
|
|||
144
webview-ui/src/components/ui/select.tsx
Normal file
144
webview-ui/src/components/ui/select.tsx
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
import * as React from "react"
|
||||
import * as SelectPrimitive from "@radix-ui/react-select"
|
||||
import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"
|
||||
|
||||
import { cn } from "@/lib/utils"
|
||||
|
||||
function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>) {
|
||||
return <SelectPrimitive.Root data-slot="select" {...props} />
|
||||
}
|
||||
|
||||
function SelectGroup({ ...props }: React.ComponentProps<typeof SelectPrimitive.Group>) {
|
||||
return <SelectPrimitive.Group data-slot="select-group" {...props} />
|
||||
}
|
||||
|
||||
function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>) {
|
||||
return <SelectPrimitive.Value data-slot="select-value" {...props} />
|
||||
}
|
||||
|
||||
function SelectTrigger({ className, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Trigger>) {
|
||||
return (
|
||||
<SelectPrimitive.Trigger
|
||||
data-slot="select-trigger"
|
||||
className={cn(
|
||||
"border-input data-[placeholder]:text-muted-foreground [&_svg:not([class*='text-'])]:text-muted-foreground focus-visible:border-vscode-focusBorder aria-invalid:border-destructive flex h-7 w-fit items-center justify-between gap-2 rounded-xs border bg-vscode-input-background hover:bg-transparent px-3 py-2 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none disabled:cursor-not-allowed disabled:opacity-50 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-2 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 cursor-pointer",
|
||||
className,
|
||||
)}
|
||||
{...props}>
|
||||
{children}
|
||||
<SelectPrimitive.Icon asChild>
|
||||
<ChevronDownIcon className="size-4 opacity-50" />
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectContent({
|
||||
className,
|
||||
children,
|
||||
position = "popper",
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.Content>) {
|
||||
return (
|
||||
<SelectPrimitive.Portal>
|
||||
<SelectPrimitive.Content
|
||||
data-slot="select-content"
|
||||
className={cn(
|
||||
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 relative z-50 max-h-72 min-w-[8rem] overflow-hidden rounded-xs border border-vscode-focusBorder shadow-md",
|
||||
position === "popper" &&
|
||||
"data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
||||
className,
|
||||
)}
|
||||
position={position}
|
||||
{...props}>
|
||||
<SelectScrollUpButton />
|
||||
<SelectPrimitive.Viewport
|
||||
className={cn(
|
||||
"p-1",
|
||||
position === "popper" &&
|
||||
"h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)] scroll-my-1",
|
||||
)}>
|
||||
{children}
|
||||
</SelectPrimitive.Viewport>
|
||||
<SelectScrollDownButton />
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>) {
|
||||
return (
|
||||
<SelectPrimitive.Label
|
||||
data-slot="select-label"
|
||||
className={cn("px-2 py-1.5 text-sm font-medium", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectItem({ className, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Item>) {
|
||||
return (
|
||||
<SelectPrimitive.Item
|
||||
data-slot="select-item"
|
||||
className={cn(
|
||||
"focus:bg-accent focus:text-accent-foreground [&_svg:not([class*='text-'])]:text-muted-foreground relative flex w-full cursor-default items-center gap-2 rounded-xs py-1.5 pr-8 pl-2 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex *:[span]:last:items-center *:[span]:last:gap-2 cursor-pointer",
|
||||
className,
|
||||
)}
|
||||
{...props}>
|
||||
<span className="absolute right-2 flex size-3.5 items-center justify-center">
|
||||
<SelectPrimitive.ItemIndicator>
|
||||
<CheckIcon className="size-4" />
|
||||
</SelectPrimitive.ItemIndicator>
|
||||
</span>
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectSeparator({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Separator>) {
|
||||
return (
|
||||
<SelectPrimitive.Separator
|
||||
data-slot="select-separator"
|
||||
className={cn("bg-border pointer-events-none -mx-1 my-1 h-px", className)}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectScrollUpButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>) {
|
||||
return (
|
||||
<SelectPrimitive.ScrollUpButton
|
||||
data-slot="select-scroll-up-button"
|
||||
className={cn("flex cursor-default items-center justify-center py-1", className)}
|
||||
{...props}>
|
||||
<ChevronUpIcon className="size-4" />
|
||||
</SelectPrimitive.ScrollUpButton>
|
||||
)
|
||||
}
|
||||
|
||||
function SelectScrollDownButton({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>) {
|
||||
return (
|
||||
<SelectPrimitive.ScrollDownButton
|
||||
data-slot="select-scroll-down-button"
|
||||
className={cn("flex cursor-default items-center justify-center py-1", className)}
|
||||
{...props}>
|
||||
<ChevronDownIcon className="size-4" />
|
||||
</SelectPrimitive.ScrollDownButton>
|
||||
)
|
||||
}
|
||||
|
||||
export {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectScrollDownButton,
|
||||
SelectScrollUpButton,
|
||||
SelectSeparator,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue