From ddc5964b855fe39af31e9a7cd9244c59f569eca0 Mon Sep 17 00:00:00 2001 From: viettranx Date: Thu, 2 Apr 2026 15:09:19 +0700 Subject: [PATCH] feat(web): replace user ID text input with Combobox user picker in CLI user credentials Use existing useUserPicker hook + Combobox component to search contacts + tenant_users instead of manual UUID entry. Supports allowCustom for IDs not in the search results. --- .../cli-user-credentials-dialog.tsx | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/ui/web/src/pages/cli-credentials/cli-user-credentials-dialog.tsx b/ui/web/src/pages/cli-credentials/cli-user-credentials-dialog.tsx index d777b1cf..dfffafd8 100644 --- a/ui/web/src/pages/cli-credentials/cli-user-credentials-dialog.tsx +++ b/ui/web/src/pages/cli-credentials/cli-user-credentials-dialog.tsx @@ -10,12 +10,13 @@ import { DialogFooter, } from "@/components/ui/dialog"; import { Button } from "@/components/ui/button"; -import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; +import { Combobox } from "@/components/ui/combobox"; import { KeyValueEditor } from "@/components/shared/key-value-editor"; import { toast } from "@/stores/use-toast-store"; import { useHttp } from "@/hooks/use-ws"; +import { useUserPicker } from "@/hooks/use-user-picker"; import i18next from "i18next"; import type { SecureCLIBinary } from "./hooks/use-cli-credentials"; @@ -52,10 +53,14 @@ export function CLIUserCredentialsDialog({ open, onOpenChange, binary }: CLIUser // Form state const [editEntry, setEditEntry] = useState(null); const [userId, setUserId] = useState(""); + const [userSearch, setUserSearch] = useState(""); const [env, setEnv] = useState>({}); const [saving, setSaving] = useState(false); const [deleting, setDeletingId] = useState(null); + // User picker for the form + const { options: userOptions } = useUserPicker(userSearch, undefined, "tenant_user"); + const loadList = useCallback(async () => { setLoadingList(true); try { @@ -75,6 +80,7 @@ export function CLIUserCredentialsDialog({ open, onOpenChange, binary }: CLIUser setView("list"); setEditEntry(null); setUserId(""); + setUserSearch(""); setEnv({}); loadList(); }, [open, loadList]); @@ -82,6 +88,7 @@ export function CLIUserCredentialsDialog({ open, onOpenChange, binary }: CLIUser const openAdd = () => { setEditEntry(null); setUserId(""); + setUserSearch(""); setEnv({}); setView("form"); }; @@ -89,6 +96,7 @@ export function CLIUserCredentialsDialog({ open, onOpenChange, binary }: CLIUser const openEdit = async (entry: UserCredEntry) => { setEditEntry(entry); setUserId(entry.user_id); + setUserSearch(""); setEnv({}); setView("form"); // Load existing env for edit @@ -230,13 +238,14 @@ export function CLIUserCredentialsDialog({ open, onOpenChange, binary }: CLIUser <>
- - {t("userCredentials.userId")} + setUserId(e.target.value)} + onChange={(v) => { setUserId(v); setUserSearch(v); }} + onSelect={(v) => setUserId(v)} + options={userOptions} placeholder={t("userCredentials.userIdPlaceholder")} - disabled={!!editEntry} + allowCustom className="text-base md:text-sm font-mono" />