mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-06 15:39:41 +02:00
COD-131 sync tab order across devices via server state
Tab reordering (drag-and-drop + Ctrl+Shift+{/}) persisted only to
localStorage (codeman-session-order), so each device kept its own private
order. Add server-side persistence so the order follows the user across
devices, live. Takes the issue's recommended default (a): one global order,
server authoritative, localStorage as offline fallback.
- session-order.ts (new, pure + unit-tested): normalizeSessionOrder (coerce
to string[], drop empty/non-string, dedup) and mergeSessionOrder (the
pushing device's order wins; ids the device hadn't loaded fall to the end
in their existing relative order, never dropped — graceful for
closed/remote/parked sessions absent on that device).
- AppState.sessionOrder?: string[]; StateStore get/setSessionOrder + the field
added to buildPartialJson() (the incremental serializer whitelists fields,
so without this the value never reached disk / survived a restart).
- PUT /api/session-order (session-routes): parse -> merge -> persist ->
broadcast session:orderChanged; getLightState() init snapshot now carries
sessionOrder so a fresh load/reconnect restores it.
- SSE event session:orderChanged registered in sse-events.ts + constants.js.
- app.js: handleInit seeds localStorage from the server snapshot before
syncSessionOrder(); saveSessionOrder() also PUTs to the server (debounced
400ms, covers drag + both keyboard moves); _onSessionOrderChanged adopts a
remote order and re-renders (no-op-guarded to avoid echo flicker).
Verified (orchestrator re-ran all gates): tsc 0, lint 0, frontend-syntax +
prettier clean, build ok; session-order + session-order-routes + state-store
56/56. Functional round-trip on an isolated beta: PUT {a,b,c} -> status
snapshot reflects it; merge PUT {c,a} vs {a,b,c} -> {c,a,b} (b preserved at
end); malformed payload rejected with a clean 400; sessionOrder persisted to
state.json and survived a restart.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 79415f2fdfbdf3fbe362a063534e7f84c553eefb)
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
6f4b2b8a17
commit
8807b3ff6d
@@ -21,6 +21,10 @@ export function createMockRouteContext(options?: { sessionId?: string }) {
|
||||
const sessions = new Map<string, MockSession>();
|
||||
sessions.set(sessionId, session);
|
||||
|
||||
// Stateful backing for the global tab order (COD-131) so route tests can
|
||||
// assert that setSessionOrder() actually persists what the handler computed.
|
||||
let sessionOrder: string[] = [];
|
||||
|
||||
return {
|
||||
// -- SessionPort --
|
||||
sessions,
|
||||
@@ -65,6 +69,10 @@ export function createMockRouteContext(options?: { sessionId?: string }) {
|
||||
load: vi.fn(),
|
||||
incrementSessionsCreated: vi.fn(),
|
||||
setConfig: vi.fn(),
|
||||
getSessionOrder: vi.fn(() => sessionOrder),
|
||||
setSessionOrder: vi.fn((order: string[]) => {
|
||||
sessionOrder = order;
|
||||
}),
|
||||
getAggregateStats: vi.fn(() => ({ totalInputTokens: 0, totalOutputTokens: 0, totalCost: 0 })),
|
||||
getGlobalStats: vi.fn(() => ({ sessionsCreated: 0 })),
|
||||
getDailyStats: vi.fn(() => []),
|
||||
|
||||
Reference in New Issue
Block a user