mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-04 06:15:09 +00:00
fix(web): plugin settings form shows schema defaults for unsaved keys (#597)
The server-rendered plugin settings partial rendered straight from the saved config, so an option added in a plugin update (geochron 1.2.0's show_date / show_date_line, default true) drew as an unchecked box, and the save route's missing-checkbox handling then stored it as false. Enum dropdowns likewise showed their first option instead of the default. - _load_plugin_config_partial runs the stored section through prepare_plugin_config (as GET /plugins/config does) before masking secrets, so a secret's schema default is masked too. - render_field falls back to the field's own default, covering children of objects that declare a default of their own (where the defaults extraction stops). - The legacy-boolean parity test now compares against the config the plugin actually runs with (defaults included). Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ _SAFE_WEB_UI_FILE_RE = re.compile(r'^[a-zA-Z0-9_-]{1,64}\.html$')
|
||||
_SAFE_WIDGET_NAME_RE = re.compile(r'^[a-zA-Z0-9_-]{1,64}$')
|
||||
_SAFE_WIDGET_SCRIPT_RE = re.compile(r'^[a-zA-Z0-9_-]{1,64}\.js$')
|
||||
from src.web_interface.secret_helpers import mask_secret_fields
|
||||
from src.plugin_system.schema_manager import plugin_config_defaults, prepare_plugin_config
|
||||
from src.common.path_safety import resolve_under, safe_path_component
|
||||
from src.pi5_matrix_support import is_raspberry_pi_5
|
||||
from web_interface import widget_bundle
|
||||
@@ -917,10 +918,25 @@ def _load_plugin_config_partial(plugin_id):
|
||||
except Exception as e:
|
||||
logger.warning("Could not load manifest for plugin: %s", e)
|
||||
|
||||
# Mask secret fields before rendering template (fail closed — never leak secrets)
|
||||
schema_properties = schema.get('properties') if isinstance(schema, dict) else None
|
||||
if not isinstance(schema_properties, dict):
|
||||
return '<div class="text-red-500 p-4">Error loading plugin config securely: schema unavailable.</div>', 500
|
||||
|
||||
# Fill in schema defaults for keys the saved config doesn't have yet,
|
||||
# as GET /api/v3/plugins/config does. Without this, an option added in
|
||||
# a plugin update (geochron 1.2.0's show_date, default true) renders
|
||||
# as an unchecked box, and because the save treats every drawn but
|
||||
# unposted checkbox as false, the first save turns it off for good.
|
||||
try:
|
||||
defaults = plugin_config_defaults(schema)
|
||||
if schema_mgr is not None:
|
||||
defaults = schema_mgr.apply_device_location(defaults)
|
||||
config = prepare_plugin_config(config, schema, defaults)
|
||||
except Exception as e:
|
||||
logger.warning("Could not merge schema defaults for %s: %s", plugin_id, e)
|
||||
|
||||
# Mask secret fields before rendering template (fail closed — never
|
||||
# leak secrets). After the merge, so a secret's default is masked too.
|
||||
config = mask_secret_fields(config, schema_properties)
|
||||
|
||||
# Determine enabled status
|
||||
|
||||
Reference in New Issue
Block a user