You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Dashboard: setDashboard mutations clobber each other when fired back-to-back #2216
Two setDashboard(...) calls in quick succession (eg. toggle bordered on group A, then add a tab to group B) can leave the backend with only the second mutation's effect. The first change appears to "save" in the UI but is lost on reload.
Surfaced while writing the DashboardContainer e2e round-trip in PR #2205. The save-and-reload test has been narrowed to a single mutation per step to work around this; the bordered-toggle round-trip is now covered only by the in-page test (PR #2205, line 78) and not by the navigate-away-and-back round-trip.
Root cause (confirmed via code reading)
setDashboard for a remote dashboard calls updateDashboard.mutate(newDashboard) (no optimistic cache update). The component still reads dashboard from the React Query cache until invalidateQueries -> refetch completes.
Two consecutive setDashboard(produce(dashboard, ...)) calls both produce from the same pre-mutation snapshot. Both PATCH /api/dashboards/{id}. The second PATCH overwrites the first because the body it sends derives from a snapshot that doesn't yet include the first mutation's change.
Optimistic update in useUpdateDashboard.onMutate: write the new dashboard into the cache immediately so the next produce derives from up-to-date state. Roll back in onError.
Serialize mutations through a queue (mutation chain) so the second waits on the first.
Switch the local component state to be the source of truth, with a debounced flush to the backend.
Option 1 is the smallest change and matches typical React Query patterns.
Acceptance
E2E test: toggle bordered on group A, add a tab to group B in succession, navigate away, navigate back. Both changes survive.
Picking this up. Confirmed the root cause: useUpdateDashboard has no optimistic cache update, so dashboard (read from the ['dashboards'] React Query cache) stays stale until refetch, and two consecutive setDashboard(produce(dashboard, ...)) calls both derive from the same pre-mutation snapshot — the second PATCH clobbers the first. Implementing Option 1 (optimistic update in onMutate writing the merged dashboard into the cache, rollback in onError, invalidate in onSettled) so the next produce sees up-to-date state. PR incoming with unit tests.
Activity
test(e2e): cover unified DashboardContainer (collapse, border, tabs, …
rachit367 commentedon Jul 2, 2026
Picking this up. Confirmed the root cause:
useUpdateDashboardhas no optimistic cache update, sodashboard(read from the['dashboards']React Query cache) stays stale until refetch, and two consecutivesetDashboard(produce(dashboard, ...))calls both derive from the same pre-mutation snapshot — the second PATCH clobbers the first. Implementing Option 1 (optimistic update inonMutatewriting the merged dashboard into the cache, rollback inonError, invalidate inonSettled) so the nextproducesees up-to-date state. PR incoming with unit tests.test(app): strengthen dashboard optimistic-update coverage