feat(ui): add session history navigation, permission keys, and review shortcuts
mod+alt+arrows step through this window's session-open history (or between neighbouring tabs when session tabs are on), mod+k r renames the current session inline, and mod+k a toggles permission auto-accept. Pending permission cards respond to alt+enter / alt+shift+enter / alt+backspace with the keys printed on the buttons. The commit message box commits on mod+enter, alt+arrows step the diff review between changed files, and the command palette gains search-only commands for rare actions so the initial list stays short.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import type { Session } from '@opencode-ai/sdk/v2';
|
||||
import { navigateSessionHistory } from './sessionNavigationHistory';
|
||||
import { useSessionUIStore } from '@/sync/session-ui-store';
|
||||
import { useGlobalSessionsStore } from '@/stores/useGlobalSessionsStore';
|
||||
|
||||
// SAFETY: the history module only reads a session's id and directory metadata.
|
||||
const session = (id: string): Session => ({
|
||||
id,
|
||||
title: id,
|
||||
directory: '/repo',
|
||||
projectID: 'p1',
|
||||
version: '1',
|
||||
time: { created: 1, updated: 1 },
|
||||
} as Session);
|
||||
|
||||
describe('sessionNavigationHistory', () => {
|
||||
test('steps back and forward through the visit order', () => {
|
||||
useGlobalSessionsStore.setState({ activeSessions: [session('s1'), session('s2'), session('s3')] });
|
||||
|
||||
useSessionUIStore.setState({ currentSessionId: 's1' });
|
||||
useSessionUIStore.setState({ currentSessionId: 's2' });
|
||||
useSessionUIStore.setState({ currentSessionId: 's3' });
|
||||
|
||||
expect(navigateSessionHistory(-1)).toBe(true);
|
||||
expect(useSessionUIStore.getState().currentSessionId).toBe('s2');
|
||||
expect(navigateSessionHistory(-1)).toBe(true);
|
||||
expect(useSessionUIStore.getState().currentSessionId).toBe('s1');
|
||||
expect(navigateSessionHistory(-1)).toBe(false);
|
||||
|
||||
expect(navigateSessionHistory(1)).toBe(true);
|
||||
expect(useSessionUIStore.getState().currentSessionId).toBe('s2');
|
||||
});
|
||||
|
||||
test('a fresh visit truncates the forward branch', () => {
|
||||
// Continues from the previous test's state: at s2 with s3 forward.
|
||||
useSessionUIStore.setState({ currentSessionId: 's1' });
|
||||
expect(navigateSessionHistory(1)).toBe(false);
|
||||
expect(navigateSessionHistory(-1)).toBe(true);
|
||||
expect(useSessionUIStore.getState().currentSessionId).toBe('s2');
|
||||
});
|
||||
|
||||
test('skips and drops entries whose session no longer exists', () => {
|
||||
useSessionUIStore.setState({ currentSessionId: 's3' });
|
||||
useGlobalSessionsStore.setState({ activeSessions: [session('s1'), session('s3')] });
|
||||
// History behind s3 contains s2 (dead) then s1 (alive).
|
||||
expect(navigateSessionHistory(-1)).toBe(true);
|
||||
expect(useSessionUIStore.getState().currentSessionId).toBe('s1');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user