fix(ui): mount only the active session chat iframe (#2816)
* fix(ui): mount only the active session chat iframe * repro(ui): mount-all-persisted session-chat iframes (#2815) Adds a regression-style reproduction for issue #2815: ContextPanel renders one full-application iframe for every chat tab (inactive tabs are only hidden via the Tailwind 'hidden' class, never unmounted), so a reload restores all persisted session-chat tabs from the ui-store and mounts N embedded OpenChamber apps in one browser tab. The test reads the real ContextPanel.tsx render block, drives the real useUIStore with the issue's persisted scenario (11 tabs, 8 read-only session-chat tabs), and models the render block with the real buildEmbeddedSessionChatURL helper, showing 8 live src iframes (7 hidden but loaded). * test(ui): adapt issue 2815 reproduction for active chat * fix(ui): unmount session chat when panel closes --------- Co-authored-by: ChangeHow <23733347+ChangeHow@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
co-authored by
ChangeHow
parent
b55152db6f
commit
454119ac25
@@ -45,6 +45,7 @@ import { invokeDesktopCommand } from '@/lib/desktopNative';
|
||||
import {
|
||||
EMBEDDED_RUNTIME_BOOTSTRAP_REQUEST,
|
||||
EMBEDDED_RUNTIME_BOOTSTRAP_RESPONSE,
|
||||
getActiveEmbeddedSessionChatTab,
|
||||
getOrCreateEmbeddedSessionChatURL,
|
||||
type EmbeddedSessionChatURLCacheEntry,
|
||||
type EmbeddedSessionRuntimeBootstrap,
|
||||
@@ -2483,8 +2484,13 @@ export const ContextPanel: React.FC = () => {
|
||||
|
||||
}, [activeTab, directoryKey, setSelectedFilePath]);
|
||||
|
||||
const activeChatTabID = activeTab?.mode === 'chat' ? activeTab.id : null;
|
||||
const activeChatSessionID = activeTab?.mode === 'chat' ? getSessionIDFromDedupeKey(activeTab.dedupeKey) : null;
|
||||
const chatTabs = React.useMemo(
|
||||
() => tabs.filter((tab) => tab.mode === 'chat'),
|
||||
[tabs],
|
||||
);
|
||||
const activeChatTabID = isOpen && activeTab?.mode === 'chat' ? activeTab.id : null;
|
||||
const activeChatSessionID = isOpen && activeTab?.mode === 'chat' ? getSessionIDFromDedupeKey(activeTab.dedupeKey) : null;
|
||||
const activeChatTab = getActiveEmbeddedSessionChatTab(chatTabs, activeChatTabID);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!isOpen || !directoryKey || !activeChatSessionID || typeof window === 'undefined') {
|
||||
@@ -2525,6 +2531,10 @@ export const ContextPanel: React.FC = () => {
|
||||
});
|
||||
}, [currentTheme, darkThemeId, directoryKey, lightThemeId, themeMode]);
|
||||
|
||||
const activeChatSrc = activeChatTab && activeChatSessionID
|
||||
? getEmbeddedChatSrc(activeChatTab.id, activeChatSessionID, activeChatTab.readOnly)
|
||||
: null;
|
||||
|
||||
React.useEffect(() => {
|
||||
const liveTabIDs = new Set(tabs.map((tab) => tab.id));
|
||||
for (const tabID of chatFrameSrcByTabIDRef.current.keys()) {
|
||||
@@ -2721,10 +2731,6 @@ export const ContextPanel: React.FC = () => {
|
||||
</div>
|
||||
);
|
||||
|
||||
const chatTabs = React.useMemo(
|
||||
() => tabs.filter((tab) => tab.mode === 'chat'),
|
||||
[tabs],
|
||||
);
|
||||
const browserTabs = React.useMemo(
|
||||
() => tabs.filter((tab) => tab.mode === 'browser'),
|
||||
[tabs],
|
||||
@@ -2934,41 +2940,26 @@ export const ContextPanel: React.FC = () => {
|
||||
<EditorTreeColumn visible={contextEditorTreeVisible} />
|
||||
</div>
|
||||
) : null}
|
||||
{chatTabs.map((tab) => {
|
||||
const sessionID = getSessionIDFromDedupeKey(tab.dedupeKey);
|
||||
if (!sessionID) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const src = getEmbeddedChatSrc(tab.id, sessionID, tab.readOnly);
|
||||
if (!src) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<iframe
|
||||
key={tab.id}
|
||||
ref={(node) => {
|
||||
if (!node) {
|
||||
chatFrameRefs.current.delete(tab.id);
|
||||
return;
|
||||
}
|
||||
chatFrameRefs.current.set(tab.id, node);
|
||||
}}
|
||||
src={src}
|
||||
title={t('contextPanel.iframe.sessionChatTitle', { sessionID })}
|
||||
className={cn(
|
||||
'absolute inset-0 h-full w-full border-0 bg-background',
|
||||
activeChatTabID === tab.id ? 'block' : 'hidden'
|
||||
)}
|
||||
onLoad={() => {
|
||||
postThemeSyncToEmbeddedChat();
|
||||
postChatSettingsSyncToEmbeddedChat();
|
||||
postEmbeddedVisibilityToChats();
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{activeChatTab && activeChatSessionID && activeChatSrc ? (
|
||||
<iframe
|
||||
key={activeChatTab.id}
|
||||
ref={(node) => {
|
||||
if (!node) {
|
||||
chatFrameRefs.current.delete(activeChatTab.id);
|
||||
return;
|
||||
}
|
||||
chatFrameRefs.current.set(activeChatTab.id, node);
|
||||
}}
|
||||
src={activeChatSrc}
|
||||
title={t('contextPanel.iframe.sessionChatTitle', { sessionID: activeChatSessionID })}
|
||||
className="absolute inset-0 h-full w-full border-0 bg-background"
|
||||
onLoad={() => {
|
||||
postThemeSyncToEmbeddedChat();
|
||||
postChatSettingsSyncToEmbeddedChat();
|
||||
postEmbeddedVisibilityToChats();
|
||||
}}
|
||||
/>
|
||||
) : null}
|
||||
{browserTabs.map((tab) => (
|
||||
<div
|
||||
key={tab.id}
|
||||
|
||||
Reference in New Issue
Block a user