From 1aa9cb7504a7b8329d44940e617461c0e96d40ca Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 6 Aug 2026 01:01:53 +0000 Subject: [PATCH] fix(web): route pixel_mapper_config into display.hardware; guard time-picker registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pixel_mapper_config was the only display.hardware key absent from both the display_fields detection allowlist and the hardware write loop in the settings save path. No form posts it today, but if one ever did the key would fall through to the generic handler and land at the TOP level of config.json — where state_reconciliation would mistake it for a missing plugin id and loop auto-repair attempts (the failure class the 'github'/'youtube' exclusion comment documents). It now round-trips into display.hardware like its siblings. time-picker.js gains the same LEDMatrixWidgets-undefined guard its two sibling widgets already have; correct today only via defer ordering. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01SXb4mKcAkVaxkeTb3YnAdr --- web_interface/blueprints/api_v3.py | 5 +++-- web_interface/static/v3/js/widgets/time-picker.js | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/web_interface/blueprints/api_v3.py b/web_interface/blueprints/api_v3.py index 9b4fec57..cd3a8cd2 100644 --- a/web_interface/blueprints/api_v3.py +++ b/web_interface/blueprints/api_v3.py @@ -807,7 +807,7 @@ def save_main_config(): 'gpio_slowdown', 'rp1_rio', 'scan_mode', 'disable_hardware_pulsing', 'inverse_colors', 'show_refresh_rate', 'pwm_bits', 'pwm_dither_bits', 'pwm_lsb_nanoseconds', 'limit_refresh_rate_hz', 'use_short_date_format', 'max_dynamic_duration_seconds', 'led_rgb_sequence', 'multiplexing', 'panel_type', - 'row_address_type'] + 'row_address_type', 'pixel_mapper_config'] if any(k in data for k in display_fields): if 'display' not in current_config: @@ -850,7 +850,8 @@ def save_main_config(): # Handle hardware settings for field in ['rows', 'cols', 'chain_length', 'parallel', 'brightness', 'hardware_mapping', 'scan_mode', 'pwm_bits', 'pwm_dither_bits', 'pwm_lsb_nanoseconds', 'limit_refresh_rate_hz', - 'led_rgb_sequence', 'multiplexing', 'panel_type', 'row_address_type']: + 'led_rgb_sequence', 'multiplexing', 'panel_type', 'row_address_type', + 'pixel_mapper_config']: if field in data: if field in ['rows', 'cols', 'chain_length', 'parallel', 'brightness', 'scan_mode', 'pwm_bits', 'pwm_dither_bits', 'pwm_lsb_nanoseconds', 'limit_refresh_rate_hz', diff --git a/web_interface/static/v3/js/widgets/time-picker.js b/web_interface/static/v3/js/widgets/time-picker.js index bf8b7636..30366022 100644 --- a/web_interface/static/v3/js/widgets/time-picker.js +++ b/web_interface/static/v3/js/widgets/time-picker.js @@ -57,6 +57,11 @@ target.appendChild(frag); } + if (typeof window.LEDMatrixWidgets === 'undefined') { + console.error('[TimePicker] LEDMatrixWidgets registry not loaded'); + return; + } + window.LEDMatrixWidgets.register('time-picker', { name: 'Time Picker Widget', version: '1.0.0',