You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ma...@apache.org on 2025/06/24 20:49:52 UTC

(superset) 02/03: move theme loading from bootstrapData in the ThemeController

This is an automated email from the ASF dual-hosted git repository.

maximebeauchemin pushed a commit to branch theme_dark
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 312f6c5ed63aa0e38a90b476332a4e97c73cb2ca
Author: Maxime Beauchemin <ma...@gmail.com>
AuthorDate: Tue Jun 24 13:44:45 2025 -0700

    move theme loading from bootstrapData in the ThemeController
---
 superset-frontend/src/theme/ThemeController.tsx    | 47 ++++++++++++++--------
 .../src/views/RootContextProviders.tsx             |  5 +--
 2 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/superset-frontend/src/theme/ThemeController.tsx b/superset-frontend/src/theme/ThemeController.tsx
index 37a6c8c5e9..fce09ff6bd 100644
--- a/superset-frontend/src/theme/ThemeController.tsx
+++ b/superset-frontend/src/theme/ThemeController.tsx
@@ -25,6 +25,7 @@ import {
   themeObject,
 } from '@superset-ui/core';
 import { ThemeMode } from '@superset-ui/core/theme/types';
+import getBootstrapData from 'src/utils/getBootstrapData';
 
 export class LocalStorageAdapter implements ThemeStorage {
   getItem(key: string): string | null {
@@ -65,12 +66,18 @@ export class ThemeController {
 
   private mediaQuery: MediaQueryList;
 
-  constructor(options: ThemeControllerOptions = { themeObject }) {
+  constructor(options: ThemeControllerOptions = {}) {
     this.storage = options.storage || new LocalStorageAdapter();
     this.storageKey = options.storageKey || 'superset-theme';
     this.modeStorageKey = options.modeStorageKey || `${this.storageKey}-mode`;
     this.defaultTheme = options.defaultTheme || {};
-    this.themeObject = options.themeObject;
+
+    // Load themeObject — either passed in or auto-loaded from bootstrap
+    if (options.themeObject) {
+      this.themeObject = options.themeObject;
+    } else {
+      this.themeObject = ThemeController.loadThemeFromBootstrap();
+    }
 
     // Load customizations from storage
     const savedThemeJson = this.storage.getItem(this.storageKey);
@@ -103,8 +110,28 @@ export class ThemeController {
   }
 
   /**
-   * Cleans up listeners. Should be called when the controller is no longer needed.
+   * Load theme object directly from bootstrapData if not provided explicitly
    */
+  private static loadThemeFromBootstrap(): Theme {
+    const bootstrapData = getBootstrapData().common;
+
+    let themeConfig: AnyThemeConfig = {};
+
+    if (bootstrapData.theme) {
+      themeConfig = bootstrapData.theme;
+    } else if (bootstrapData.themes) {
+      const systemMode = ThemeController.getSystemMode();
+      const preferred = systemMode;
+      if (bootstrapData.themes[preferred]) {
+        themeConfig = bootstrapData.themes[preferred];
+      }
+    } else {
+      console.warn('No theme data found in bootstrapData');
+    }
+
+    return themeObject.setConfig(themeConfig);
+  }
+
   public destroy(): void {
     this.mediaQuery.removeEventListener('change', this.handleSystemThemeChange);
   }
@@ -125,10 +152,6 @@ export class ThemeController {
     return this.currentMode;
   }
 
-  /**
-   * Sets new theme customizations (e.g., from a JSON editor).
-   * This method updates the theme's appearance but preserves the current mode.
-   */
   public setTheme(newCustomizations: AnyThemeConfig): void {
     if (!this.canUpdateTheme()) {
       throw new Error('User does not have permission to update the theme');
@@ -138,7 +161,6 @@ export class ThemeController {
     if (!newCustomizations.algorithm) {
       this.currentMode = ThemeMode.LIGHT;
     }
-
     if (newCustomizations?.algorithm) {
       this.currentMode = newCustomizations.algorithm as ThemeMode;
     }
@@ -148,10 +170,6 @@ export class ThemeController {
     this.notifyListeners();
   }
 
-  /**
-   * Changes the theme mode (light, dark, or system).
-   * This is for the mode switch.
-   */
   public changeThemeMode(newMode: ThemeMode): void {
     if (!this.canUpdateMode()) {
       throw new Error('User does not have permission to update the theme mode');
@@ -184,16 +202,12 @@ export class ThemeController {
     if (this.systemMode === newSystemMode) return;
 
     this.systemMode = newSystemMode;
-    // If the current mode is SYSTEM, we need to re-apply the theme
     if (this.currentMode === ThemeMode.SYSTEM) {
       this.applyTheme();
       this.notifyListeners();
     }
   };
 
-  /**
-   * Centralized method to apply the current customizations and mode.
-   */
   private applyTheme(): void {
     const newConfig = { ...this.customizations };
 
@@ -221,7 +235,6 @@ export class ThemeController {
 
   private persist(): void {
     this.storage.setItem(this.modeStorageKey, this.currentMode);
-
     const { algorithm, ...persistedCustomizations } = this.customizations;
     this.storage.setItem(
       this.storageKey,
diff --git a/superset-frontend/src/views/RootContextProviders.tsx b/superset-frontend/src/views/RootContextProviders.tsx
index d27b271c44..666e1cba1c 100644
--- a/superset-frontend/src/views/RootContextProviders.tsx
+++ b/superset-frontend/src/views/RootContextProviders.tsx
@@ -33,10 +33,7 @@ import '../preamble';
 
 const { common } = getBootstrapData();
 
-if (Object.keys(common?.theme || {}).length > 0) {
-  themeObject.setConfig(common.theme);
-}
-const themeController = new ThemeController({ themeObject });
+const themeController = new ThemeController();
 
 const extensionsRegistry = getExtensionsRegistry();
 export const RootContextProviders: React.FC = ({ children }) => {