let two windows onto the same dashboards agree again

The dashboard-state cache had staleTime: Infinity and there is no invalidateQueries anywhere in the
repo, so it was fetched once per page load and never again: two windows diverged permanently and neither
was ever told. It now refetches on focus — with three non-default guards, because this cache is
optimistic and a refetch that started before an in-flight PATCH landed would overwrite the value we
already showed. Never on mount (splitting a panel mounts a fresh consumer, which is exactly when a write
is in flight), never on reconnect, and on focus only after a short quiet period with nothing in flight.

The PATCH stopped assembling a full state blob it then returned to nobody — three SELECTs per splitter
release, thrown away, and a caller that did read it would be reading state assembled before whatever
concurrent write it raced.

And the last three `.catch(() => {})` in this family are gone: dashboard create, rename and delete build
their own multi-key patches and so bypass the hook. They now go through persistDashboardState, which
keeps the in-flight bookkeeping honest and, on failure, invalidates rather than reverts — there is no
single previous value to swap back once the roster has been rewritten, and a refetch is the only thing
that makes the list agree with the server. A failed delete used to leave the dashboard gone from the list
and alive on the server, reappearing at the next reload with no hint why.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-07 09:15:55 +00:00
co-authored by Claude Opus 5
parent b0a32ae473
commit 81ad3ef5ef
4 changed files with 85 additions and 18 deletions
+4 -2
View File
@@ -121,6 +121,8 @@ dashboardsRouter.patch('/', async (ctx) => {
return ctx.json({ error: `unknown dashboard-state key "${key}"` }, 400);
}
const state = await getAllDashboardState(userId);
return ctx.json(state);
// Three SELECTs per splitter release, thrown away — no caller has ever read this response body, and one
// that did would be reading a blob assembled *before* the concurrent write it raced. The client
// converges by refetching on focus instead (`useDashboardState`).
return ctx.json({ ok: true });
});