diff --git a/CHANGELOG.md b/CHANGELOG.md index f5ff1df..4fcd261 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,12 @@ The application version is maintained in `package.json` and displayed in the adm No changes recorded yet. +## 1.12.1 - 2026-09-10 + +### Fixed + +- Clicking a race-audio "Test" button (either the general one, or a per-event one in the sound table) saved the settings form to the database on every click, including any other unsaved edits sitting in the form at the time. Testing a sound is now purely a local preview - it still uses whatever's currently in the form, but no longer writes it to the database. The database is written only when you press Save, or edit a field directly (unchanged). + ## 1.12.0 - 2026-09-10 ### Changed diff --git a/ROADMAP.md b/ROADMAP.md index 722d02f..9cfe60f 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -279,6 +279,15 @@ Requested 2026-09-10 by the user: the Settings view stacked all eleven panel sec Verified 2026-09-10: a full headless-browser check against a real, isolated server confirmed exactly 4 tabs render, only the Connection tab's panels (including the out-of-order Managed AMMC section) are visible by default, clicking each tab shows that tab's controls and hides the others (decoder form, race-sounds table, track layouts, OBS config, storage/export, clear-data buttons, race presets all checked by id), every previously-existing control id is still present in the DOM after the restructure (nothing dropped), and the chosen tab survives switching to another view via the app's real sidebar navigation and back. The full existing `tests:browser` suite (all pre-existing browser regression coverage, including the decoder-settings test that already exercises the `wsUrl` field inside the now-tabbed Connection panel) was also re-run and passed unchanged. +## Race-audio "Test" button was silently saving to the database + +Reported 2026-09-10 by the user, noticed right after the settings-tabs restructure: clicking a "Test" button next to the race-sound settings (the general one, or a per-event one in the sound table) showed the app's own "Ändringar sparade" (changes saved) status - a plain sound preview shouldn't write to the database at all. + +- [x] Root cause (`src/settings.js`): `testRaceAudio` (used by both `settingsRaceAudioTest` and every `[data-test-race-audio]` button) called `persistRaceAudioFormValues`, which both applies the form's current values to `state.settings.raceAudio` *and* calls `saveState()` (localStorage + a scheduled backend/SQLite sync). Reading the form's current, possibly-still-unsaved values was the point (so a test plays what you're about to save), but persisting them wasn't supposed to be part of that. The legacy (non-race-audio) test buttons never had this problem - they already only applied form values in memory (`applyAudioFormValues`, no `saveState()` call). +- [x] Split `persistRaceAudioFormValues` into `applyRaceAudioFormValuesFromDom` (apply only, in memory) and `persistRaceAudioFormValues` (apply + `saveState()`, unchanged for its existing callers). `testRaceAudio` now calls only the apply-only variant. The explicit "Save" button and the auto-save-on-change listener on every race-audio field are untouched and still persist as before - only the "Test" buttons stopped writing to the database. + +Verified 2026-09-10: a headless-browser check against a real, isolated server confirmed both the general race-sounds "Test" button and a per-event "Test" button in the sound table no longer issue a `POST /api/state` (watched over the real network layer, not just state inspection), while the "Save" button and directly editing a race-audio field (e.g. toggling mute) both still do, exactly as before. + ## Documentation maintenance - [ ] Update the architecture's module/dependency inventory as modules change. diff --git a/package-lock.json b/package-lock.json index 04d9e3c..9359238 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "rc-racecore", - "version": "1.12.0", + "version": "1.12.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "rc-racecore", - "version": "1.12.0", + "version": "1.12.1", "hasInstallScript": true, "dependencies": { "better-sqlite3": "^12.11.1", diff --git a/package.json b/package.json index 3d67d70..feda13f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "rc-racecore", - "version": "1.12.0", + "version": "1.12.1", "private": true, "description": "RC RaceCore live timing and race control with AMMC ingest and SQLite persistence", "engines": { diff --git a/src/settings.js b/src/settings.js index e760b0a..ce508d0 100644 --- a/src/settings.js +++ b/src/settings.js @@ -659,11 +659,16 @@ Erik Eriksson;654321;4WD;Associated;; }); }; - const persistRaceAudioFormValues = () => { + const applyRaceAudioFormValuesFromDom = () => { const formNode = document.getElementById("settingsForm"); if (!(formNode instanceof HTMLFormElement)) return false; applyRaceAudioFormValues(new FormData(formNode)); state.settings.audioEnabled = state.settings.audioEnabled || state.settings.raceAudio.enabled; + return true; + }; + + const persistRaceAudioFormValues = () => { + if (!applyRaceAudioFormValuesFromDom()) return false; saveState(); return true; }; @@ -755,7 +760,10 @@ Erik Eriksson;654321;4WD;Associated;; }); document.getElementById("settingsSaveRaceAudio")?.addEventListener("click", persistRaceAudioFormValues); const testRaceAudio = (eventKey) => { - persistRaceAudioFormValues(); + // Uses whatever's currently in the form (including unsaved edits) so a test preview + // matches what you're about to hear - but a test playback is not itself a reason to + // write those still-unsaved changes to the database. Use the explicit Save button for that. + applyRaceAudioFormValuesFromDom(); triggerRaceAudio(eventKey, { force: true, interrupt: true, variables: { driverName: state.drivers[0]?.name || "Driver", lapTime: "16.000", marshalPost: "1", transponder: "123", podium: "P1, P2, P3" } }); }; document.getElementById("settingsRaceAudioTest")?.addEventListener("click", () => testRaceAudio("audio_test"));