Settings: a failed save can be retried, and says what is happening #275

Merged
robbertbos merged 1 commit from settings-retry into main 2026-08-09 21:05:58 +00:00
Owner

Closes the last open item in #208, plus three things found next to it while
testing.

The item from #208

Voorkeuren and Automatisch opruimen save on change, with no submit button. So a
failed save left nothing to press: picking the same value again fires no change
event, and reloading was the only way back. The banner said "Probeer het
opnieuw" without offering the means.

Each panel now keeps the last patch it sent, and the banner offers it back
through nldd-banner's own actions slot.

Found while testing, not in #208

Automatisch opruimen showed nothing at all when a save failed - the same
silence #201 fixed for Voorkeuren. It was never passed failed. It also had no
live region, so a screen reader heard none of this either. Both fixed, with the
tests it never had.

Both panels shared one mutation, so they shared its state: changing a theme
put "Opslaan..." under Automatisch opruimen as well, and a failure would have
shown the notice in a panel the user never touched. One saver per panel now, so
the state cannot leak rather than being filtered afterwards. Settings.vue gets
the test it never had; it fails on the shared-mutation version.

Offline said "Opslaan..." forever. TanStack pauses a mutation instead of
running it (networkMode: 'online'), so nothing was being saved and no error
would ever arrive - the retry button could not appear by construction. That
state now says "Wachten op verbinding...".

The save notice

  • It flashed on every change. It now waits a second - the point where a delay
    stops feeling instant, and the same hold-back nldd-activity-indicator uses.
  • It sat at the foot of the card, so it belonged to whichever of the three
    fields you last touched. Each field carries its own now, and only the one
    being saved speaks.
  • It kept the meta font size and secondary colour, so it whispered. It appears
    only when something is slow or stuck, so it takes the content tier - which in
    this repo means no size rule at all.
  • The spinner is nldd-activity-indicator, which needs a box of its own:
    measured at 518x518 when left to fill its parent, 20x20 once given one. Its
    own 1000ms hold-back is off, since the delay is already ours.

The banner drops its full stop: "Opslaan mislukt" is a fragment, and the other
fragment-shaped notice in the app has none either.

Verification

  • 764 frontend unit tests, vue-tsc, eslint 0 errors, the full e2e suite
    (67 passed, 3 skipped), uvx pre-commit run --all-files including the
    generated-API-types gate.
  • Driven in a browser with a delayed PUT /api/settings: exactly one live
    region speaks, and it is the field that was changed.
  • No backend change.
Closes the last open item in #208, plus three things found next to it while testing. ## The item from #208 Voorkeuren and Automatisch opruimen save on change, with no submit button. So a failed save left nothing to press: picking the same value again fires no change event, and reloading was the only way back. The banner said "Probeer het opnieuw" without offering the means. Each panel now keeps the last patch it sent, and the banner offers it back through `nldd-banner`'s own `actions` slot. ## Found while testing, not in #208 **Automatisch opruimen showed nothing at all when a save failed** - the same silence #201 fixed for Voorkeuren. It was never passed `failed`. It also had no live region, so a screen reader heard none of this either. Both fixed, with the tests it never had. **Both panels shared one mutation**, so they shared its state: changing a theme put "Opslaan..." under Automatisch opruimen as well, and a failure would have shown the notice in a panel the user never touched. One saver per panel now, so the state cannot leak rather than being filtered afterwards. `Settings.vue` gets the test it never had; it fails on the shared-mutation version. **Offline said "Opslaan..." forever.** TanStack pauses a mutation instead of running it (`networkMode: 'online'`), so nothing was being saved and no error would ever arrive - the retry button could not appear by construction. That state now says "Wachten op verbinding...". ## The save notice - It flashed on every change. It now waits a second - the point where a delay stops feeling instant, and the same hold-back `nldd-activity-indicator` uses. - It sat at the foot of the card, so it belonged to whichever of the three fields you last touched. Each field carries its own now, and only the one being saved speaks. - It kept the meta font size and secondary colour, so it whispered. It appears only when something is slow or stuck, so it takes the content tier - which in this repo means no size rule at all. - The spinner is `nldd-activity-indicator`, which needs a box of its own: measured at 518x518 when left to fill its parent, 20x20 once given one. Its own 1000ms hold-back is off, since the delay is already ours. The banner drops its full stop: "Opslaan mislukt" is a fragment, and the other fragment-shaped notice in the app has none either. ## Verification - 764 frontend unit tests, `vue-tsc`, eslint 0 errors, the full e2e suite (67 passed, 3 skipped), `uvx pre-commit run --all-files` including the generated-API-types gate. - Driven in a browser with a delayed `PUT /api/settings`: exactly one live region speaks, and it is the field that was changed. - No backend change.
robbertbos changed title from Settings: a failed save can be retried to Settings: a failed save can be retried, and says what is happening 2026-08-09 20:55:39 +00:00
robbertbos force-pushed settings-retry from cc8261564a
Some checks failed
CI / release-scripts (pull_request) Successful in 6s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 15s
security-scan / SBOM (trivy) (pull_request) Successful in 11s
security-scan / JS SCA (npm audit) (pull_request) Successful in 17s
security-scan / Python SAST (bandit) (pull_request) Successful in 22s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 42s
CI / pre-commit (pull_request) Successful in 50s
test-build / build (frontend) (pull_request) Successful in 58s
test-build / build (backend) (pull_request) Successful in 1m1s
test-build / build (pull_request) Successful in 0s
CI / frontend-test (pull_request) Failing after 1m6s
CI / e2e (pull_request) Successful in 2m17s
CI / backend-test (pull_request) Successful in 2m9s
to cfa8249bd0
All checks were successful
CI / release-scripts (pull_request) Successful in 6s
security-scan / SBOM (trivy) (pull_request) Successful in 11s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 14s
security-scan / JS SCA (npm audit) (pull_request) Successful in 19s
security-scan / Python SAST (bandit) (pull_request) Successful in 20s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 39s
CI / pre-commit (pull_request) Successful in 53s
test-build / build (frontend) (pull_request) Successful in 1m5s
test-build / build (backend) (pull_request) Successful in 1m7s
CI / frontend-test (pull_request) Successful in 1m8s
test-build / build (pull_request) Successful in 0s
CI / backend-test (pull_request) Successful in 2m8s
CI / e2e (pull_request) Successful in 2m19s
CI / release-scripts (push) Successful in 7s
security-scan / SBOM (trivy) (push) Successful in 12s
security-scan / Filesystem scan (trivy fs) (push) Successful in 15s
security-scan / JS SCA (npm audit) (push) Successful in 17s
security-scan / Python SAST (bandit) (push) Successful in 19s
security-scan / Python SCA (pip-audit) (push) Successful in 40s
CI / pre-commit (push) Successful in 1m1s
publish-main / build (frontend) (push) Successful in 1m1s
publish-main / build (backend) (push) Successful in 1m7s
publish-main / build (push) Successful in 0s
CI / frontend-test (push) Successful in 1m12s
CI / backend-test (push) Successful in 2m17s
CI / e2e (push) Successful in 2m26s
2026-08-09 21:01:56 +00:00
Compare
robbertbos deleted branch settings-retry 2026-08-09 21:05:58 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
robbertbos/waggle!275
No description provided.