fix(chat): enable in-place subtask navigation in embedded session-chat iframe (#2138)
This commit is contained in:
@@ -5,6 +5,7 @@ import { parseRoute, updateBrowserURL, hasRouteParams } from '@/lib/router';
|
||||
import type { RouteState, AppRouteState } from '@/lib/router';
|
||||
import type { MainTab } from '@/stores/useUIStore';
|
||||
import { resolveSettingsSlug } from '@/lib/settings/metadata';
|
||||
import { isEmbeddedSessionChat } from '@/components/layout/contextPanelEmbeddedChat';
|
||||
|
||||
/**
|
||||
* Check if running in VS Code webview context.
|
||||
@@ -29,9 +30,18 @@ function isVSCodeContext(): boolean {
|
||||
* - Web: Full bidirectional sync
|
||||
* - Desktop: Full bidirectional sync
|
||||
* - VS Code: State-only (no URL updates, reads initial params)
|
||||
* - Embedded session-chat iframe (`?ocPanel=session-chat`): No URL updates.
|
||||
* The iframe's session identity is fixed at mount (the parent builds the
|
||||
* src with `sessionId`); in-place subtask navigation must NOT rewrite the
|
||||
* URL, otherwise `ocPanel` (and `directory`/`readOnly`) get stripped and
|
||||
* `isEmbeddedSessionChat()` starts returning false, breaking subsequent
|
||||
* "Open subtask" clicks.
|
||||
*/
|
||||
export function useRouter(): void {
|
||||
const isVSCode = React.useMemo(() => isVSCodeContext(), []);
|
||||
// Captured once at mount: the iframe's embedded-ness never changes during
|
||||
// its lifetime (a parent src swap is a full reload).
|
||||
const isEmbeddedChat = React.useMemo(() => isEmbeddedSessionChat(), []);
|
||||
|
||||
// Track initialization to avoid duplicate applies
|
||||
const initializedRef = React.useRef(false);
|
||||
@@ -115,14 +125,14 @@ export function useRouter(): void {
|
||||
*/
|
||||
const syncURLFromState = React.useCallback(
|
||||
(options: { replace?: boolean } = {}) => {
|
||||
if (isVSCode || isApplyingRouteRef.current) {
|
||||
if (isVSCode || isEmbeddedChat || isApplyingRouteRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const state = getCurrentAppState();
|
||||
updateBrowserURL(state, options);
|
||||
},
|
||||
[isVSCode, getCurrentAppState]
|
||||
[isVSCode, isEmbeddedChat, getCurrentAppState]
|
||||
);
|
||||
|
||||
// Initialize: parse URL and apply route on mount
|
||||
@@ -148,7 +158,7 @@ export function useRouter(): void {
|
||||
// Use the parsed route values instead of an immediate store snapshot so
|
||||
// deep links do not briefly normalize `?session=...` back to `/` while
|
||||
// the session's directory/message bootstrap is still catching up.
|
||||
if (!isVSCode) {
|
||||
if (!isVSCode && !isEmbeddedChat) {
|
||||
updateBrowserURL({
|
||||
...getCurrentAppState(),
|
||||
sessionId: route.sessionId ?? useSessionUIStore.getState().currentSessionId,
|
||||
@@ -160,11 +170,11 @@ export function useRouter(): void {
|
||||
};
|
||||
|
||||
void initializeRoute();
|
||||
}, [applyRoute, getCurrentAppState, isVSCode]);
|
||||
}, [applyRoute, getCurrentAppState, isVSCode, isEmbeddedChat]);
|
||||
|
||||
// Subscribe to session changes
|
||||
React.useEffect(() => {
|
||||
if (isVSCode) {
|
||||
if (isVSCode || isEmbeddedChat) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -183,11 +193,11 @@ export function useRouter(): void {
|
||||
});
|
||||
|
||||
return unsubscribe;
|
||||
}, [isVSCode, syncURLFromState]);
|
||||
}, [isVSCode, isEmbeddedChat, syncURLFromState]);
|
||||
|
||||
// Subscribe to UI store changes (tab, settings)
|
||||
React.useEffect(() => {
|
||||
if (isVSCode) {
|
||||
if (isVSCode || isEmbeddedChat) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -220,11 +230,11 @@ export function useRouter(): void {
|
||||
});
|
||||
|
||||
return unsubscribe;
|
||||
}, [isVSCode, syncURLFromState]);
|
||||
}, [isVSCode, isEmbeddedChat, syncURLFromState]);
|
||||
|
||||
// Listen for browser back/forward navigation
|
||||
React.useEffect(() => {
|
||||
if (typeof window === 'undefined' || isVSCode) {
|
||||
if (typeof window === 'undefined' || isVSCode || isEmbeddedChat) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -254,5 +264,5 @@ export function useRouter(): void {
|
||||
return () => {
|
||||
window.removeEventListener('popstate', handlePopState);
|
||||
};
|
||||
}, [applyRoute, isVSCode, setActiveMainTab, setSettingsDialogOpen]);
|
||||
}, [applyRoute, isVSCode, isEmbeddedChat, setActiveMainTab, setSettingsDialogOpen]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user