From 2c530f67c3f8dbe400e303e6bd8edb3cf405883e Mon Sep 17 00:00:00 2001 From: viettranx Date: Thu, 19 Mar 2026 13:35:39 +0700 Subject: [PATCH] fix(ui): agent delete dialog + channel managers cleanup + combobox iOS - agents-page: ConfirmDeleteDialog with type-to-confirm, expanded warning - channel-managers-tab: simplify add form (remove manual name/username fields, auto-fill from contact search), Loader2 spinner on refresh - combobox: text-base md:text-sm to prevent iOS Safari auto-zoom --- ui/web/src/components/ui/combobox.tsx | 2 +- ui/web/src/pages/agents/agents-page.tsx | 19 ++--- .../channel-detail/channel-managers-tab.tsx | 83 +++++-------------- 3 files changed, 31 insertions(+), 73 deletions(-) diff --git a/ui/web/src/components/ui/combobox.tsx b/ui/web/src/components/ui/combobox.tsx index 82d4bc4a..0d822880 100644 --- a/ui/web/src/components/ui/combobox.tsx +++ b/ui/web/src/components/ui/combobox.tsx @@ -147,7 +147,7 @@ export function Combobox({ onFocus={() => options.length > 0 && setOpen(true)} placeholder={placeholder} className={cn( - "border-input placeholder:text-muted-foreground dark:bg-input/30 h-9 w-full rounded-md border bg-transparent px-3 py-1 pr-8 text-sm shadow-xs outline-none transition-[color,box-shadow]", + "border-input placeholder:text-muted-foreground dark:bg-input/30 h-9 w-full rounded-md border bg-transparent px-3 py-1 pr-8 text-base md:text-sm shadow-xs outline-none transition-[color,box-shadow]", "focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]", )} /> diff --git a/ui/web/src/pages/agents/agents-page.tsx b/ui/web/src/pages/agents/agents-page.tsx index 24a5e65a..b45b6542 100644 --- a/ui/web/src/pages/agents/agents-page.tsx +++ b/ui/web/src/pages/agents/agents-page.tsx @@ -10,7 +10,7 @@ import { CardSkeleton } from "@/components/shared/loading-skeleton"; import { useDeferredLoading } from "@/hooks/use-deferred-loading"; import { Button } from "@/components/ui/button"; import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip"; -import { ConfirmDialog } from "@/components/shared/confirm-dialog"; +import { ConfirmDeleteDialog } from "@/components/shared/confirm-delete-dialog"; import { Select, SelectContent, @@ -38,7 +38,7 @@ export function AgentsPage() { const [viewMode, setViewMode] = useState<"card" | "list">("card"); const [ownerFilter, setOwnerFilter] = useState(); const [createOpen, setCreateOpen] = useState(false); - const [deleteTarget, setDeleteTarget] = useState(null); + const [deleteTarget, setDeleteTarget] = useState<{ id: string; name: string } | null>(null); const [summoningAgent, setSummoningAgent] = useState<{ id: string; name: string } | null>(null); // Collect unique owner IDs for filter + contact resolution @@ -192,7 +192,7 @@ export function AgentsPage() { agent={agent} onClick={() => handleClick(agent)} onResummon={() => handleResummon(agent)} - onDelete={() => setDeleteTarget(agent.id)} + onDelete={() => setDeleteTarget({ id: agent.id, name: agent.display_name || agent.agent_key })} /> ))} @@ -205,7 +205,7 @@ export function AgentsPage() { ownerName={resolveOwnerName(agent.owner_id)} onClick={() => handleClick(agent)} onResummon={() => handleResummon(agent)} - onDelete={() => setDeleteTarget(agent.id)} + onDelete={() => setDeleteTarget({ id: agent.id, name: agent.display_name || agent.agent_key })} /> ))} @@ -238,16 +238,15 @@ export function AgentsPage() { }} /> - setDeleteTarget(null)} + onOpenChange={(open) => !open && setDeleteTarget(null)} title={t("delete.title")} - description={t("delete.description")} - confirmLabel={t("delete.confirmLabel")} - variant="destructive" + description={t("delete.deleteWarning")} + confirmValue={deleteTarget?.name ?? ""} onConfirm={async () => { if (deleteTarget) { - await deleteAgent(deleteTarget); + await deleteAgent(deleteTarget.id); setDeleteTarget(null); } }} diff --git a/ui/web/src/pages/channels/channel-detail/channel-managers-tab.tsx b/ui/web/src/pages/channels/channel-detail/channel-managers-tab.tsx index b32755d5..06069af1 100644 --- a/ui/web/src/pages/channels/channel-detail/channel-managers-tab.tsx +++ b/ui/web/src/pages/channels/channel-detail/channel-managers-tab.tsx @@ -1,6 +1,6 @@ import { useState, useEffect, useCallback } from "react"; import { useTranslation } from "react-i18next"; -import { Plus, Trash2, RefreshCw, Users, ChevronDown, ChevronRight } from "lucide-react"; +import { Plus, Trash2, Loader2, RefreshCw, Users, ChevronDown, ChevronRight } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -37,19 +37,12 @@ function InlineAddForm({ groupId, showGroupField, listContacts, onAdd }: InlineA const { t } = useTranslation("channels"); const [formGroupId, setFormGroupId] = useState(""); const [userId, setUserId] = useState(""); - const [displayName, setDisplayName] = useState(""); - const [username, setUsername] = useState(""); const [adding, setAdding] = useState(false); const [error, setError] = useState(""); const { options: contactOptions, searchContacts, getContact, clearOptions } = useContactPicker(listContacts); const handleUserIdChange = (val: string) => { setUserId(val); - const contact = getContact(val); - if (contact) { - setDisplayName(contact.display_name ?? ""); - setUsername(contact.username ?? ""); - } searchContacts(val); }; @@ -63,10 +56,12 @@ function InlineAddForm({ groupId, showGroupField, listContacts, onAdd }: InlineA setAdding(true); setError(""); try { - await onAdd(gid, uid, displayName.trim(), username.trim()); + // Auto-fill display name and username from selected contact + const contact = getContact(uid); + const displayName = contact?.display_name ?? ""; + const username = contact?.username ?? ""; + await onAdd(gid, uid, displayName, username); setUserId(""); - setDisplayName(""); - setUsername(""); clearOptions(); if (!groupId) setFormGroupId(""); } catch (err) { @@ -81,89 +76,50 @@ function InlineAddForm({ groupId, showGroupField, listContacts, onAdd }: InlineA
{t("detail.managers.addForm.title")}

{t("detail.managers.addForm.hint")}

-
-
+
+
setFormGroupId(e.target.value)} placeholder={t("detail.managers.addForm.groupIdPlaceholder")} - className="text-sm" + className="text-base md:text-sm" />
-
+
-
- - setDisplayName(e.target.value)} - placeholder={t("detail.managers.addForm.optional")} - className="text-sm" - /> -
-
- - setUsername(e.target.value)} - placeholder={t("detail.managers.addForm.usernameWithout")} - className="text-sm" - /> -
-
- {error &&

{error}

} -
+ {error &&

{error}

}
); } return (
-
+
-
-
- - setDisplayName(e.target.value)} - placeholder={t("detail.managers.addForm.optional")} - className="h-8 text-sm" - /> -
-
- - setUsername(e.target.value)} - placeholder={t("detail.managers.addForm.optional")} - className="h-8 text-sm" + className="h-8" />
{error &&

{error}

} @@ -277,7 +233,10 @@ export function ChannelManagersTab({ )}