hyperdxio / hyperdxio/hyperdx

Dashboard: setDashboard mutations clobber each other when fired back-to-back

Open
#2,216 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app bug
Dominant language
TypeScript
Stars
9.9k
Forks
471
Avg merge
2d 4h
Merged PRs (30d)
117

Description

Symptom

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.

packages/app/src/dashboard.ts:151-181 (setDashboard).
packages/app/src/dashboard.ts:213+ (useUpdateDashboard).

Fix options

  1. 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.
  2. Serialize mutations through a queue (mutation chain) so the second waits on the first.
  3. 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.
  • Existing in-page tests (PR #2205 lines 48, 78) keep passing.
  • The narrowed round-trip in PR #2205 (line 231) can be re-extended to include a bordered toggle on group A.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in packages/app/src/dashboard.ts:151-181 and inspect useUpdateDashboard at packages/app/src/dashboard.ts:213+. Read the DashboardContainer e2e coverage from PR #2205, especially lines 48, 78, and 231. Done means successive bordered-toggle and tab-add mutations both survive navigation away and back, while existing in-page tests pass.

Written by the indexing model from the issue text.

Assessment

Tech stack
react, typescript
Domain
frontend, observability
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.