fix: preserve iframe plugin chat mode

This commit is contained in:
Rocky Kwok committed 2026-07-28 11:03:28 +08:00
1 parent bd8ec41914
commit 008c9ede6e
3 files changed
+50 -20

No files matched your search

@@ -45,14 +45,37 @@ test("requires an explicit chatMode=iframe opt-in for the Brainy page", () => {
assert.equal(isExplicitBrainyIframeMode("chatMode=IFRAME"), true); 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( assert.equal(
resolveStandardChatFallback( resolveStandardChatFallback(
"/page/workspace/chats_iframe/new", "/page/workspace/chats_iframe/new",
"?from=iframe&hideChrome=1", "?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( assert.equal(
resolveStandardChatFallback( resolveStandardChatFallback(
"/page/workspace/chats_iframe/thread-123", "/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", () => { test("preserves the iframe theme in the post-login redirect", () => {
assert.equal( assert.equal(
buildChatsIframeRedirectPath("?from=iframe&theme=dark-blue"), 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( assert.equal(
buildChatsIframeRedirectPath("?from=iframe"), buildChatsIframeRedirectPath("?from=iframe"),
"/page/workspace/chats_iframe/new?from=iframe", "/page/workspace/chats_iframe/new?from=iframe&chatMode=iframe",
); );
assert.equal( assert.equal(
buildChatsIframeRedirectPath( buildChatsIframeRedirectPath(
"?from=iframe&theme=dark-blue&ticket=secret&authToken=secret", "?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", "?from=iframe&theme=dark-blue&yUserId=user-1",
"/page/workspace/chats/new", "/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( assert.equal(
resolvePostLoginRedirectPath("?yUserId=user-1", "/page/workspace/chats/new"), 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", "thread-123",
"?from=iframe&theme=dark-blue&ticket=secret", "?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",
); );
}); });
@@ -23,7 +23,13 @@ export function buildChatsIframeRedirectPath(search: string): string {
target.set("from", IFRAME_LOGIN_SOURCE); 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"); target.set("chatMode", "iframe");
} }
@@ -89,21 +95,25 @@ export function resolveStandardChatFallback(
pathname: string, pathname: string,
search: string, search: string,
): string | null { ): string | null {
if ( if (!isChatsIframeWorkspacePath(pathname) || isExplicitBrainyIframeMode(search)) {
!isChatsIframeWorkspacePath(pathname) ||
isExplicitBrainyIframeMode(search)
) {
return null; 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 routePrefix = "/page/workspace/chats_iframe/";
const routeSuffix = pathname.slice(routePrefix.length); const routeSuffix = pathname.slice(routePrefix.length);
const targetPath = const targetPath =
routeSuffix && routeSuffix !== "new" routeSuffix && routeSuffix !== "new"
? `/page/workspace/chats/${routeSuffix}` ? `/page/workspace/chats/${routeSuffix}`
: "/page/workspace/chats/new"; : "/page/workspace/chats/new";
const normalizedSearch = search.startsWith("?") ? search.slice(1) : search;
const params = new URLSearchParams(normalizedSearch);
params.delete("from"); params.delete("from");
params.set("chatMode", "full"); params.set("chatMode", "full");
const targetSearch = params.toString(); const targetSearch = params.toString();
+3 -6
View File
@@ -76,7 +76,6 @@ function summarizeStoredUserInfo(): Record<string, unknown> | null {
} }
const DEFAULT_USERNAME = 'guest'; const DEFAULT_USERNAME = 'guest';
const IFRAME_LOGIN_SOURCE = 'iframe';
const IFRAME_CHAT_MODE = 'iframe'; const IFRAME_CHAT_MODE = 'iframe';
const DEFAULT_REDIRECT_PATH = '/page/workspace/chats/new'; const DEFAULT_REDIRECT_PATH = '/page/workspace/chats/new';
const FULL_CHAT_MODE = 'full'; const FULL_CHAT_MODE = 'full';
@@ -104,15 +103,13 @@ export default function LoginPage() {
searchParams.get('chatMode')?.trim().toLowerCase() ?? ''; searchParams.get('chatMode')?.trim().toLowerCase() ?? '';
const brainyIframeRequested = requestedChatMode === IFRAME_CHAT_MODE; const brainyIframeRequested = requestedChatMode === IFRAME_CHAT_MODE;
// Wujie is an application container, not the Brainy iframe protocol. It // Wujie is an application container, not the Brainy iframe protocol. It
// must therefore land on the regular full ChatPage. Legacy `from=iframe` // must therefore land on the regular full ChatPage. Plugin links with
// links now do the same; only the explicit `chatMode=iframe` protocol opt-in // `from=iframe` are normalized into the explicit iframe protocol mode.
// is allowed to open IframeChatPage.
const fullChatRequested = useMemo( const fullChatRequested = useMemo(
() => () =>
!brainyIframeRequested && !brainyIframeRequested &&
(isWujieEnv() || (isWujieEnv() ||
requestedChatMode === FULL_CHAT_MODE || requestedChatMode === FULL_CHAT_MODE),
searchParams.get('from') === IFRAME_LOGIN_SOURCE),
[brainyIframeRequested, requestedChatMode, searchParams], [brainyIframeRequested, requestedChatMode, searchParams],
); );
const isIframeLogin = useMemo( const isIframeLogin = useMemo(