From b2cabf012200255c07e6c3da5b5d16a5c62ef254 Mon Sep 17 00:00:00 2001 From: diegosouzapw Date: Wed, 25 Mar 2026 19:00:13 -0300 Subject: [PATCH] feat(playground): add persistent Account/Key selector Rewrote the account selector with a simpler, reliable approach: - Fetch ALL connections once at startup (not per-provider) - Filter by selectedProvider using ALIAS_TO_ID mapping - Account/Key dropdown always visible when provider selected - Shows 'Auto (N accounts)' default or individual account names - Works for both OAuth accounts and API key providers --- .../(dashboard)/dashboard/playground/page.tsx | 79 +++++++++---------- 1 file changed, 38 insertions(+), 41 deletions(-) diff --git a/src/app/(dashboard)/dashboard/playground/page.tsx b/src/app/(dashboard)/dashboard/playground/page.tsx index 1a6d245651..0c297de428 100644 --- a/src/app/(dashboard)/dashboard/playground/page.tsx +++ b/src/app/(dashboard)/dashboard/playground/page.tsx @@ -190,7 +190,7 @@ function ImageResultsInline({ data }: { data: any }) { export default function PlaygroundPage() { const [models, setModels] = useState([]); const [providers, setProviders] = useState([]); - const [connections, setConnections] = useState([]); + const [allConnections, setAllConnections] = useState([]); const [selectedProvider, setSelectedProvider] = useState(""); const [selectedModel, setSelectedModel] = useState(""); const [selectedConnection, setSelectedConnection] = useState(""); @@ -215,40 +215,16 @@ export default function PlaygroundPage() { const isImageEndpoint = selectedEndpoint === "images"; const supportsVision = isChatEndpoint && isVisionModel(selectedModel); - // Load connections for a given provider (called imperatively) - const loadConnections = useCallback((provider: string) => { - if (!provider) { - setConnections([]); - setSelectedConnection(""); - return; - } - fetch("/api/providers/client") - .then((res) => res.json()) - .then((data) => { - const allConns: ConnectionOption[] = []; - // Resolve alias → ID (e.g. cx → codex, kr → kiro) - const resolvedProvider = ALIAS_TO_ID[provider] || provider; - // API returns flat { connections: [...] } — each has a .provider field - for (const conn of data?.connections || []) { - if (conn.provider !== resolvedProvider && conn.provider !== provider) continue; - allConns.push({ - id: conn.id, - name: conn.name || conn.email || conn.id, - provider: conn.provider, - authType: conn.authType || "apiKey", - }); - } - setConnections(allConns); - setSelectedConnection(""); - }) - .catch(() => { - setConnections([]); - setSelectedConnection(""); - }); - }, []); + // Load connections for a given provider — filtered from allConnections + const providerConnections = allConnections.filter((c) => { + if (!selectedProvider) return false; + const resolvedProvider = ALIAS_TO_ID[selectedProvider] || selectedProvider; + return c.provider === resolvedProvider || c.provider === selectedProvider; + }); - // Fetch models and initialize first provider + // Fetch models and ALL connections at startup useEffect(() => { + // Fetch models fetch("/v1/models") .then((res) => res.json()) .then((data) => { @@ -266,11 +242,27 @@ export default function PlaygroundPage() { setProviders(providerOpts); if (providerOpts.length > 0) { setSelectedProvider(providerOpts[0].value); - loadConnections(providerOpts[0].value); } }) .catch(() => {}); - }, [loadConnections]); + + // Fetch ALL connections (once) + fetch("/api/providers/client") + .then((res) => res.json()) + .then((data) => { + const conns: ConnectionOption[] = []; + for (const conn of data?.connections || []) { + conns.push({ + id: conn.id, + name: conn.name || conn.email || conn.id, + provider: conn.provider, + authType: conn.authType || "apiKey", + }); + } + setAllConnections(conns); + }) + .catch(() => {}); + }, []); const filteredModels = models .filter((m) => !selectedProvider || m.id.startsWith(selectedProvider + "/")) @@ -287,7 +279,6 @@ export default function PlaygroundPage() { const handleProviderChange = (newProvider: string) => { setSelectedProvider(newProvider); setSelectedConnection(""); - loadConnections(newProvider); const providerModels = models .filter((m) => !newProvider || m.id.startsWith(newProvider + "/")) .map((m) => m.id); @@ -529,18 +520,24 @@ export default function PlaygroundPage() { )} - {/* Account/Connection — shown when provider has multiple connections */} - {!isSearchEndpoint && connections.length >= 1 && ( + {/* Account/Key — always shown when provider is selected */} + {!isSearchEndpoint && (