From 3acc22067974707ad4ee78def8010804e3080327 Mon Sep 17 00:00:00 2001 From: Taylor Ho Date: Wed, 20 May 2026 11:45:52 -0700 Subject: [PATCH] Reshape AddChannelBotDialog with progressive disclosure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructure the dialog from a flat wall of fields into three layers: 1. Primary (always visible): Persona/team selection + runtime picker. These are the two decisions that matter most. 2. Customize (collapsed): Bot name, system prompt, respond-to allowlist. Power user controls that don't block the happy path. 3. Advanced (collapsed): Backend provider selection, provider config. Expert territory hidden by default. Uses a simple DisclosureSection component with chevron toggle. All existing functionality preserved — just layered behind progressive disclosure. Description updated to match the new vibe. --- .../channels/ui/AddChannelBotDialog.tsx | 257 +++++++++++------- 1 file changed, 155 insertions(+), 102 deletions(-) diff --git a/desktop/src/features/channels/ui/AddChannelBotDialog.tsx b/desktop/src/features/channels/ui/AddChannelBotDialog.tsx index 45c33d59ef..231e0973b3 100644 --- a/desktop/src/features/channels/ui/AddChannelBotDialog.tsx +++ b/desktop/src/features/channels/ui/AddChannelBotDialog.tsx @@ -1,4 +1,4 @@ -import { AlertTriangle, ChevronDown } from "lucide-react"; +import { AlertTriangle, ChevronDown, ChevronRight } from "lucide-react"; import * as React from "react"; import { @@ -43,6 +43,7 @@ import { getActivePersonas } from "@/features/agents/lib/catalog"; import { getUsableTeams } from "@/features/agents/lib/teamPersonas"; import { useLastRuntimeProvider } from "@/features/agents/lib/useLastRuntimeProvider"; import { CreateAgentRespondToField } from "@/features/agents/ui/RespondToField"; +import { cn } from "@/shared/lib/cn"; type AddChannelBotDialogProps = { backendProviders?: BackendProviderCandidate[]; @@ -92,6 +93,43 @@ function formatBatchFailureSummary( .join("; "); } +// ── Collapsible section ───────────────────────────────────────────────────── + +function DisclosureSection({ + children, + defaultOpen = false, + label, + testId, +}: { + children: React.ReactNode; + defaultOpen?: boolean; + label: string; + testId?: string; +}) { + const [isOpen, setIsOpen] = React.useState(defaultOpen); + + return ( +
+ + {isOpen ?
{children}
: null} +
+ ); +} + +// ── Main dialog ───────────────────────────────────────────────────────────── + export function AddChannelBotDialog({ backendProviders, backendProvidersLoading, @@ -418,9 +456,6 @@ export function AddChannelBotDialog({ } } - // Allowlist mode requires at least one entry, mirroring the harness's own - // validation. If we let it through empty, the agent crash-loops at startup - // with a config error. const respondToValid = respondTo !== "allowlist" || respondToAllowlist.length > 0; @@ -453,7 +488,7 @@ export function AddChannelBotDialog({