From 97639c06ab0c8152b9cb5b011b0ba918e5bd46be Mon Sep 17 00:00:00 2001 From: Ilya Bersenev Date: Fri, 10 Apr 2026 14:03:49 +0300 Subject: [PATCH] feat: add setting to keep AI groups expanded after context navigation Navigating from the Visible Context panel temporarily expands the target AI group, but it collapses again after the 2s highlight fades. A new "Keep expanded after context navigation" toggle in Appearance settings persists the expansion via expandAIGroupForTab so the group stays open until manually collapsed. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/main/ipc/configValidation.ts | 1 + src/main/services/infrastructure/ConfigManager.ts | 2 ++ src/renderer/components/chat/ChatHistory.tsx | 10 ++++++++-- src/renderer/components/settings/SettingsView.tsx | 1 + .../components/settings/hooks/useSettingsConfig.ts | 2 ++ .../components/settings/hooks/useSettingsHandlers.ts | 1 + .../components/settings/sections/GeneralSection.tsx | 12 ++++++++++++ src/shared/types/notifications.ts | 2 ++ test/mocks/electronAPI.ts | 1 + 9 files changed, 30 insertions(+), 2 deletions(-) diff --git a/src/main/ipc/configValidation.ts b/src/main/ipc/configValidation.ts index aa71e865..78001f24 100644 --- a/src/main/ipc/configValidation.ts +++ b/src/main/ipc/configValidation.ts @@ -302,6 +302,7 @@ function validateDisplaySection(data: unknown): ValidationSuccess<'display'> | V 'showTimestamps', 'compactMode', 'syntaxHighlighting', + 'keepContextNavExpanded', ]; const result: Partial = {}; diff --git a/src/main/services/infrastructure/ConfigManager.ts b/src/main/services/infrastructure/ConfigManager.ts index 91e57254..3bb36bab 100644 --- a/src/main/services/infrastructure/ConfigManager.ts +++ b/src/main/services/infrastructure/ConfigManager.ts @@ -189,6 +189,7 @@ export interface DisplayConfig { showTimestamps: boolean; compactMode: boolean; syntaxHighlighting: boolean; + keepContextNavExpanded: boolean; } export interface SessionsConfig { @@ -257,6 +258,7 @@ const DEFAULT_CONFIG: AppConfig = { showTimestamps: true, compactMode: false, syntaxHighlighting: true, + keepContextNavExpanded: false, }, sessions: { pinnedSessions: {}, diff --git a/src/renderer/components/chat/ChatHistory.tsx b/src/renderer/components/chat/ChatHistory.tsx index 33159f14..a212eb76 100644 --- a/src/renderer/components/chat/ChatHistory.tsx +++ b/src/renderer/components/chat/ChatHistory.tsx @@ -415,6 +415,9 @@ export const ChatHistory = ({ tabId }: ChatHistoryProps): JSX.Element => { if (!element) return; element.scrollIntoView({ behavior: 'smooth', block: 'center' }); + if (useStore.getState().appConfig?.display?.keepContextNavExpanded) { + expandAIGroup(groupId); + } setHighlightedGroupId(groupId); setIsNavigationHighlight(true); if (navigationHighlightTimerRef.current) { @@ -428,7 +431,7 @@ export const ChatHistory = ({ tabId }: ChatHistoryProps): JSX.Element => { }; void run(); }, - [conversation, ensureGroupVisible, setHighlightedGroupId] + [conversation, ensureGroupVisible, setHighlightedGroupId, expandAIGroup] ); // Handler to navigate to a user message group (preceding the AI group at turnIndex) @@ -481,6 +484,9 @@ export const ChatHistory = ({ tabId }: ChatHistoryProps): JSX.Element => { await ensureGroupVisible(groupId); // Set group + tool highlight immediately + if (useStore.getState().appConfig?.display?.keepContextNavExpanded) { + expandAIGroup(groupId); + } setHighlightedGroupId(groupId); setIsNavigationHighlight(true); setContextNavToolUseId(toolUseId); @@ -513,7 +519,7 @@ export const ChatHistory = ({ tabId }: ChatHistoryProps): JSX.Element => { }; void run(); }, - [conversation, ensureGroupVisible, setHighlightedGroupId] + [conversation, ensureGroupVisible, setHighlightedGroupId, expandAIGroup] ); // Scroll to current search result when it changes diff --git a/src/renderer/components/settings/SettingsView.tsx b/src/renderer/components/settings/SettingsView.tsx index ee4f0400..41626a30 100644 --- a/src/renderer/components/settings/SettingsView.tsx +++ b/src/renderer/components/settings/SettingsView.tsx @@ -127,6 +127,7 @@ export const SettingsView = (): React.JSX.Element | null => { safeConfig={safeConfig} saving={saving} onGeneralToggle={handlers.handleGeneralToggle} + onDisplayToggle={handlers.handleDisplayToggle} onThemeChange={handlers.handleThemeChange} /> )} diff --git a/src/renderer/components/settings/hooks/useSettingsConfig.ts b/src/renderer/components/settings/hooks/useSettingsConfig.ts index 192346ae..afeae139 100644 --- a/src/renderer/components/settings/hooks/useSettingsConfig.ts +++ b/src/renderer/components/settings/hooks/useSettingsConfig.ts @@ -47,6 +47,7 @@ export interface SafeConfig { showTimestamps: boolean; compactMode: boolean; syntaxHighlighting: boolean; + keepContextNavExpanded: boolean; }; } @@ -173,6 +174,7 @@ export function useSettingsConfig(): UseSettingsConfigReturn { showTimestamps: displayConfig?.display?.showTimestamps ?? true, compactMode: displayConfig?.display?.compactMode ?? false, syntaxHighlighting: displayConfig?.display?.syntaxHighlighting ?? true, + keepContextNavExpanded: displayConfig?.display?.keepContextNavExpanded ?? false, }, }), [displayConfig] diff --git a/src/renderer/components/settings/hooks/useSettingsHandlers.ts b/src/renderer/components/settings/hooks/useSettingsHandlers.ts index 617e2c45..0b020b00 100644 --- a/src/renderer/components/settings/hooks/useSettingsHandlers.ts +++ b/src/renderer/components/settings/hooks/useSettingsHandlers.ts @@ -294,6 +294,7 @@ export function useSettingsHandlers({ showTimestamps: true, compactMode: false, syntaxHighlighting: true, + keepContextNavExpanded: false, }, sessions: { pinnedSessions: {}, diff --git a/src/renderer/components/settings/sections/GeneralSection.tsx b/src/renderer/components/settings/sections/GeneralSection.tsx index 1ed1ae20..e7e84904 100644 --- a/src/renderer/components/settings/sections/GeneralSection.tsx +++ b/src/renderer/components/settings/sections/GeneralSection.tsx @@ -28,6 +28,7 @@ interface GeneralSectionProps { readonly safeConfig: SafeConfig; readonly saving: boolean; readonly onGeneralToggle: (key: keyof AppConfig['general'], value: boolean) => void; + readonly onDisplayToggle: (key: keyof AppConfig['display'], value: boolean) => void; readonly onThemeChange: (value: 'dark' | 'light' | 'system') => void; } @@ -35,6 +36,7 @@ export const GeneralSection = ({ safeConfig, saving, onGeneralToggle, + onDisplayToggle, onThemeChange, }: GeneralSectionProps): React.JSX.Element => { const [serverStatus, setServerStatus] = useState({ @@ -297,6 +299,16 @@ export const GeneralSection = ({ disabled={saving} /> + + onDisplayToggle('keepContextNavExpanded', v)} + disabled={saving} + /> + {isElectron && !window.navigator.userAgent.includes('Macintosh') && (