diff --git a/frontend-web/src/core/page-layout/chats-iframe-route.test.mjs b/frontend-web/src/core/page-layout/chats-iframe-route.test.mjs index 4d237adb..246c2d70 100644 --- a/frontend-web/src/core/page-layout/chats-iframe-route.test.mjs +++ b/frontend-web/src/core/page-layout/chats-iframe-route.test.mjs @@ -45,14 +45,37 @@ test("requires an explicit chatMode=iframe opt-in for the Brainy page", () => { assert.equal(isExplicitBrainyIframeMode("chatMode=IFRAME"), true); }); -test("redirects accidental chats_iframe routes to standard full chat", () => { +test("upgrades legacy iframe-source routes to the iframe protocol", () => { assert.equal( resolveStandardChatFallback( "/page/workspace/chats_iframe/new", "?from=iframe&hideChrome=1", ), - "/page/workspace/chats/new?hideChrome=1&chatMode=full", + "/page/workspace/chats_iframe/new?from=iframe&hideChrome=1&chatMode=iframe", ); +}); + +test("honors an explicit chat mode over the legacy iframe source", () => { + assert.equal( + resolveStandardChatFallback( + "/page/workspace/chats_iframe/new", + "?from=iframe&chatMode=full", + ), + "/page/workspace/chats/new?chatMode=full", + ); +}); + +test("treats a blank chat mode as absent for the legacy iframe source", () => { + assert.equal( + resolveStandardChatFallback( + "/page/workspace/chats_iframe/new", + "?from=iframe&chatMode=%20%20", + ), + "/page/workspace/chats_iframe/new?from=iframe&chatMode=iframe", + ); +}); + +test("redirects chats_iframe routes without the iframe source to standard full chat", () => { assert.equal( resolveStandardChatFallback( "/page/workspace/chats_iframe/thread-123", @@ -121,17 +144,17 @@ test("forces the iframe theme on the login route without changing normal login", test("preserves the iframe theme in the post-login redirect", () => { assert.equal( buildChatsIframeRedirectPath("?from=iframe&theme=dark-blue"), - "/page/workspace/chats_iframe/new?from=iframe&theme=dark-blue", + "/page/workspace/chats_iframe/new?from=iframe&chatMode=iframe&theme=dark-blue", ); assert.equal( buildChatsIframeRedirectPath("?from=iframe"), - "/page/workspace/chats_iframe/new?from=iframe", + "/page/workspace/chats_iframe/new?from=iframe&chatMode=iframe", ); assert.equal( buildChatsIframeRedirectPath( "?from=iframe&theme=dark-blue&ticket=secret&authToken=secret", ), - "/page/workspace/chats_iframe/new?from=iframe&theme=dark-blue", + "/page/workspace/chats_iframe/new?from=iframe&chatMode=iframe&theme=dark-blue", ); }); @@ -141,7 +164,7 @@ test("keeps the iframe redirect ahead of login-method fallbacks", () => { "?from=iframe&theme=dark-blue&yUserId=user-1", "/page/workspace/chats/new", ), - "/page/workspace/chats_iframe/new?from=iframe&theme=dark-blue", + "/page/workspace/chats_iframe/new?from=iframe&chatMode=iframe&theme=dark-blue", ); assert.equal( resolvePostLoginRedirectPath("?yUserId=user-1", "/page/workspace/chats/new"), @@ -156,7 +179,7 @@ test("preserves iframe theme when a new chat becomes a thread", () => { "thread-123", "?from=iframe&theme=dark-blue&ticket=secret", ), - "/page/workspace/chats_iframe/thread-123?from=iframe&theme=dark-blue", + "/page/workspace/chats_iframe/thread-123?from=iframe&chatMode=iframe&theme=dark-blue", ); }); diff --git a/frontend-web/src/core/page-layout/chats-iframe-route.ts b/frontend-web/src/core/page-layout/chats-iframe-route.ts index 2868b00d..aadfb64d 100644 --- a/frontend-web/src/core/page-layout/chats-iframe-route.ts +++ b/frontend-web/src/core/page-layout/chats-iframe-route.ts @@ -23,7 +23,13 @@ export function buildChatsIframeRedirectPath(search: string): string { target.set("from", IFRAME_LOGIN_SOURCE); } - if (isExplicitBrainyIframeMode(search)) { + const requestedMode = source.get("chatMode")?.trim(); + if (requestedMode) { + target.set("chatMode", requestedMode); + } else if (isChatsIframeLogin(search)) { + // Plugin links historically identify this protocol with `from=iframe`. + // Normalize that legacy marker into the explicit mode before handing the + // URL to the workspace route, so it does not fall back to the full chat. target.set("chatMode", "iframe"); } @@ -89,21 +95,25 @@ export function resolveStandardChatFallback( pathname: string, search: string, ): string | null { - if ( - !isChatsIframeWorkspacePath(pathname) || - isExplicitBrainyIframeMode(search) - ) { + if (!isChatsIframeWorkspacePath(pathname) || isExplicitBrainyIframeMode(search)) { return null; } + const normalizedSearch = search.startsWith("?") ? search.slice(1) : search; + const params = new URLSearchParams(normalizedSearch); + const requestedMode = params.get("chatMode")?.trim(); + if (isChatsIframeLogin(search) && !requestedMode) { + params.set("chatMode", "iframe"); + const targetSearch = params.toString(); + return targetSearch ? `${pathname}?${targetSearch}` : pathname; + } + const routePrefix = "/page/workspace/chats_iframe/"; const routeSuffix = pathname.slice(routePrefix.length); const targetPath = routeSuffix && routeSuffix !== "new" ? `/page/workspace/chats/${routeSuffix}` : "/page/workspace/chats/new"; - const normalizedSearch = search.startsWith("?") ? search.slice(1) : search; - const params = new URLSearchParams(normalizedSearch); params.delete("from"); params.set("chatMode", "full"); const targetSearch = params.toString(); diff --git a/frontend-web/src/pages/IframeChatPage.tsx b/frontend-web/src/pages/IframeChatPage.tsx index ca66cb18..4bf84389 100644 --- a/frontend-web/src/pages/IframeChatPage.tsx +++ b/frontend-web/src/pages/IframeChatPage.tsx @@ -1,7 +1,6 @@ "use client"; import { - ArrowRightIcon, BookMarkedIcon, BotIcon, BrainCircuitIcon, @@ -709,7 +708,7 @@ export default function IframeChatPage() {