Skip to content

Reach every recording a fault kept, not just the newest - #95

Merged
mfaferek93 merged 5 commits into
feature/scripts-e2efrom
feat/620-multi-rosbag-ui
Aug 20, 2026
Merged

Reach every recording a fault kept, not just the newest#95
mfaferek93 merged 5 commits into
feature/scripts-e2efrom
feat/620-multi-rosbag-ui

Conversation

@mfaferek93

Copy link
Copy Markdown
Contributor

Summary

ros2_medkit#620 lets one fault hold several black-box recordings instead of overwriting on every re-confirmation. This is the web UI side of that: the extra recordings have to be visible, distinguishable and downloadable, and three existing behaviours got in the way.

Verified in a browser against a real gateway holding two real bags produced by the real capture pipeline. Every fix below has a spec that fails without it - all three specs go red when the source changes are reverted.

What was wrong

  • The fault detail was fetched once per fault and cached forever. A recording written while the page was open stayed invisible until the component remounted, which is exactly the recording a technician watching a machine fault again is waiting for. It now refetches on expand; the previous entry stays rendered meanwhile, so re-expanding does not flicker.
  • The dashboard keyed that cache by fault code alone. It lists faults from every entity at once, and a fault code is only unique within one entity, so two apps both reporting LIDAR_RANGE_INVALID rendered each other's environment data - download buttons pointing at another entity's recordings. The key now includes the entity. This was reachable before #620; several recordings per fault only make it easier to hit.
  • The download buttons had no accessible name at all. The icon variant renders no text, so a fault with N recordings became N nameless identical buttons: unusable with a screen reader, ambiguous with a mouse. Each is now named after the recording it fetches.
  • The saved file lost its extension. The filename came from the descriptor's display label (<id> recording <timestamp>) rather than from the gateway's Content-Disposition, so a bag landed on disk with no .mcap and neither the OS nor ros2 bag play could open it without a rename. The server is the only party that knows the storage format, so its name is the one to use; this also drops a listing round-trip per download.

Testing

  • e2e/rosbag-recordings.spec.ts - three specs in a real browser: the detail shows every recording with distinct names, each downloads as its own bag with a real extension, and re-expanding refetches. Reverting the source changes turns all three red.
  • e2e/docker-compose.rosbag.yml - a stack with a fault manager, which the scripts stack does not run, plus a seed that confirms, acknowledges and re-confirms one fault so it ends up owning two bags.
  • src/lib/store-download.test.ts - the Content-Disposition parser, including the RFC 5987 form and the empty-filename case that an earlier draft got wrong.
  • Full suite: 625 unit tests, lint and typecheck clean.

Ordering

  • Based on Add a Playwright end-to-end harness with a containerised gateway #91 to reuse its Playwright harness rather than stand up a second one. Nothing in that PR is modified here.
  • The specs assert the recording-id contract from ros2_medkit#620, which is newer than any published gateway tag. They skip with a named reason until an image carrying it exists; point E2E_ROSBAG_GATEWAY_IMAGE at a local build to run them now.

A fault can now hold several black-box recordings. The detail refetches on
expand so one written while the page is open is reachable, the dashboard keys
its cache by entity as well as code so two entities reporting the same code
stop showing each other's evidence, each download button names its recording,
and the saved file keeps the extension the gateway put on it.

Adds a Playwright stack with a fault manager and specs covering all of it.
Distinct filenames alone would pass on a build that resolved both ids to one
recording and labelled the responses differently.
A fetch in beforeAll threw before the skip guard could run, so CI went red on a
missing fixture rather than reporting it as skipped.

@bburda bburda left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Three things outside this diff that I think also need a change:

  • CONTRIBUTING.md still describes one stack. The new stack, the separate compose project name, the image override and the seeding step are not written down anywhere, so nobody can reproduce the run from the repo. It also tells developers to move the gateway to port 8081 when 8080 is taken, and that is the port the new stack takes by default.
  • The CI workflow only starts the old stack, so npm run test:e2e runs the new project and reports three skips. They show up as skipped, but nothing fails. Skipping is the right behaviour until the gateway change lands, but could you wire the stack into CI in the same change that pins the published image, so these specs do not stay dormant after that?
  • Nothing that runs in CI covers the two behaviour fixes (the entity aware cache key, the refetch on expand). There is no test file for FaultsDashboard or FaultsPanel. I wrote three vitest cases while reading this and all three reproduce the problems flagged inline, so they are cheap to cover.

Comment thread e2e/rosbag-recordings.spec.ts Outdated
Comment thread e2e/gateway/seed_recordings.py Outdated
Comment thread e2e/docker-compose.rosbag.yml
Comment thread e2e/docker-compose.rosbag.yml Outdated
Comment thread e2e/docker-compose.rosbag.yml
Comment thread src/components/FaultsDashboard.tsx Outdated
Comment thread src/components/FaultsDashboard.tsx Outdated
Comment thread src/components/FaultsDashboard.tsx Outdated
Comment thread src/components/FaultsPanel.tsx Outdated
Comment thread src/lib/store.ts Outdated
Per-entity faultKey shared by the dashboard and the entity panel - expand,
loading, clearing and the detail cache no longer tie colliding codes
together, clear takes the Fault, and expansion opens before the refetch
without blanking cached evidence on a 404. RFC 8187 charset+language
filename parsing. The e2e stack gets its own compose project, sources ROS
in the parent shell, runs the seeder as a watched job, and the seeder
survives for discovery and checks both service responses.
Brought the stack up for real: '&' still bound the whole
'source && source && fault_manager' chain, so the gateway leg ran
unsourced and exited 127. Semicolons scope each '&' to one command.
Verified live: all three jobs up, two recordings seeded, specs' data
visible in the browser.
@mfaferek93
mfaferek93 merged commit 440aafe into feature/scripts-e2e Aug 20, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants