refactor(team): extract messages panel mode persistence

This commit is contained in:
777genius 2026-05-22 11:39:54 +03:00
parent f0ca6a57c2
commit ab76e5424d
3 changed files with 104 additions and 27 deletions

View file

@ -89,6 +89,10 @@ import {
pruneOptimisticMessages,
upsertOptimisticTeamMessage,
} from '../team/teamMessagesCache';
import {
loadPersistedMessagesPanelMode,
savePersistedMessagesPanelMode,
} from '../team/teamMessagesPanelModePersistence';
import {
clearAllPendingReplyRefreshWaits,
clearPendingReplyRefreshWaits,
@ -175,6 +179,10 @@ export type {
TeamMessagesCacheEntry,
} from '../team/teamMessagesCache';
export { selectMemberMessagesForTeamMember, selectTeamMessages } from '../team/teamMessagesCache';
export {
loadPersistedMessagesPanelMode,
savePersistedMessagesPanelMode,
} from '../team/teamMessagesPanelModePersistence';
export {
getActiveTeamPendingReplyWaits,
hasActiveTeamPendingReplyWait,
@ -2200,33 +2208,6 @@ export interface TeamSlice {
// --- Per-team launch params persistence ---
const LAUNCH_PARAMS_PREFIX = 'team:launchParams:';
const MESSAGES_PANEL_MODE_STORAGE_KEY = 'team:messagesPanelMode';
const DEFAULT_MESSAGES_PANEL_MODE: TeamMessagesPanelMode = 'sidebar';
const VALID_MESSAGES_PANEL_MODES: ReadonlySet<TeamMessagesPanelMode> = new Set([
'sidebar',
'inline',
'bottom-sheet',
'floating-composer',
]);
export function loadPersistedMessagesPanelMode(): TeamMessagesPanelMode {
try {
const persisted = localStorage.getItem(MESSAGES_PANEL_MODE_STORAGE_KEY);
return VALID_MESSAGES_PANEL_MODES.has(persisted as TeamMessagesPanelMode)
? (persisted as TeamMessagesPanelMode)
: DEFAULT_MESSAGES_PANEL_MODE;
} catch {
return DEFAULT_MESSAGES_PANEL_MODE;
}
}
export function savePersistedMessagesPanelMode(mode: TeamMessagesPanelMode): void {
try {
localStorage.setItem(MESSAGES_PANEL_MODE_STORAGE_KEY, mode);
} catch {
// ignore - best-effort UI preference persistence
}
}
export function getCurrentProvisioningProgressForTeam(
state: Pick<TeamSlice, 'currentProvisioningRunIdByTeam' | 'provisioningRuns'>,

View file

@ -0,0 +1,29 @@
import type { TeamMessagesPanelMode } from '@renderer/types/teamMessagesPanelMode';
const MESSAGES_PANEL_MODE_STORAGE_KEY = 'team:messagesPanelMode';
const DEFAULT_MESSAGES_PANEL_MODE: TeamMessagesPanelMode = 'sidebar';
const VALID_MESSAGES_PANEL_MODES: ReadonlySet<TeamMessagesPanelMode> = new Set([
'sidebar',
'inline',
'bottom-sheet',
'floating-composer',
]);
export function loadPersistedMessagesPanelMode(): TeamMessagesPanelMode {
try {
const persisted = localStorage.getItem(MESSAGES_PANEL_MODE_STORAGE_KEY);
return VALID_MESSAGES_PANEL_MODES.has(persisted as TeamMessagesPanelMode)
? (persisted as TeamMessagesPanelMode)
: DEFAULT_MESSAGES_PANEL_MODE;
} catch {
return DEFAULT_MESSAGES_PANEL_MODE;
}
}
export function savePersistedMessagesPanelMode(mode: TeamMessagesPanelMode): void {
try {
localStorage.setItem(MESSAGES_PANEL_MODE_STORAGE_KEY, mode);
} catch {
// ignore - best-effort UI preference persistence
}
}

View file

@ -0,0 +1,67 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import {
loadPersistedMessagesPanelMode,
savePersistedMessagesPanelMode,
} from '../../../src/renderer/store/team/teamMessagesPanelModePersistence';
import type { TeamMessagesPanelMode } from '../../../src/renderer/types/teamMessagesPanelMode';
const STORAGE_KEY = 'team:messagesPanelMode';
describe('teamMessagesPanelModePersistence', () => {
beforeEach(() => {
window.localStorage.clear();
});
afterEach(() => {
vi.restoreAllMocks();
});
it('defaults to sidebar when no value was persisted', () => {
expect(loadPersistedMessagesPanelMode()).toBe('sidebar');
});
it('loads each supported persisted mode', () => {
const modes: TeamMessagesPanelMode[] = [
'sidebar',
'inline',
'bottom-sheet',
'floating-composer',
];
for (const mode of modes) {
window.localStorage.setItem(STORAGE_KEY, mode);
expect(loadPersistedMessagesPanelMode()).toBe(mode);
}
});
it('falls back to sidebar for invalid persisted values', () => {
window.localStorage.setItem(STORAGE_KEY, 'bad-mode');
expect(loadPersistedMessagesPanelMode()).toBe('sidebar');
});
it('persists the selected mode', () => {
savePersistedMessagesPanelMode('inline');
expect(window.localStorage.getItem(STORAGE_KEY)).toBe('inline');
});
it('falls back to sidebar when localStorage read fails', () => {
vi.spyOn(Storage.prototype, 'getItem').mockImplementation(() => {
throw new Error('blocked');
});
expect(loadPersistedMessagesPanelMode()).toBe('sidebar');
});
it('ignores localStorage write failures', () => {
vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => {
throw new Error('blocked');
});
expect(() => savePersistedMessagesPanelMode('bottom-sheet')).not.toThrow();
});
});