Skip to content

Commit eeb1e45

Browse files
committed
Improve UI experience
1 parent b732005 commit eeb1e45

File tree

12 files changed

+303
-354
lines changed

12 files changed

+303
-354
lines changed

webview-ui/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
"build-storybook": "storybook build"
1616
},
1717
"dependencies": {
18+
"@radix-ui/react-alert-dialog": "^1.1.6",
1819
"@radix-ui/react-collapsible": "^1.1.3",
1920
"@radix-ui/react-dialog": "^1.1.6",
2021
"@radix-ui/react-dropdown-menu": "^2.1.5",
@@ -23,7 +24,7 @@
2324
"@radix-ui/react-progress": "^1.1.2",
2425
"@radix-ui/react-separator": "^1.1.2",
2526
"@radix-ui/react-slider": "^1.2.3",
26-
"@radix-ui/react-slot": "^1.1.1",
27+
"@radix-ui/react-slot": "^1.1.2",
2728
"@radix-ui/react-tooltip": "^1.1.8",
2829
"@tailwindcss/vite": "^4.0.0",
2930
"@vscode/webview-ui-toolkit": "^1.4.0",

webview-ui/src/components/settings/ApiConfigManager.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { ApiConfigMeta } from "../../../../src/shared/ExtensionMessage"
44
import { Dropdown } from "vscrui"
55
import type { DropdownOption } from "vscrui"
66
import { Dialog, DialogContent, DialogTitle } from "../ui/dialog"
7+
import { Button, Input } from "../ui"
78

89
interface ApiConfigManagerProps {
910
currentApiConfigName?: string
@@ -299,7 +300,7 @@ const ApiConfigManager = ({
299300
aria-labelledby="new-profile-title">
300301
<DialogContent className="p-4 max-w-sm">
301302
<DialogTitle>New Configuration Profile</DialogTitle>
302-
<VSCodeTextField
303+
<Input
303304
ref={newProfileInputRef}
304305
value={newProfileName}
305306
onInput={(e: unknown) => {
@@ -324,15 +325,12 @@ const ApiConfigManager = ({
324325
</p>
325326
)}
326327
<div className="flex justify-end gap-2 mt-4">
327-
<VSCodeButton appearance="secondary" onClick={resetCreateState}>
328+
<Button variant="secondary" onClick={resetCreateState}>
328329
Cancel
329-
</VSCodeButton>
330-
<VSCodeButton
331-
appearance="primary"
332-
disabled={!newProfileName.trim()}
333-
onClick={handleNewProfileSave}>
330+
</Button>
331+
<Button variant="default" disabled={!newProfileName.trim()} onClick={handleNewProfileSave}>
334332
Create Profile
335-
</VSCodeButton>
333+
</Button>
336334
</div>
337335
</DialogContent>
338336
</Dialog>

webview-ui/src/components/settings/ApiOptions.tsx

Lines changed: 105 additions & 181 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react"
2-
import { useEvent } from "react-use"
1+
import { memo, useCallback, useMemo, useState } from "react"
2+
import { useDebounce, useEvent } from "react-use"
33
import { Checkbox, Dropdown, Pane, type DropdownOption } from "vscrui"
44
import { VSCodeLink, VSCodeRadio, VSCodeRadioGroup, VSCodeTextField } from "@vscode/webview-ui-toolkit/react"
55
import { TemperatureControl } from "./TemperatureControl"
@@ -88,29 +88,21 @@ const ApiOptions = ({
8888
return normalizeApiConfiguration(apiConfiguration)
8989
}, [apiConfiguration])
9090

91-
const requestLocalModelsTimeoutRef = useRef<NodeJS.Timeout | null>(null)
9291
// Pull ollama/lmstudio models
93-
const requestLocalModels = useCallback(() => {
94-
if (selectedProvider === "ollama") {
95-
vscode.postMessage({ type: "requestOllamaModels", text: apiConfiguration?.ollamaBaseUrl })
96-
} else if (selectedProvider === "lmstudio") {
97-
vscode.postMessage({ type: "requestLmStudioModels", text: apiConfiguration?.lmStudioBaseUrl })
98-
} else if (selectedProvider === "vscode-lm") {
99-
vscode.postMessage({ type: "requestVsCodeLmModels" })
100-
}
101-
}, [selectedProvider, apiConfiguration?.ollamaBaseUrl, apiConfiguration?.lmStudioBaseUrl])
10292
// Debounced model updates, only executed 250ms after the user stops typing
103-
useEffect(() => {
104-
if (requestLocalModelsTimeoutRef.current) {
105-
clearTimeout(requestLocalModelsTimeoutRef.current)
106-
}
107-
requestLocalModelsTimeoutRef.current = setTimeout(requestLocalModels, 250)
108-
return () => {
109-
if (requestLocalModelsTimeoutRef.current) {
110-
clearTimeout(requestLocalModelsTimeoutRef.current)
93+
useDebounce(
94+
() => {
95+
if (selectedProvider === "ollama") {
96+
vscode.postMessage({ type: "requestOllamaModels", text: apiConfiguration?.ollamaBaseUrl })
97+
} else if (selectedProvider === "lmstudio") {
98+
vscode.postMessage({ type: "requestLmStudioModels", text: apiConfiguration?.lmStudioBaseUrl })
99+
} else if (selectedProvider === "vscode-lm") {
100+
vscode.postMessage({ type: "requestVsCodeLmModels" })
111101
}
112-
}
113-
}, [requestLocalModels])
102+
},
103+
250,
104+
[selectedProvider, apiConfiguration?.ollamaBaseUrl, apiConfiguration?.lmStudioBaseUrl],
105+
)
114106
const handleMessage = useCallback((event: MessageEvent) => {
115107
const message: ExtensionMessage = event.data
116108
if (message.type === "ollamaModels" && Array.isArray(message.ollamaModels)) {
@@ -663,8 +655,7 @@ const ApiOptions = ({
663655
]}>
664656
<div
665657
style={{
666-
padding: 15,
667-
backgroundColor: "var(--vscode-editor-background)",
658+
padding: 12,
668659
}}>
669660
<p
670661
style={{
@@ -678,24 +669,11 @@ const ApiOptions = ({
678669
</p>
679670

680671
{/* Capabilities Section */}
681-
<div
682-
style={{
683-
marginBottom: 20,
684-
padding: 12,
685-
backgroundColor: "var(--vscode-editor-inactiveSelectionBackground)",
686-
borderRadius: 4,
687-
}}>
688-
<span
689-
style={{
690-
fontWeight: 500,
691-
fontSize: "12px",
692-
display: "block",
693-
marginBottom: 12,
694-
color: "var(--vscode-editor-foreground)",
695-
}}>
672+
<div>
673+
<h3 className="font-medium text-sm text-vscode-editor-foreground">
696674
Model Capabilities
697-
</span>
698-
<div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
675+
</h3>
676+
<div className="flex flex-col gap-2">
699677
<div className="token-config-field">
700678
<VSCodeTextField
701679
value={
@@ -792,158 +770,104 @@ const ApiOptions = ({
792770
</span>
793771
</div>
794772
</div>
773+
</div>
774+
</div>
795775

796-
<div
797-
style={{
798-
backgroundColor: "var(--vscode-editor-background)",
799-
padding: "12px",
800-
borderRadius: "4px",
801-
marginTop: "8px",
802-
border: "1px solid var(--vscode-input-border)",
803-
transition: "background-color 0.2s ease",
804-
}}>
805-
<span
776+
<div>
777+
<h3 className="font-medium text-sm text-vscode-editor-foreground">Model Features</h3>
778+
<div className="flex flex-col gap-2">
779+
<div className="feature-toggle">
780+
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
781+
<Checkbox
782+
checked={
783+
apiConfiguration?.openAiCustomModelInfo?.supportsImages ??
784+
openAiModelInfoSaneDefaults.supportsImages
785+
}
786+
onChange={handleInputChange("openAiCustomModelInfo", (checked) => {
787+
return {
788+
...(apiConfiguration?.openAiCustomModelInfo ||
789+
openAiModelInfoSaneDefaults),
790+
supportsImages: checked,
791+
}
792+
})}>
793+
<span style={{ fontWeight: 500 }}>Image Support</span>
794+
</Checkbox>
795+
<i
796+
className="codicon codicon-info"
797+
title="Enable if the model can process and understand images in the input. Required for image-based assistance and visual code understanding."
798+
style={{
799+
fontSize: "12px",
800+
color: "var(--vscode-descriptionForeground)",
801+
cursor: "help",
802+
}}
803+
/>
804+
</div>
805+
<p
806806
style={{
807807
fontSize: "11px",
808-
fontWeight: 500,
809-
color: "var(--vscode-editor-foreground)",
810-
display: "block",
811-
marginBottom: "10px",
808+
color: "var(--vscode-descriptionForeground)",
809+
marginLeft: "24px",
810+
marginTop: "4px",
811+
lineHeight: "1.4",
812+
marginBottom: 0,
812813
}}>
813-
Model Features
814-
</span>
815-
816-
<div style={{ display: "flex", flexDirection: "column", gap: "12px" }}>
817-
<div className="feature-toggle">
818-
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
819-
<Checkbox
820-
checked={
821-
apiConfiguration?.openAiCustomModelInfo?.supportsImages ??
822-
openAiModelInfoSaneDefaults.supportsImages
823-
}
824-
onChange={handleInputChange(
825-
"openAiCustomModelInfo",
826-
(checked) => {
827-
return {
828-
...(apiConfiguration?.openAiCustomModelInfo ||
829-
openAiModelInfoSaneDefaults),
830-
supportsImages: checked,
831-
}
832-
},
833-
)}>
834-
<span style={{ fontWeight: 500 }}>Image Support</span>
835-
</Checkbox>
836-
<i
837-
className="codicon codicon-info"
838-
title="Enable if the model can process and understand images in the input. Required for image-based assistance and visual code understanding."
839-
style={{
840-
fontSize: "12px",
841-
color: "var(--vscode-descriptionForeground)",
842-
cursor: "help",
843-
}}
844-
/>
845-
</div>
846-
<p
847-
style={{
848-
fontSize: "11px",
849-
color: "var(--vscode-descriptionForeground)",
850-
marginLeft: "24px",
851-
marginTop: "4px",
852-
lineHeight: "1.4",
853-
}}>
854-
Allows the model to analyze and understand images, essential for
855-
visual code assistance
856-
</p>
857-
</div>
814+
Allows the model to analyze and understand images, essential for visual code
815+
assistance
816+
</p>
817+
</div>
858818

859-
<div
860-
className="feature-toggle"
819+
<div
820+
className="feature-toggle"
821+
style={{
822+
borderTop: "1px solid var(--vscode-input-border)",
823+
}}>
824+
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
825+
<Checkbox
826+
checked={
827+
apiConfiguration?.openAiCustomModelInfo?.supportsComputerUse ??
828+
false
829+
}
830+
onChange={handleInputChange("openAiCustomModelInfo", (checked) => {
831+
return {
832+
...(apiConfiguration?.openAiCustomModelInfo ||
833+
openAiModelInfoSaneDefaults),
834+
supportsComputerUse: checked,
835+
}
836+
})}>
837+
<span style={{ fontWeight: 500 }}>Computer Use</span>
838+
</Checkbox>
839+
<i
840+
className="codicon codicon-info"
841+
title="Enable if the model can interact with your computer through commands and file operations. Required for automated tasks and file modifications."
861842
style={{
862-
borderTop: "1px solid var(--vscode-input-border)",
863-
paddingTop: "12px",
864-
}}>
865-
<div style={{ display: "flex", alignItems: "center", gap: "8px" }}>
866-
<Checkbox
867-
checked={
868-
apiConfiguration?.openAiCustomModelInfo
869-
?.supportsComputerUse ?? false
870-
}
871-
onChange={handleInputChange(
872-
"openAiCustomModelInfo",
873-
(checked) => {
874-
return {
875-
...(apiConfiguration?.openAiCustomModelInfo ||
876-
openAiModelInfoSaneDefaults),
877-
supportsComputerUse: checked,
878-
}
879-
},
880-
)}>
881-
<span style={{ fontWeight: 500 }}>Computer Use</span>
882-
</Checkbox>
883-
<i
884-
className="codicon codicon-info"
885-
title="Enable if the model can interact with your computer through commands and file operations. Required for automated tasks and file modifications."
886-
style={{
887-
fontSize: "12px",
888-
color: "var(--vscode-descriptionForeground)",
889-
cursor: "help",
890-
}}
891-
/>
892-
</div>
893-
<p
894-
style={{
895-
fontSize: "11px",
896-
color: "var(--vscode-descriptionForeground)",
897-
marginLeft: "24px",
898-
marginTop: "4px",
899-
lineHeight: "1.4",
900-
}}>
901-
This model feature is for computer use like sonnet 3.5 support
902-
</p>
903-
</div>
843+
fontSize: "12px",
844+
color: "var(--vscode-descriptionForeground)",
845+
cursor: "help",
846+
}}
847+
/>
904848
</div>
849+
<p
850+
style={{
851+
fontSize: "11px",
852+
color: "var(--vscode-descriptionForeground)",
853+
marginLeft: "24px",
854+
marginTop: "4px",
855+
lineHeight: "1.4",
856+
marginBottom: 0,
857+
}}>
858+
This model feature is for computer use like sonnet 3.5 support
859+
</p>
905860
</div>
906861
</div>
907862
</div>
908863

909864
{/* Pricing Section */}
910-
<div
911-
style={{
912-
backgroundColor: "var(--vscode-editor-inactiveSelectionBackground)",
913-
padding: "12px",
914-
borderRadius: "4px",
915-
marginTop: "15px",
916-
}}>
917-
<div style={{ marginBottom: "12px" }}>
918-
<span
919-
style={{
920-
fontWeight: 500,
921-
fontSize: "12px",
922-
color: "var(--vscode-editor-foreground)",
923-
display: "block",
924-
marginBottom: "4px",
925-
}}>
926-
Model Pricing
927-
</span>
928-
<span
929-
style={{
930-
fontSize: "11px",
931-
color: "var(--vscode-descriptionForeground)",
932-
display: "block",
933-
}}>
934-
Configure token-based pricing in USD per million tokens
935-
</span>
936-
</div>
937-
938-
<div
939-
style={{
940-
display: "grid",
941-
gridTemplateColumns: "1fr 1fr",
942-
gap: "12px",
943-
backgroundColor: "var(--vscode-editor-background)",
944-
padding: "12px",
945-
borderRadius: "4px",
946-
}}>
865+
<div>
866+
<h3 className="font-medium text-sm text-vscode-editor-foreground mb-0">
867+
Model Pricing
868+
</h3>
869+
<div className="text-xs">Configure token-based pricing in USD per million tokens</div>
870+
<div className="flex flex-row gap-2 mt-1.5">
947871
<div className="price-input">
948872
<VSCodeTextField
949873
value={

0 commit comments

Comments
 (0)