fix(web): partial JSON saves to /config/main change only what they send

A JSON body with one field reset every checkbox in the sections it touched:
the MQTT bridge's brightness slider turned off disable_hardware_pulsing,
inverse_colors, show_refresh_rate and use_short_date_format, and a
timezone-only save turned off web-UI autostart and weekly auto-updates.
Missing-means-unchecked now applies only to form posts: form-encoded bodies
and the v3 forms, which mark themselves with a hidden __form_section input.

Also on the config routes:
- vegas_min/max_cycle_duration no longer match the generic *_duration rule,
  so they stop landing in display_durations and a blank one no longer
  rejects the whole Display save;
- saving from the Raw JSON editor calls start_setup_if_needed like the
  General form, so enabling auto-update there finishes its setup;
- the schedule and dim-schedule POSTs accept the per-day days.<day> shape
  their GETs return, as well as the flat form keys.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-09-17 08:54:01 -04:00
co-authored by Claude Opus 5
parent a0e1ce6c6c
commit a49bd5c611
6 changed files with 387 additions and 39 deletions
@@ -34,6 +34,10 @@
class="space-y-6"
novalidate
onsubmit="fixInvalidNumberInputs(this); return true;">
{# Marks this post as the whole form, so an unchecked box saves as
false. Without it the save endpoint treats absent keys as unchanged
(FORM_SECTION_FIELD in api_v3/config.py). #}
<input type="hidden" name="__form_section" value="display">
<!-- Hardware Settings -->
<div class="bg-gray-50 rounded-lg p-4">
@@ -15,6 +15,8 @@
class="space-y-6"
novalidate
onsubmit="fixInvalidNumberInputs(this); return true;">
{# See general.html: identifies a whole-form post to /config/main. #}
<input type="hidden" name="__form_section" value="durations">
<!-- Primary rotation order: drag to reorder which plugin shows first,
second, ... in the normal display rotation. Saved as
@@ -30,6 +30,10 @@
showNotification(message, status);
"
class="space-y-6">
{# Marks this post as the whole form, so an unchecked box saves as
false. Without it the save endpoint treats absent keys as unchanged
(FORM_SECTION_FIELD in api_v3/config.py). #}
<input type="hidden" name="__form_section" value="general">
<!-- Web Display Autostart -->
<div class="form-group" id="setting-general-web_display_autostart" data-setting-key="web_display_autostart">