From 19145d518a41048e94eb5d94e177ec632669fdf2 Mon Sep 17 00:00:00 2001 From: Dotta Date: Sun, 27 Sep 2026 21:07:47 -0500 Subject: [PATCH] fix(chat): preserve X setup inputs on save and exit Co-Authored-By: Paperclip --- tests/e2e/x-chat-setup.spec.ts | 21 ++++++++++++++++++++- ui/src/pages/apps/chat/XChatSetup.tsx | 23 ++++++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/tests/e2e/x-chat-setup.spec.ts b/tests/e2e/x-chat-setup.spec.ts index 9039d470617..f475aa90316 100644 --- a/tests/e2e/x-chat-setup.spec.ts +++ b/tests/e2e/x-chat-setup.spec.ts @@ -111,7 +111,12 @@ test("X setup resumes drafts, separates bot and human authorization, and permits .getByRole("button", { name: "Select agent…", exact: true }) .click(); await page.getByRole("button", { name: "Select Maya", exact: true }).click(); - await page.getByRole("button", { name: "Continue", exact: true }).click(); + await page.getByRole("button", { name: "Save & exit", exact: true }).click(); + await expect(page).toHaveURL(new RegExp(`/${seed.prefix}/apps$`)); + expect(created).toBe(true); + await page.goto( + `/${seed.prefix}/apps/chat/connect?provider=x&resume=endpoint-x`, + ); await expect( page.getByRole("heading", { name: "Configure X app", exact: true }), ).toBeVisible(); @@ -132,6 +137,20 @@ test("X setup resumes drafts, separates bot and human authorization, and permits await page .getByLabel("OAuth 2.0 Client Secret", { exact: true }) .fill("fixture-secret"); + await page.getByRole("button", { name: "Save & exit", exact: true }).click(); + await expect(page).toHaveURL(new RegExp(`/${seed.prefix}/apps$`)); + expect(endpoint.setup.x.clientConfigured).toBe(true); + await page.goto( + `/${seed.prefix}/apps/chat/connect?provider=x&resume=endpoint-x`, + ); + await expect( + page.getByText( + "X app credentials are saved. Leave these fields blank to keep them.", + ), + ).toBeVisible(); + await expect( + page.getByLabel("OAuth 2.0 Client Secret", { exact: true }), + ).toHaveValue(""); await page.getByRole("button", { name: "Save app & continue" }).click(); await page .getByRole("button", { name: "Authorize bot account on X" }) diff --git a/ui/src/pages/apps/chat/XChatSetup.tsx b/ui/src/pages/apps/chat/XChatSetup.tsx index e03d3cd1f6e..80412610554 100644 --- a/ui/src/pages/apps/chat/XChatSetup.tsx +++ b/ui/src/pages/apps/chat/XChatSetup.tsx @@ -109,7 +109,22 @@ export function XChatSetup() { else await advance(5); } async function exit() { - if (endpoint) await xChatApi.progress(endpoint.id, Math.max(1, step)); + const draft = + endpoint ?? + (selectedCompanyId && agentId + ? await chatEndpointsApi.create(selectedCompanyId, { + provider: "x", + assignedAgentId: agentId, + }) + : null); + if (draft) { + setEndpoint(draft); + if (step === 1 && (client.clientId || client.clientSecret)) { + await xChatApi.authorize(draft.id, "bot", client); + setClient({ clientId: "", clientSecret: "" }); + } + await xChatApi.progress(draft.id, Math.max(1, step)); + } navigate("/apps"); } async function copy(value: string, label: string) { @@ -255,6 +270,12 @@ export function XChatSetup() { {copied === "callback" ? "Copied" : "Copy callback URL"} + {endpoint?.setup?.x?.clientConfigured && ( +

+ X app credentials are saved. Leave these fields blank to keep + them. +

+ )}