Fix race-audio Test buttons silently saving settings to the database

Clicking a Test button (general or per-event) in the race-sounds table
called persistRaceAudioFormValues, which both applied the form's
current values and saved them to the backend on every click. A sound
preview should only apply values in memory, not persist them - split
into an apply-only helper used by the Test buttons, keeping the
existing save behavior for the explicit Save button and field changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
larssand
2026-09-10 19:28:46 +02:00
parent cc9f5c380b
commit f988ad2690
5 changed files with 28 additions and 5 deletions

View File

@@ -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

View File

@@ -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.

4
package-lock.json generated
View File

@@ -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",

View File

@@ -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": {

View File

@@ -659,11 +659,16 @@ Erik Eriksson;654321;4WD;Associated;;</code></pre>
});
};
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;;</code></pre>
});
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"));