From 60f9221d69784dda91c89c3bffb946d075eaeff4 Mon Sep 17 00:00:00 2001 From: Sam Hoang Van Date: Sat, 5 Apr 2025 11:56:54 +0700 Subject: [PATCH] feat(settings): add searchable dropdown to API config profiles setting page (#2221) - Replace Select with Command+Popover components in ApiConfigManager - Add search functionality to filter configuration profiles - Add clear search button and selected item indicator - Add internationalization support for all languages - Match UX pattern from ModelPicker component for consistency --- .../components/settings/ApiConfigManager.tsx | 124 +++++++++++++++--- .../__tests__/ApiConfigManager.test.tsx | 46 ++++++- webview-ui/src/i18n/locales/ca/settings.json | 2 + webview-ui/src/i18n/locales/de/settings.json | 2 + webview-ui/src/i18n/locales/en/settings.json | 2 + webview-ui/src/i18n/locales/es/settings.json | 2 + webview-ui/src/i18n/locales/fr/settings.json | 2 + webview-ui/src/i18n/locales/hi/settings.json | 2 + webview-ui/src/i18n/locales/it/settings.json | 2 + webview-ui/src/i18n/locales/ja/settings.json | 2 + webview-ui/src/i18n/locales/ko/settings.json | 2 + webview-ui/src/i18n/locales/pl/settings.json | 2 + .../src/i18n/locales/pt-BR/settings.json | 2 + webview-ui/src/i18n/locales/tr/settings.json | 2 + webview-ui/src/i18n/locales/vi/settings.json | 2 + .../src/i18n/locales/zh-CN/settings.json | 2 + .../src/i18n/locales/zh-TW/settings.json | 2 + 17 files changed, 181 insertions(+), 19 deletions(-) diff --git a/webview-ui/src/components/settings/ApiConfigManager.tsx b/webview-ui/src/components/settings/ApiConfigManager.tsx index e57bfd8175..6db79f761a 100644 --- a/webview-ui/src/components/settings/ApiConfigManager.tsx +++ b/webview-ui/src/components/settings/ApiConfigManager.tsx @@ -1,20 +1,26 @@ import { memo, useEffect, useRef, useState } from "react" import { VSCodeTextField } from "@vscode/webview-ui-toolkit/react" +import { ChevronsUpDown, Check, X } from "lucide-react" import { ApiConfigMeta } from "../../../../src/shared/ExtensionMessage" import { useAppTranslation } from "@/i18n/TranslationContext" +import { cn } from "@/lib/utils" import { Button, Input, Dialog, DialogContent, DialogTitle, - Select, - SelectTrigger, - SelectValue, - SelectContent, - SelectItem, + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, + Popover, + PopoverContent, + PopoverTrigger, } from "@/components/ui" interface ApiConfigManagerProps { @@ -41,8 +47,11 @@ const ApiConfigManager = ({ const [inputValue, setInputValue] = useState("") const [newProfileName, setNewProfileName] = useState("") const [error, setError] = useState(null) + const [open, setOpen] = useState(false) + const [searchValue, setSearchValue] = useState("") const inputRef = useRef(null) const newProfileInputRef = useRef(null) + const searchInputRef = useRef(null) const validateName = (name: string, isNewProfile: boolean): string | null => { const trimmed = name.trim() @@ -95,8 +104,31 @@ const ApiConfigManager = ({ useEffect(() => { resetCreateState() resetRenameState() + // Reset search value when current profile changes + setTimeout(() => setSearchValue(""), 100) }, [currentApiConfigName]) + const onOpenChange = (open: boolean) => { + setOpen(open) + + // Reset search when closing the popover + if (!open) { + setTimeout(() => setSearchValue(""), 100) + } + } + + const onClearSearch = () => { + setSearchValue("") + searchInputRef.current?.focus() + } + + const handleSelectConfig = (configName: string) => { + if (!configName) return + + setOpen(false) + onSelectConfig(configName) + } + const handleAdd = () => { resetCreateState() setIsCreating(true) @@ -206,18 +238,76 @@ const ApiConfigManager = ({ ) : ( <>
- + + + + + + +
+ + {searchValue.length > 0 && ( +
+ +
+ )} +
+ + + {searchValue && ( +
+ {t("settings:providers.noMatchFound")} +
+ )} +
+ + {listApiConfigMeta + .filter((config) => + searchValue + ? config.name.toLowerCase().includes(searchValue.toLowerCase()) + : true, + ) + .map((config) => ( + + {config.name} + + + ))} + +
+
+
+