fix(ui): default project sorting to manual
This commit is contained in:
@@ -67,6 +67,8 @@ Shared safe storage treats durable failures per key. A quota or access failure c
|
||||
|
||||
Project and UI settings use successful settings synchronization as authority. Omitted fields in a complete snapshot reset to canonical client defaults, including an omitted project list becoming empty; transport or settings-load failure dispatches no synchronization event and preserves current state. Settings save responses are partial patches and must not clear unrelated in-memory preferences or local mirrors.
|
||||
|
||||
Project ordering defaults to manual. Session display persistence v3 migrates the previously shipped `recent` project order to `manual` while preserving every other explicit sort mode.
|
||||
|
||||
Session folders persist in runtime-specific v2 browser keys without silently evicting older runtime namespaces. Runtime switch, page hide, app freeze, and unload synchronously flush the pending browser snapshot before lifecycle suspension or namespace replacement. A runtime switch then cancels stale old-runtime disk work and starts generation-owned disk hydration. Missing or malformed server files are not authoritative empty snapshots; disk data may replace browser state only when it carries a real revision and no newer local folder mutation occurred. Server writes are serialized and reject non-newer revisions so delayed or duplicate requests cannot overwrite the current state. File-search cache and in-flight keys include runtime plus directory and are cleared on endpoint reset.
|
||||
|
||||
Persisted session todos use a bounded composite key of runtime, normalized directory, and session ID. Ambiguous legacy todo entries are discarded rather than claimed by whichever runtime starts first. Authoritative deletion uses an explicit runtime identity, and session-folder deletion scans every scope in the active runtime so archived assignments cannot survive after their session is gone.
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import { migrateSessionDisplayState, useSessionDisplayStore } from './useSessionDisplayStore';
|
||||
|
||||
describe('useSessionDisplayStore project sorting', () => {
|
||||
test('defaults to manual ordering', () => {
|
||||
expect(useSessionDisplayStore.getState().projectSortOrder).toBe('manual');
|
||||
});
|
||||
|
||||
test('migrates the v2 recent default to manual', () => {
|
||||
const migrated = migrateSessionDisplayState({ projectSortOrder: 'recent' }, 2);
|
||||
|
||||
expect(migrated.projectSortOrder).toBe('manual');
|
||||
});
|
||||
|
||||
for (const projectSortOrder of ['manual', 'a-z', 'z-a', 'date-added'] as const) {
|
||||
test(`preserves the v2 ${projectSortOrder} sort order`, () => {
|
||||
const migrated = migrateSessionDisplayState({ projectSortOrder }, 2);
|
||||
|
||||
expect(migrated.projectSortOrder).toBe(projectSortOrder);
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -18,6 +18,23 @@ type SessionDisplayStore = {
|
||||
setProjectSortOrder: (order: ProjectSortOrder) => void;
|
||||
};
|
||||
|
||||
export const migrateSessionDisplayState = (
|
||||
persisted: unknown,
|
||||
version: number,
|
||||
): Partial<SessionDisplayStore> => {
|
||||
const state = (persisted ?? {}) as Partial<SessionDisplayStore>;
|
||||
if (version < 1) {
|
||||
return { ...state, displayMode: 'minimal', projectSortOrder: 'manual' };
|
||||
}
|
||||
if (version < 2) {
|
||||
return { ...state, projectSortOrder: 'manual' };
|
||||
}
|
||||
if (version < 3 && state.projectSortOrder === 'recent') {
|
||||
return { ...state, projectSortOrder: 'manual' };
|
||||
}
|
||||
return state;
|
||||
};
|
||||
|
||||
export const useSessionDisplayStore = create<SessionDisplayStore>()(
|
||||
persist(
|
||||
(set) => ({
|
||||
@@ -28,7 +45,7 @@ export const useSessionDisplayStore = create<SessionDisplayStore>()(
|
||||
// disappear once the persisted preference rehydrates. Users who opted into
|
||||
// showing archived have `true` persisted, which is preserved on rehydrate.
|
||||
showArchivedSessions: false,
|
||||
projectSortOrder: 'recent',
|
||||
projectSortOrder: 'manual',
|
||||
setDisplayMode: (mode) => set({ displayMode: mode }),
|
||||
setShowRecentSection: (show) => set({ showRecentSection: show }),
|
||||
setShowArchivedSessions: (show) => set({ showArchivedSessions: show }),
|
||||
@@ -38,21 +55,13 @@ export const useSessionDisplayStore = create<SessionDisplayStore>()(
|
||||
}),
|
||||
{
|
||||
name: 'session-display-mode',
|
||||
version: 2,
|
||||
version: 3,
|
||||
// v0 shipped 'default' as the only/initial mode, so most existing users
|
||||
// have it persisted by accident rather than choice. Nudge everyone onto
|
||||
// minimal once so the mode can be evaluated before removing it entirely.
|
||||
// v1→v2 adds projectSortOrder defaulting to 'recent'.
|
||||
migrate: (persisted, version) => {
|
||||
const state = (persisted ?? {}) as Partial<SessionDisplayStore>;
|
||||
if (version < 1) {
|
||||
return { ...state, displayMode: 'minimal', projectSortOrder: 'recent' };
|
||||
}
|
||||
if (version < 2) {
|
||||
return { ...state, projectSortOrder: 'recent' };
|
||||
}
|
||||
return state;
|
||||
},
|
||||
// v1→v2 adds projectSortOrder using the canonical manual ordering.
|
||||
// v2→v3 replaces the previously shipped recent default with manual.
|
||||
migrate: migrateSessionDisplayState,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user