feat(sidebar): add single-project display mode

This commit is contained in:
Bohdan Triapitsyn
2026-08-21 16:25:51 +03:00
parent bbb2fdbe19
commit b879cf323f
30 changed files with 557 additions and 61 deletions
+105
View File
@@ -6,6 +6,7 @@ import { startModelPrefsAutoSave } from '@/lib/modelPrefsAutoSave';
import { startAppearanceAutoSave } from '@/lib/appearanceAutoSave';
import { useUIStore } from '@/stores/useUIStore';
import { useMessageQueueStore } from '@/stores/messageQueueStore';
import { useSessionDisplayStore } from '@/stores/useSessionDisplayStore';
import {
applyPersistedHomeDirectoryToWindow,
getRuntimeSettingsMirrorStorageKey,
@@ -443,6 +444,110 @@ describe('updateDesktopSettings', () => {
expect(localStorage.getItem('selectedThemeId')).toBe('existing-theme');
});
test('applies authoritative shared sidebar preferences without replacing local-only sidebar state', async () => {
getWindow();
useSessionDisplayStore.setState({
projectDisplayMode: 'all',
sessionGroupingMode: 'by-worktree',
projectSortOrder: 'manual',
showRecentSection: true,
singleProjectId: 'local-project',
stickyZoneHeaders: false,
});
registerSettingsApi(async () => ({}), async () => ({
settings: {
sidebarProjectDisplayMode: 'single',
sidebarSessionGroupingMode: 'flat',
sidebarProjectSortOrder: 'recent',
sidebarShowRecentSection: false,
autoSaveEnabled: true,
draftStartersCraftGoalAdded: true,
draftStartersScheduleTaskAdded: true,
},
source: 'web',
}));
await syncDesktopSettings();
const state = useSessionDisplayStore.getState();
expect({
projectDisplayMode: state.projectDisplayMode,
sessionGroupingMode: state.sessionGroupingMode,
projectSortOrder: state.projectSortOrder,
showRecentSection: state.showRecentSection,
singleProjectId: state.singleProjectId,
stickyZoneHeaders: state.stickyZoneHeaders,
}).toEqual({
projectDisplayMode: 'single',
sessionGroupingMode: 'flat',
projectSortOrder: 'recent',
showRecentSection: false,
singleProjectId: 'local-project',
stickyZoneHeaders: false,
});
});
test('seeds missing shared sidebar preferences from the hydrated local cache', async () => {
getWindow();
const saves: Array<Partial<SettingsPayload>> = [];
useSessionDisplayStore.setState({
projectDisplayMode: 'single',
sessionGroupingMode: 'flat',
projectSortOrder: 'a-z',
showRecentSection: false,
});
registerSettingsApi(async (changes) => {
saves.push(changes);
return changes;
}, async () => ({
settings: {
autoSaveEnabled: true,
draftStartersCraftGoalAdded: true,
draftStartersScheduleTaskAdded: true,
},
source: 'web',
}));
await syncDesktopSettings();
expect(saves).toEqual([{
draftStartersCraftGoalAdded: true,
draftStartersScheduleTaskAdded: true,
sidebarProjectDisplayMode: 'single',
sidebarSessionGroupingMode: 'flat',
sidebarProjectSortOrder: 'a-z',
sidebarShowRecentSection: false,
}]);
});
test('preserves local sidebar preferences when the authoritative load fails', async () => {
getWindow();
useSessionDisplayStore.setState({
projectDisplayMode: 'single',
sessionGroupingMode: 'flat',
projectSortOrder: 'z-a',
showRecentSection: false,
});
registerSettingsApi(async () => ({}), async () => {
throw new Error('offline');
});
await syncDesktopSettings();
const state = useSessionDisplayStore.getState();
expect({
projectDisplayMode: state.projectDisplayMode,
sessionGroupingMode: state.sessionGroupingMode,
projectSortOrder: state.projectSortOrder,
showRecentSection: state.showRecentSection,
}).toEqual({
projectDisplayMode: 'single',
sessionGroupingMode: 'flat',
projectSortOrder: 'z-a',
showRecentSection: false,
});
});
test('applies model selector settings from server settings', async () => {
getWindow();
const settings = {