Skip to content

Commit 8251337

Browse files
committed
fix: preserve sessions tab render on navigation
1 parent 8d5cc34 commit 8251337

6 files changed

Lines changed: 54 additions & 5 deletions

File tree

tests/unit/config-tabs-ui.test.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,8 @@ test('web ui script defines provider mode metadata for codex only', () => {
408408
assert.match(appScript, /const enteringUsageTab = nextTab === 'usage';/);
409409
assert.match(appScript, /this\.loadSessionsUsage\(\);/);
410410
assert.match(appScript, /if \(targetTab === previousTab\) {/);
411-
assert.match(appScript, /const shouldDeferApply = isLeavingSessions;/);
411+
assert.match(appScript, /const shouldPreserveSessionRender = isLeavingSessions && this\.preserveSessionRenderOnTabLeave === true;/);
412+
assert.match(appScript, /const shouldDeferApply = isLeavingSessions && !shouldPreserveSessionRender;/);
412413
assert.match(appScript, /if \(isLeavingSessions && !this\.isSessionPanelFastHidden\(\)\) {/);
413414
assert.match(appScript, /switchState\.pendingTarget = targetTab;/);
414415
assert.match(appScript, /if \(ticket !== liveState\.ticket\) return;/);

tests/unit/session-tab-switch-performance.test.mjs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,45 @@ test('deferred teardown is skipped when user quickly switches back to sessions',
425425
assert.strictEqual(teardownCount, 0);
426426
});
427427

428+
test('switchMainTab can preserve rendered sessions when leaving and returning to the browser tab', () => {
429+
const calls = {
430+
teardown: 0,
431+
prepare: 0,
432+
loadSessions: 0
433+
};
434+
const vm = {
435+
mainTab: 'sessions',
436+
configMode: 'codex',
437+
sessionsLoadedOnce: true,
438+
preserveSessionRenderOnTabLeave: true,
439+
sessionListRenderEnabled: true,
440+
sessionPreviewRenderEnabled: true,
441+
scheduleSessionTabDeferredTeardown() {
442+
calls.teardown += 1;
443+
},
444+
teardownSessionTabRender() {
445+
calls.teardown += 1;
446+
},
447+
prepareSessionTabRender() {
448+
calls.prepare += 1;
449+
},
450+
loadSessions() {
451+
calls.loadSessions += 1;
452+
},
453+
refreshClaudeModelContext() {}
454+
};
455+
456+
switchMainTab.call(vm, 'usage');
457+
assert.strictEqual(vm.mainTab, 'usage');
458+
assert.strictEqual(vm.sessionListRenderEnabled, true);
459+
assert.strictEqual(vm.sessionPreviewRenderEnabled, true);
460+
assert.deepStrictEqual(calls, { teardown: 0, prepare: 0, loadSessions: 0 });
461+
462+
switchMainTab.call(vm, 'sessions');
463+
assert.strictEqual(vm.mainTab, 'sessions');
464+
assert.deepStrictEqual(calls, { teardown: 0, prepare: 0, loadSessions: 0 });
465+
});
466+
428467
test('loadSessions replays the latest pending request after an in-flight list refresh completes', async () => {
429468
const apiCalls = [];
430469
let resolveFirstRequest = null;

tests/unit/web-ui-behavior-parity.test.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ test('captured bundled app skeleton only exposes expected data key drift versus
444444
'promptComposerVarValuesRaw',
445445
'sessionConverting',
446446
'sessionImportingNative',
447+
'preserveSessionRenderOnTabLeave',
447448
'sessionSortMode',
448449
'sessionsUsageCompareEnabled',
449450
'sessionsUsageSelectedDayKey',

web-ui/app.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,7 @@ document.addEventListener('DOMContentLoaded', () => {
232232
sessionPreviewHeaderEl: null,
233233
sessionPreviewHeaderResizeObserver: null,
234234
sessionListRenderEnabled: false,
235+
preserveSessionRenderOnTabLeave: true,
235236
sessionListVisibleCount: 0,
236237
sessionListInitialBatchSize: 40,
237238
sessionListLoadStep: 80,

web-ui/modules/app.methods.navigation.mjs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,9 +489,10 @@
489489
return;
490490
}
491491
const isLeavingSessions = previousTab === 'sessions' && targetTab !== 'sessions';
492-
const shouldDeferApply = isLeavingSessions;
492+
const shouldPreserveSessionRender = isLeavingSessions && this.preserveSessionRenderOnTabLeave === true;
493+
const shouldDeferApply = isLeavingSessions && !shouldPreserveSessionRender;
493494
if (isLeavingSessions && !this.isSessionPanelFastHidden()) {
494-
this.setSessionPanelFastHidden(true);
495+
this.setSessionPanelFastHidden(!shouldPreserveSessionRender);
495496
}
496497
if (shouldDeferApply && typeof this.suspendSessionTabRender === 'function') {
497498
this.suspendSessionTabRender();

web-ui/session-helpers.mjs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export function switchMainTab(tab) {
9090
emitSessionLoadDebug(this, 'switchMainTab:start', `from=${previousTab}\nto=${nextTab}`);
9191
this.mainTab = nextTab;
9292

93-
if (leavingSessions) {
93+
if (leavingSessions && this.preserveSessionRenderOnTabLeave !== true) {
9494
const teardown = () => {
9595
if (this.mainTab === 'sessions') return;
9696
if (typeof this.finalizeSessionTabTeardown === 'function') {
@@ -156,7 +156,13 @@ export function switchMainTab(tab) {
156156
if (nextTab !== 'orchestration' && typeof this.stopTaskOrchestrationPolling === 'function') {
157157
this.stopTaskOrchestrationPolling();
158158
}
159-
if (nextTab === 'sessions') {
159+
if (
160+
nextTab === 'sessions'
161+
&& (
162+
!this.sessionListRenderEnabled
163+
|| !this.sessionPreviewRenderEnabled
164+
)
165+
) {
160166
this.prepareSessionTabRender();
161167
}
162168
const shouldLoadTrashListOnSettingsEnter = nextTab === 'settings'

0 commit comments

Comments
 (0)