gabotorresruiz commented on code in PR #35220:
URL: https://github.com/apache/superset/pull/35220#discussion_r2391861954
##########
superset/views/base.py:
##########
@@ -311,66 +313,86 @@ def menu_data(user: User) -> dict[str, Any]:
}
+def _merge_theme_dicts(base: dict[str, Any], overlay: dict[str, Any]) ->
dict[str, Any]:
+ """
+ Recursively merge overlay theme dict into base theme dict.
+ Arrays and non-dict values are replaced, not merged.
+ """
+ result = base.copy()
+ for key, value in overlay.items():
+ if isinstance(result.get(key), dict) and isinstance(value, dict):
+ result[key] = _merge_theme_dicts(result[key], value)
+ else:
+ result[key] = value
+ return result
+
+
+def _load_theme_from_model(
+ theme_model: ThemeModel | None,
+ fallback_theme: Theme | None,
+ theme_type: str,
+) -> Theme | None:
+ """Load and parse theme from database model, merging with config theme as
base."""
+ if theme_model:
+ try:
+ db_theme = json.loads(theme_model.json_data)
+ if fallback_theme:
+ merged = _merge_theme_dicts(dict(fallback_theme), db_theme)
+ return cast(Theme, merged)
+ return db_theme
+ except json.JSONDecodeError:
+ logger.error(
+ "Invalid JSON in system %s theme %s", theme_type,
theme_model.id
+ )
+ return fallback_theme
+ return fallback_theme
+
+
+def _process_theme(theme: Theme | None, theme_type: str) -> Theme:
+ """Process and validate a theme, returning an empty dict if invalid."""
+ if theme is None or theme == {}:
+ # When config theme is None or empty, don't provide a custom theme
+ # The frontend will use base theme only
+ return {}
+ elif not is_valid_theme(cast(dict[str, Any], theme)):
+ logger.warning(
+ "Invalid %s theme configuration: %s, clearing it",
+ theme_type,
+ theme,
+ )
+ return {}
+ return theme or {}
+
+
def get_theme_bootstrap_data() -> dict[str, Any]:
"""
Returns the theme data to be sent to the client.
"""
# Check if UI theme administration is enabled
enable_ui_admin = app.config.get("ENABLE_UI_THEME_ADMINISTRATION", False)
+ # Get config themes to use as fallback
+ config_theme_default = get_config_value("THEME_DEFAULT")
+ config_theme_dark = get_config_value("THEME_DARK")
+
if enable_ui_admin:
# Try to load themes from database
default_theme_model = ThemeDAO.find_system_default()
dark_theme_model = ThemeDAO.find_system_dark()
# Parse theme JSON from database models
- default_theme = {}
- if default_theme_model:
- try:
- default_theme = json.loads(default_theme_model.json_data)
- except json.JSONDecodeError:
- logger.error(
- "Invalid JSON in system default theme %s",
- default_theme_model.id,
- )
- # Fallback to config
- default_theme = get_config_value("THEME_DEFAULT")
- else:
- # No system default theme in database, use config
- default_theme = get_config_value("THEME_DEFAULT")
-
- dark_theme = {}
- if dark_theme_model:
- try:
- dark_theme = json.loads(dark_theme_model.json_data)
- except json.JSONDecodeError:
- logger.error(
- "Invalid JSON in system dark theme %s", dark_theme_model.id
- )
- # Fallback to config
- dark_theme = get_config_value("THEME_DARK")
- else:
- # No system dark theme in database, use config
- dark_theme = get_config_value("THEME_DARK")
- else:
- # UI theme administration disabled, use config-based themes
- default_theme = get_config_value("THEME_DEFAULT")
- dark_theme = get_config_value("THEME_DARK")
-
- # Validate theme configurations
- if not is_valid_theme(default_theme):
- logger.warning(
- "Invalid default theme configuration: %s, using empty theme",
- default_theme,
+ default_theme = _load_theme_from_model(
+ default_theme_model, config_theme_default, "default"
)
- default_theme = {}
+ dark_theme = _load_theme_from_model(dark_theme_model,
config_theme_dark, "dark")
+ else:
+ # UI theme administration disabled - use config-based themes
+ default_theme = config_theme_default
+ dark_theme = config_theme_dark
- if not is_valid_theme(dark_theme):
- logger.warning(
- "Invalid dark theme configuration: %s, using empty theme",
- dark_theme,
- )
- dark_theme = {}
+ # Process and validate themes
+ default_theme = _process_theme(default_theme, "default")
+ dark_theme = _process_theme(dark_theme, "dark")
Review Comment:
Yes, we already have one defined in `superset/themes/types.py` so I'll just
use that one. Nice catch!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]