feat(settings): Session tabs toggle in General → Navigation

A new Session tabs group (web/desktop only) turns the header session
tabs off; disabled, the header renders the exact pre-tabs view — plain
session title with meta row and the always-visible session menu (the
same block VS Code uses). The Alt+W close-tab shortcut no-ops while
tabs are off. Registered in settings search with a matching anchor;
labels translated in all locales.
This commit is contained in:
Bohdan Triapitsyn
2026-08-25 00:05:45 +03:00
parent 2c1d8d592e
commit ce90e7e24f
16 changed files with 83 additions and 5 deletions
+3 -2
View File
@@ -436,6 +436,7 @@ export const Header: React.FC = () => {
const openContextPlan = useUIStore((state) => state.openContextPlan);
const closeContextPanel = useUIStore((state) => state.closeContextPanel);
const shortcutOverrides = useUIStore((state) => state.shortcutOverrides);
const sessionTabsEnabled = useUIStore((state) => state.sessionTabsEnabled);
const getCurrentModel = useConfigStore((state) => state.getCurrentModel);
const runtimeApis = useRuntimeAPIs();
@@ -1654,7 +1655,7 @@ export const Header: React.FC = () => {
</span>
) : null}
</div>
) : isVSCode ? (
) : (isVSCode || !sessionTabsEnabled) ? (
<div className="app-region-no-drag mr-3 flex min-w-0 max-w-full items-center gap-0.5 py-0.5 -my-0.5 text-left">
{!isSidebarOpen ? (
<SessionSwitcherDropdown align="start">
@@ -1876,7 +1877,7 @@ export const Header: React.FC = () => {
</div>
)}
{activeSurfaceHeader || isVSCode ? <div className="flex-1" /> : null}
{activeSurfaceHeader || isVSCode || !sessionTabsEnabled ? <div className="flex-1" /> : null}
<div className="flex shrink-0 items-center gap-1">
{showDesktopHeaderContextUsage && stableDesktopContextUsage ? (
@@ -266,7 +266,7 @@ const normalizeUserMessageRenderingMode = (mode: unknown): 'markdown' | 'plain'
return mode === 'markdown' ? 'markdown' : 'plain';
};
type VisibleSetting = 'sessionAssist' | 'sessionGoal' | 'theme' | 'windowControlsPosition' | 'pwaInstallName' | 'pwaOrientation' | 'mobileKeyboardMode' | 'timeFormat' | 'weekStart' | 'fontSize' | 'terminalFontSize' | 'terminalShell' | 'terminalLoginShell' | 'editorFontSize' | 'spacing' | 'inputBarOffset' | 'mermaidRendering' | 'userMessageRendering' | 'chatRenderMode' | 'messageTransport' | 'activityRenderMode' | 'collapsibleUserMessages' | 'stickyUserHeader' | 'promptNavigatorEnabled' | 'wideChatLayout' | 'codeBlockLineWrap' | 'splitAssistantMessageActions' | 'subagentReadOnlyBanner' | 'diffLayout' | 'mobileStatusBar' | 'dotfiles' | 'fileViewerPreview' | 'reasoning' | 'showToolFileIcons' | 'showTurnChangedFiles' | 'expandedTools' | 'followUpBehavior' | 'terminalQuickKeys' | 'fileEditorKeymap' | 'persistDraft' | 'inputSpellcheck' | 'reportUsage' | 'expandedEditorToolbar' | 'autoSaveEnabled';
type VisibleSetting = 'sessionAssist' | 'sessionGoal' | 'theme' | 'windowControlsPosition' | 'pwaInstallName' | 'pwaOrientation' | 'mobileKeyboardMode' | 'timeFormat' | 'weekStart' | 'fontSize' | 'terminalFontSize' | 'terminalShell' | 'terminalLoginShell' | 'editorFontSize' | 'spacing' | 'inputBarOffset' | 'mermaidRendering' | 'userMessageRendering' | 'chatRenderMode' | 'messageTransport' | 'activityRenderMode' | 'collapsibleUserMessages' | 'stickyUserHeader' | 'promptNavigatorEnabled' | 'wideChatLayout' | 'codeBlockLineWrap' | 'splitAssistantMessageActions' | 'subagentReadOnlyBanner' | 'diffLayout' | 'mobileStatusBar' | 'dotfiles' | 'fileViewerPreview' | 'reasoning' | 'showToolFileIcons' | 'showTurnChangedFiles' | 'expandedTools' | 'followUpBehavior' | 'terminalQuickKeys' | 'fileEditorKeymap' | 'persistDraft' | 'inputSpellcheck' | 'reportUsage' | 'expandedEditorToolbar' | 'autoSaveEnabled' | 'sessionTabs';
const WINDOW_CONTROLS_POSITION_OPTIONS: Array<{ id: DesktopWindowControlsPosition; labelKey: string }> = [
{ id: 'left', labelKey: 'settings.openchamber.desktopNetwork.option.windowControlsLeft' },
@@ -350,6 +350,8 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
const diffLayoutPreference = useUIStore(state => state.diffLayoutPreference);
const setDiffLayoutPreference = useUIStore(state => state.setDiffLayoutPreference);
const showTerminalQuickKeysOnDesktop = useUIStore(state => state.showTerminalQuickKeysOnDesktop);
const sessionTabsEnabled = useUIStore(state => state.sessionTabsEnabled);
const setSessionTabsEnabled = useUIStore(state => state.setSessionTabsEnabled);
const setShowTerminalQuickKeysOnDesktop = useUIStore(state => state.setShowTerminalQuickKeysOnDesktop);
const fileEditorKeymap = useUIStore(state => state.fileEditorKeymap);
const setFileEditorKeymap = useUIStore(state => state.setFileEditorKeymap);
@@ -621,7 +623,7 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
? hasLocalizationSettings
: (shouldShow('theme') || showWindowControlsPositionSetting || shouldShow('pwaInstallName') || shouldShow('pwaOrientation') || shouldShow('timeFormat') || shouldShow('weekStart'));
const hasLayoutSettings = shouldShow('fontSize') || shouldShow('terminalFontSize') || shouldShow('editorFontSize') || shouldShow('spacing') || (shouldShow('inputBarOffset') && isMobile);
const hasNavigationSettings = (shouldShow('terminalQuickKeys') && !isMobile) || ((shouldShow('terminalShell') || shouldShow('terminalLoginShell')) && !isVSCode) || shouldShow('fileEditorKeymap') || shouldShow('autoSaveEnabled') || (shouldShow('expandedEditorToolbar') && !isVSCode);
const hasNavigationSettings = (shouldShow('terminalQuickKeys') && !isMobile) || ((shouldShow('terminalShell') || shouldShow('terminalLoginShell')) && !isVSCode) || shouldShow('fileEditorKeymap') || shouldShow('autoSaveEnabled') || (shouldShow('expandedEditorToolbar') && !isVSCode) || (shouldShow('sessionTabs') && !isVSCode && !isMobile);
const hasBehaviorSettings = shouldShow('mermaidRendering')
|| (shouldShow('sessionGoal') && !isVSCode)
|| shouldShow('userMessageRendering')
@@ -1436,6 +1438,20 @@ export const OpenChamberVisualSettings: React.FC<OpenChamberVisualSettingsProps>
</SettingsRadioGroup>
</SettingsControlGroup>
)}
{shouldShow('sessionTabs') && !isVSCode && !isMobile && (
<SettingsControlGroup
title={t('settings.openchamber.visual.field.sessionTabsGroup')}
settingsItem="appearance.session-tabs"
>
<SettingsCheckboxRow
checked={sessionTabsEnabled}
onChange={setSessionTabsEnabled}
label={t('settings.openchamber.visual.field.sessionTabs')}
ariaLabel={t('settings.openchamber.visual.field.sessionTabsAria')}
info={t('settings.openchamber.visual.field.sessionTabsInfo')}
/>
</SettingsControlGroup>
)}
<div className={SETTINGS_OPTION_STACK_CLASS}>
{shouldShow('autoSaveEnabled') && (
<SettingsCheckboxRow
@@ -300,7 +300,7 @@ export const useKeyboardShortcuts = () => {
return;
}
if (!isVSCodeRuntime() && eventMatchesShortcut(e, combo('close_session_tab'))) {
if (!isVSCodeRuntime() && useUIStore.getState().sessionTabsEnabled && eventMatchesShortcut(e, combo('close_session_tab'))) {
e.preventDefault();
if (currentSessionId) {
closeSessionTabAndActivateNeighbour(currentSessionId);
@@ -1917,6 +1917,10 @@ export const settingsDict = {
'settings.openchamber.visual.actions.resetInputBarOffsetAria': 'Versatz der Eingabeleiste zurücksetzen',
'settings.openchamber.visual.field.terminalQuickKeysAria': 'Schnelltasten des Terminals',
'settings.openchamber.visual.field.terminalQuickKeys': 'Schnelltasten des Terminals',
'settings.openchamber.visual.field.sessionTabsGroup': 'Sitzungs-Tabs',
'settings.openchamber.visual.field.sessionTabs': 'Sitzungen als Tabs in der Kopfzeile anzeigen',
'settings.openchamber.visual.field.sessionTabsAria': 'Sitzungs-Tabs in der Kopfzeile umschalten',
'settings.openchamber.visual.field.sessionTabsInfo': 'Geöffnete Sitzungen erscheinen als Tabs in der Kopfzeile. Ausgeschaltet zeigt die Kopfzeile wieder nur den Sitzungstitel.',
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'Esc, Strg, Pfeiltasten in der Terminalansicht anzeigen',
'settings.openchamber.visual.field.fileEditorKeymap': 'Tastaturlayout für Datei-Editor',
'settings.openchamber.visual.option.fileEditorKeymap.default': 'Standard',
@@ -1995,6 +1995,10 @@ export const settingsDict = {
'settings.openchamber.visual.actions.resetInputBarOffsetAria': 'Reset input bar offset',
'settings.openchamber.visual.field.terminalQuickKeysAria': 'Terminal quick keys',
'settings.openchamber.visual.field.terminalQuickKeys': 'Terminal Quick Keys',
'settings.openchamber.visual.field.sessionTabsGroup': 'Session tabs',
'settings.openchamber.visual.field.sessionTabs': 'Show sessions as tabs in the header',
'settings.openchamber.visual.field.sessionTabsAria': 'Toggle session tabs in the header',
'settings.openchamber.visual.field.sessionTabsInfo': 'Sessions you open line up as tabs in the header. Turning this off restores the plain session title.',
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'Show Esc, Ctrl, Arrows in terminal view',
'settings.openchamber.visual.field.fileEditorKeymap': 'File editor keymap',
'settings.openchamber.visual.option.fileEditorKeymap.default': 'Default',
@@ -1972,6 +1972,10 @@ export const settingsDict = {
"settings.openchamber.visual.actions.resetInputBarOffsetAria": "Restablecer desplazamiento de la barra de entrada",
"settings.openchamber.visual.field.terminalQuickKeysAria": "Teclas rápidas del terminal",
"settings.openchamber.visual.field.terminalQuickKeys": "Teclas rápidas del terminal",
"settings.openchamber.visual.field.sessionTabsGroup": "Pestañas de sesión",
"settings.openchamber.visual.field.sessionTabs": "Mostrar las sesiones como pestañas en el encabezado",
"settings.openchamber.visual.field.sessionTabsAria": "Alternar las pestañas de sesión en el encabezado",
"settings.openchamber.visual.field.sessionTabsInfo": "Las sesiones que abres se alinean como pestañas en el encabezado. Al desactivarlo, el encabezado vuelve a mostrar solo el título de la sesión.",
"settings.openchamber.visual.field.terminalQuickKeysTooltip": "Mostrar Esc, Ctrl y flechas en la vista del terminal",
"settings.openchamber.visual.field.fileEditorKeymap": "Mapa de teclas del editor de archivos",
"settings.openchamber.visual.option.fileEditorKeymap.default": "Predeterminado",
@@ -1882,6 +1882,10 @@ export const settingsDict = {
'settings.openchamber.visual.actions.resetInputBarOffsetAria': 'Réinitialiser le décalage de la barre d\'entrée',
'settings.openchamber.visual.field.terminalQuickKeysAria': 'Touches rapides du terminal',
'settings.openchamber.visual.field.terminalQuickKeys': 'Touches rapides du terminal',
'settings.openchamber.visual.field.sessionTabsGroup': 'Onglets de session',
'settings.openchamber.visual.field.sessionTabs': 'Afficher les sessions sous forme d\'onglets dans l\'en-tête',
'settings.openchamber.visual.field.sessionTabsAria': 'Basculer les onglets de session dans l\'en-tête',
'settings.openchamber.visual.field.sessionTabsInfo': 'Les sessions ouvertes s\'alignent en onglets dans l\'en-tête. Désactivé, l\'en-tête n\'affiche que le titre de la session.',
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'Afficher Esc, Ctrl, Flèches dans la vue du terminal',
'settings.openchamber.visual.field.activityDefaultModeAria': 'Mode d\'activité par défaut : {option}',
'settings.openchamber.visual.field.showExpandedBashToolsAria': 'Afficher les outils bash étendus',
@@ -2005,6 +2005,10 @@ export const settingsDict = {
'settings.openchamber.visual.actions.resetInputBarOffsetAria': '入力バーオフセットをリセット',
'settings.openchamber.visual.field.terminalQuickKeysAria': 'ターミナルクイックキー',
'settings.openchamber.visual.field.terminalQuickKeys': 'ターミナルクイックキー',
'settings.openchamber.visual.field.sessionTabsGroup': 'セッションタブ',
'settings.openchamber.visual.field.sessionTabs': 'ヘッダーにセッションをタブとして表示',
'settings.openchamber.visual.field.sessionTabsAria': 'ヘッダーのセッションタブを切り替え',
'settings.openchamber.visual.field.sessionTabsInfo': '開いたセッションがヘッダーにタブとして並びます。オフにするとヘッダーはセッションタイトルのみ表示します。',
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'ターミナルビューに Esc、Ctrl、矢印を表示',
'settings.openchamber.visual.field.fileEditorKeymap': 'ファイルエディターキーマップ',
'settings.openchamber.visual.option.fileEditorKeymap.default': 'デフォルト',
@@ -1972,6 +1972,10 @@ export const settingsDict = {
'settings.openchamber.visual.actions.resetInputBarOffsetAria': '입력 바 오프셋 초기화',
'settings.openchamber.visual.field.terminalQuickKeysAria': '터미널 빠른 키',
'settings.openchamber.visual.field.terminalQuickKeys': '터미널 빠른 키',
'settings.openchamber.visual.field.sessionTabsGroup': '세션 탭',
'settings.openchamber.visual.field.sessionTabs': '헤더에 세션을 탭으로 표시',
'settings.openchamber.visual.field.sessionTabsAria': '헤더 세션 탭 전환',
'settings.openchamber.visual.field.sessionTabsInfo': '연 세션이 헤더에 탭으로 나열됩니다. 끄면 헤더에 세션 제목만 표시됩니다.',
'settings.openchamber.visual.field.terminalQuickKeysTooltip': '터미널 보기에서 Esc, Ctrl, 화살표를 표시합니다',
'settings.openchamber.visual.field.fileEditorKeymap': '파일 편집기 키맵',
'settings.openchamber.visual.option.fileEditorKeymap.default': '기본값',
@@ -1124,6 +1124,10 @@ export const settingsDict = {
'settings.openchamber.visual.option.terminalShell.auto': 'Automatycznie',
'settings.openchamber.visual.field.editorFontSize': 'Rozmiar czcionki edytora',
'settings.openchamber.visual.field.terminalQuickKeys': 'Szybkie klawisze terminala',
'settings.openchamber.visual.field.sessionTabsGroup': 'Karty sesji',
'settings.openchamber.visual.field.sessionTabs': 'Pokazuj sesje jako karty w nagłówku',
'settings.openchamber.visual.field.sessionTabsAria': 'Przełącz karty sesji w nagłówku',
'settings.openchamber.visual.field.sessionTabsInfo': 'Otwierane sesje układają się jako karty w nagłówku. Po wyłączeniu nagłówek pokazuje tylko tytuł sesji.',
'settings.openchamber.visual.field.terminalQuickKeysAria': 'Szybkie klawisze terminala',
'settings.openchamber.visual.field.terminalQuickKeysTooltip': 'Pokaż Esc, Ctrl i strzałki w widoku terminala',
'settings.openchamber.visual.field.fileEditorKeymap': 'Mapa klawiszy edytora plików',
@@ -1972,6 +1972,10 @@ export const settingsDict = {
"settings.openchamber.visual.actions.resetInputBarOffsetAria": "Redefinir deslocamento da barra de entrada",
"settings.openchamber.visual.field.terminalQuickKeysAria": "Teclas rápidas do terminal",
"settings.openchamber.visual.field.terminalQuickKeys": "Teclas rápidas do terminal",
"settings.openchamber.visual.field.sessionTabsGroup": "Abas de sessão",
"settings.openchamber.visual.field.sessionTabs": "Mostrar sessões como abas no cabeçalho",
"settings.openchamber.visual.field.sessionTabsAria": "Alternar abas de sessão no cabeçalho",
"settings.openchamber.visual.field.sessionTabsInfo": "As sessões abertas se alinham como abas no cabeçalho. Desativado, o cabeçalho volta a mostrar apenas o título da sessão.",
"settings.openchamber.visual.field.terminalQuickKeysTooltip": "Mostrar Esc, Ctrl e flechas na vista do terminal",
"settings.openchamber.visual.field.fileEditorKeymap": "Mapa de teclas do editor de arquivos",
"settings.openchamber.visual.option.fileEditorKeymap.default": "Padrão",
@@ -1972,6 +1972,10 @@ export const settingsDict = {
"settings.openchamber.visual.actions.resetInputBarOffsetAria": "Скинути зміщення панелі вводу",
"settings.openchamber.visual.field.terminalQuickKeysAria": "Швидкі клавіші терміналу",
"settings.openchamber.visual.field.terminalQuickKeys": "Швидкі клавіші терміналу",
"settings.openchamber.visual.field.sessionTabsGroup": "Вкладки сесій",
"settings.openchamber.visual.field.sessionTabs": "Показувати сесії як вкладки в хедері",
"settings.openchamber.visual.field.sessionTabsAria": "Перемкнути вкладки сесій у хедері",
"settings.openchamber.visual.field.sessionTabsInfo": "Відкриті сесії шикуються вкладками в хедері. Якщо вимкнено, хедер знову показує лише назву сесії.",
"settings.openchamber.visual.field.terminalQuickKeysTooltip": "Показати Esc, Ctrl, стрілки в поданні терміналу",
"settings.openchamber.visual.field.fileEditorKeymap": "Розкладка клавіш редактора файлів",
"settings.openchamber.visual.option.fileEditorKeymap.default": "Типова",
@@ -1972,6 +1972,10 @@ export const settingsDict = {
'settings.openchamber.visual.actions.resetInputBarOffsetAria': '重置输入栏偏移',
'settings.openchamber.visual.field.terminalQuickKeysAria': '终端快捷键',
'settings.openchamber.visual.field.terminalQuickKeys': '终端快捷键',
'settings.openchamber.visual.field.sessionTabsGroup': '会话标签页',
'settings.openchamber.visual.field.sessionTabs': '在页眉中以标签页显示会话',
'settings.openchamber.visual.field.sessionTabsAria': '切换页眉会话标签页',
'settings.openchamber.visual.field.sessionTabsInfo': '打开的会话会以标签页形式排列在页眉中。关闭后页眉仅显示会话标题。',
'settings.openchamber.visual.field.terminalQuickKeysTooltip': '在终端视图显示 Esc、Ctrl、方向键',
'settings.openchamber.visual.field.fileEditorKeymap': '文件编辑器键位映射',
'settings.openchamber.visual.option.fileEditorKeymap.default': '默认',
@@ -1879,6 +1879,10 @@ export const settingsDict = {
'settings.openchamber.visual.actions.resetInputBarOffsetAria': '重設輸入列偏移',
'settings.openchamber.visual.field.terminalQuickKeysAria': '終端機快速鍵',
'settings.openchamber.visual.field.terminalQuickKeys': '終端機快速鍵',
'settings.openchamber.visual.field.sessionTabsGroup': '會話分頁',
'settings.openchamber.visual.field.sessionTabs': '在頁首以分頁顯示會話',
'settings.openchamber.visual.field.sessionTabsAria': '切換頁首會話分頁',
'settings.openchamber.visual.field.sessionTabsInfo': '開啟的會話會以分頁排列在頁首。關閉後頁首僅顯示會話標題。',
'settings.openchamber.visual.field.terminalQuickKeysTooltip': '在終端機檢視顯示 Esc、Ctrl、方向鍵',
'settings.openchamber.visual.field.fileEditorKeymap': '檔案編輯器鍵位映射',
'settings.openchamber.visual.option.fileEditorKeymap.default': '預設',
+8
View File
@@ -161,6 +161,14 @@ const SETTINGS_SEARCH_ITEMS: readonly SettingsSearchItem[] = [
titleKey: 'settings.openchamber.visual.field.fileEditorKeymap',
keywords: ['editor', 'vim', 'keymap'],
},
{
id: 'appearance.session-tabs',
page: 'general',
titleKey: 'settings.openchamber.visual.field.sessionTabsGroup',
descriptionKey: 'settings.openchamber.visual.field.sessionTabsInfo',
keywords: ['session', 'tabs', 'header', 'working set'],
isAvailable: (ctx) => !ctx.isMobile && !ctx.isVSCode,
},
{
id: 'appearance.terminal-quick-keys',
page: 'general',
+9
View File
@@ -750,6 +750,8 @@ interface UIStore {
maxLastMessageLength: number; // chars — truncate {last_message} when summarization is off
showTerminalQuickKeysOnDesktop: boolean;
/** Header session tabs (web/desktop). Off restores the plain session title. */
sessionTabsEnabled: boolean;
persistChatDraft: boolean;
showOpenCodeUpdateNotifications: boolean;
agentControlToolEnabled: boolean;
@@ -920,6 +922,7 @@ interface UIStore {
setNativeNotificationsEnabled: (value: boolean) => void;
setNotificationMode: (mode: 'always' | 'hidden-only') => void;
setShowTerminalQuickKeysOnDesktop: (value: boolean) => void;
setSessionTabsEnabled: (value: boolean) => void;
setNotifyOnSubtasks: (value: boolean) => void;
setDockBadgeEnabled: (value: boolean) => void;
setNotifyOnCompletion: (value: boolean) => void;
@@ -1092,6 +1095,7 @@ export const useUIStore = create<UIStore>()(
maxLastMessageLength: 250,
showTerminalQuickKeysOnDesktop: false,
sessionTabsEnabled: true,
persistChatDraft: true,
showOpenCodeUpdateNotifications: !isWindowsArm64(),
agentControlToolEnabled: true,
@@ -2244,6 +2248,10 @@ export const useUIStore = create<UIStore>()(
set({ showTerminalQuickKeysOnDesktop: value });
},
setSessionTabsEnabled: (value) => {
set({ sessionTabsEnabled: value });
},
setNotifyOnSubtasks: (value) => {
set({ notifyOnSubtasks: value });
},
@@ -2672,6 +2680,7 @@ export const useUIStore = create<UIStore>()(
nativeNotificationsEnabled: state.nativeNotificationsEnabled,
notificationMode: state.notificationMode,
showTerminalQuickKeysOnDesktop: state.showTerminalQuickKeysOnDesktop,
sessionTabsEnabled: state.sessionTabsEnabled,
notifyOnSubtasks: state.notifyOnSubtasks,
dockBadgeEnabled: state.dockBadgeEnabled,
notifyOnCompletion: state.notifyOnCompletion,