Settings page: each card's Save sends the whole form, and a refetch can wipe unsaved edits #181
Labels
No labels
area/ai
area/backend
area/frontend
area/infra
area/scheduler
area/wled
good-first-issue
priority/high
priority/low
priority/medium
security
type/bug
type/chore
type/ci-cd
type/docs
type/feature
type/qa
v1.0.0
v1.1.0
v1.2.0
v2.0.0
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
rbrooks/Iris-WLED#181
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found while diagnosing #180's CI failure (it didn't cause it). Two related problems on
SettingsPage.tsx.1. Every card's Save sends all 46 keys
saveSettings()sends the entire form, not just the card's own fields. So saving the Watchdog card also writes the WLED host, the location, every schedule time, the AI provider, and everything else, as whatever this browser tab last loaded..envseeds can't take effect for any key (see Rhoving/iac-repo#527 §6.1), not just the one the person meant to change.Fix: each card sends only its own keys. The backend
set_all_settingsalready persists only the keys it's given.2. A refetch overwrites unsaved edits
The page copies
settingsinto local form state in auseEffectkeyed onsettings. When the settings query returns new data (a save from another tab or device, or an invalidation after some other mutation), the effect reruns and silently discards whatever the user has typed but not saved. React Query's structural sharing prevents this when nothing changed, so it only bites when something really did change.Fix: track dirty fields per card, and don't overwrite a field the user has edited since the last load. Optionally show "Settings changed elsewhere — reload?".
Tests
A vitest where a settings refetch with changed data arrives while a card has unsaved edits, and the edits survive. And a test that saving the Watchdog card sends only
watchdog_*keys.claude-bot referenced this issue2026-09-26 15:14:48 +00:00
Fixed in #180 (commit
6574b4c, squash-merged, CI green).Root cause, confirmed by instrumentation: the Settings page renders its cards before
GET /settingsreturns, and auseEffect([settings])copied every server value over the form when the response landed. An edit made during that window was silently lost, and Save sent the old values. It wasn't a remount or the service worker.Fix:
useDrafts/useDraft: a field the person has edited is never overwritten by a load or refetch.data: webhooks = []created a new array on every render, which re-rendered forever for viewers.Tests:
settingsDrafts.test.tsx(6 tests), shown to fail on the old page, and the watchdog E2E asserts the exact PUT body. 16 post-fix E2E runs under CPU limits had zero reverts.