From c3fa10b367f81638f848a4077c0623e62cf14fa6 Mon Sep 17 00:00:00 2001 From: Matt Rubens Date: Tue, 7 Jan 2025 04:21:21 -0500 Subject: [PATCH] UI cleanup --- .../src/components/chat/ChatTextArea.tsx | 62 +++- .../components/settings/ApiConfigManager.tsx | 286 +++++++++++------- .../src/components/settings/SettingsView.tsx | 8 +- 3 files changed, 235 insertions(+), 121 deletions(-) diff --git a/webview-ui/src/components/chat/ChatTextArea.tsx b/webview-ui/src/components/chat/ChatTextArea.tsx index 2078013..8762466 100644 --- a/webview-ui/src/components/chat/ChatTextArea.tsx +++ b/webview-ui/src/components/chat/ChatTextArea.tsx @@ -44,9 +44,21 @@ const ChatTextArea = forwardRef( }, ref, ) => { - const { filePaths, apiConfiguration } = useExtensionState() + const { filePaths, apiConfiguration, currentApiConfigName, listApiConfigMeta } = useExtensionState() const [isTextAreaFocused, setIsTextAreaFocused] = useState(false) const [gitCommits, setGitCommits] = useState([]) + const [showDropdown, setShowDropdown] = useState(false) + + // Close dropdown when clicking outside + useEffect(() => { + const handleClickOutside = (event: MouseEvent) => { + if (showDropdown) { + setShowDropdown(false) + } + } + document.addEventListener("mousedown", handleClickOutside) + return () => document.removeEventListener("mousedown", handleClickOutside) + }, [showDropdown]) // Handle enhanced prompt response useEffect(() => { @@ -656,6 +668,54 @@ const ChatTextArea = forwardRef( }} /> )} + {(listApiConfigMeta || []).length > 1 && ( +
+ +
+ )}
{apiConfiguration?.apiProvider === "openrouter" && ( diff --git a/webview-ui/src/components/settings/ApiConfigManager.tsx b/webview-ui/src/components/settings/ApiConfigManager.tsx index 2464840..b6cf5dd 100644 --- a/webview-ui/src/components/settings/ApiConfigManager.tsx +++ b/webview-ui/src/components/settings/ApiConfigManager.tsx @@ -1,5 +1,5 @@ -import { VSCodeButton, VSCodeDivider, VSCodeTextField } from "@vscode/webview-ui-toolkit/react" -import { memo, useState } from "react" +import { VSCodeButton, VSCodeTextField } from "@vscode/webview-ui-toolkit/react" +import { memo, useEffect, useRef, useState } from "react" import { ApiConfigMeta } from "../../../../src/shared/ExtensionMessage" interface ApiConfigManagerProps { @@ -9,7 +9,6 @@ interface ApiConfigManagerProps { onDeleteConfig: (configName: string) => void onRenameConfig: (oldName: string, newName: string) => void onUpsertConfig: (configName: string) => void - // setDraftNewConfig: (mode: boolean) => void } const ApiConfigManager = ({ @@ -19,145 +18,206 @@ const ApiConfigManager = ({ onDeleteConfig, onRenameConfig, onUpsertConfig, - // setDraftNewConfig, }: ApiConfigManagerProps) => { - const [isNewMode, setIsNewMode] = useState(false); - const [isRenameMode, setIsRenameMode] = useState(false); - const [newConfigName, setNewConfigName] = useState(""); - const [renamedConfigName, setRenamedConfigName] = useState(""); + const [editState, setEditState] = useState<'new' | 'rename' | null>(null); + const [inputValue, setInputValue] = useState(""); + const inputRef = useRef(); - const handleNewConfig = () => { - setIsNewMode(true); - setNewConfigName(""); - // setDraftNewConfig(true) - }; - - const handleSaveNewConfig = () => { - if (newConfigName.trim()) { - onUpsertConfig(newConfigName.trim()); - setIsNewMode(false); - setNewConfigName(""); - // setDraftNewConfig(false) + // Focus input when entering edit mode + useEffect(() => { + if (editState) { + setTimeout(() => inputRef.current?.focus(), 0); } - }; + }, [editState]); - const handleCancelNewConfig = () => { - setIsNewMode(false); - setNewConfigName(""); - // setDraftNewConfig(false) + // Reset edit state when current profile changes + useEffect(() => { + setEditState(null); + setInputValue(""); + }, [currentApiConfigName]); + + const handleStartNew = () => { + setEditState('new'); + setInputValue(""); }; const handleStartRename = () => { - setIsRenameMode(true); - setRenamedConfigName(currentApiConfigName || ""); + setEditState('rename'); + setInputValue(currentApiConfigName || ""); }; - const handleSaveRename = () => { - if (renamedConfigName.trim() && currentApiConfigName) { - onRenameConfig(currentApiConfigName, renamedConfigName.trim()); - setIsRenameMode(false); - setRenamedConfigName(""); + const handleCancel = () => { + setEditState(null); + setInputValue(""); + }; + + const handleSave = () => { + const trimmedValue = inputValue.trim(); + if (!trimmedValue) return; + + if (editState === 'new') { + onUpsertConfig(trimmedValue); + } else if (editState === 'rename' && currentApiConfigName) { + onRenameConfig(currentApiConfigName, trimmedValue); } + + setEditState(null); + setInputValue(""); }; - const handleCancelRename = () => { - setIsRenameMode(false); - setRenamedConfigName(""); + const handleDelete = () => { + if (!currentApiConfigName || !listApiConfigMeta || listApiConfigMeta.length <= 1) return; + + // Let the extension handle both deletion and selection + onDeleteConfig(currentApiConfigName); }; + const isOnlyProfile = listApiConfigMeta?.length === 1; + return ( -
- -
- {isNewMode ? ( - <> +
+
+ + + {editState ? ( +
setNewConfigName(e.target.value)} - placeholder="Enter configuration name" + ref={inputRef as any} + value={inputValue} + onInput={(e: any) => setInputValue(e.target.value)} + placeholder={editState === 'new' ? "Enter profile name" : "Enter new name"} style={{ flexGrow: 1 }} + onKeyDown={(e: any) => { + if (e.key === 'Enter' && inputValue.trim()) { + handleSave(); + } else if (e.key === 'Escape') { + handleCancel(); + } + }} /> - Save + - Cancel + - - ) : isRenameMode ? ( - <> - setRenamedConfigName(e.target.value)} - placeholder="Enter new name" - style={{ flexGrow: 1 }} - /> - - Save - - - Cancel - - +
) : ( <> - - - New - - - Rename - - onDeleteConfig(currentApiConfigName!)} - > - Delete - +
+ + + + + {currentApiConfigName && ( + <> + + + + + + + + )} +
+

+ Save different API configurations to quickly switch between providers and settings +

)}
-
) } diff --git a/webview-ui/src/components/settings/SettingsView.tsx b/webview-ui/src/components/settings/SettingsView.tsx index 8940833..6a0883c 100644 --- a/webview-ui/src/components/settings/SettingsView.tsx +++ b/webview-ui/src/components/settings/SettingsView.tsx @@ -164,6 +164,7 @@ const SettingsView = ({ onDone }: SettingsViewProps) => {
+

Provider Settings

{ apiConfiguration }) }} - // setDraftNewConfig={(mode: boolean) => { - // setDraftNewMode(mode) - // }} /> -
- -
-

Provider Settings