Skip to content

feat: add a theme CRUD page to manage themes #34182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 65 commits into from
Jul 25, 2025
Merged

feat: add a theme CRUD page to manage themes #34182

merged 65 commits into from
Jul 25, 2025

Conversation

mistercrunch
Copy link
Member

@mistercrunch mistercrunch commented Jul 16, 2025

Summary

This PR introduces a comprehensive theme management system for Superset with complete CRUD functionality and fixes critical theme scoping issues through a major architecture refactor.

Key Features

🎨 Theme CRUD Management

  • Complete REST API with full CRUD operations for themes
  • Interactive theme editor with live preview and apply-on-demand
  • Import/Export functionality for theme backup and distribution
  • Permission-based access with proper RBAC integration
  • System themes - Protected themes defined in configuration

📊 Dashboard Theme Integration

  • Per-dashboard theme assignment through enhanced dashboard edit modal
  • FIXED: Dashboard themes now properly scoped to dashboard content only
  • Theme selector integrated into "Theme & CSS" dashboard submenu
  • Seamless theme switching with automatic cleanup on navigation

🏗️ Architecture Refactor (Major New Work)

Problem: Dashboard themes were affecting entire app (including navbar) instead of just dashboard content.

Solution: Complete theme system overhaul:

  • ThemeController: Singleton managing all Theme object lifecycles with isolated dashboard themes
  • Nested Providers: Global ThemeProvider + Dashboard-specific ThemeProvider for proper isolation
  • Component Modernization: Eliminated global themeObject dependencies, components now use context-aware useTheme() + utilities
  • Deduplicated Logic: Removed duplicate Theme class methods, single source of truth in themeUtils.ts

🔧 System Integration

  • UUID-based theme references in configuration
  • System theme seeding with automatic startup creation/updates
  • Feature flag update - THEME_ENABLE_DARK_THEME_SWITCH defaults to True

Fixed Behaviors

  • ✅ Dashboard themes only affect dashboard content (not navbar)
  • ✅ Navbar always uses global/system theme
  • ✅ Theme mode picker only affects navbar/global theme
  • ✅ Navigation from themed dashboard restores global theme everywhere

Technical Implementation

Backend: Theme model, complete REST API, dashboard integration, system theme seeding
Frontend: CRUD interface, dashboard integration, proper theme scoping architecture
Component Library: Refactored to use context-aware theming without global dependencies
Testing: Comprehensive test coverage including new themeUtils.test.ts

Migration & Breaking Changes

  • Database migration required for themes table and dashboard theme_id column
  • No breaking changes for end users
  • Developer API changes: Use useTheme() + utilities instead of global themeObject methods

Configuration Examples

# Traditional approach
THEME_DEFAULT = {"algorithm": "default", "token": {"colorPrimary": "#2893B3"}}

# UUID reference to existing theme
THEME_DEFAULT = {"uuid": "550e8400-e29b-41d4-a716-446655440000"}

This implementation provides enterprise-grade theme management with proper isolation, security, and a solid foundation for advanced theming capabilities.

🤖 Co-generated with https://claude.ai/code

Copy link

korbit-ai bot commented Jul 16, 2025

Based on your review schedule, I'll hold off on reviewing this PR until it's marked as ready for review. If you'd like me to take a look now, comment /korbit-review.

Your admin can change your review schedule in the Korbit Console

@github-actions github-actions bot added risk:db-migration PRs that require a DB migration api Related to the REST API doc Namespace | Anything related to documentation packages labels Jul 16, 2025
@@ -38,7 +38,6 @@ Set the feature flag in your `superset_config`
```python
DEFAULT_FEATURE_FLAGS: dict[str, bool] = {
{{ ... }}
THEME_ALLOW_THEME_EDITOR_BETA = True,
Copy link
Member Author

@mistercrunch mistercrunch Jul 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for this feature flag now as we have an "apply" button in the theme editor in the new CRUD

Copy link
Contributor

@mistercrunch Processing your ephemeral environment request here. Action: up. More information on how to use or configure ephemeral environments

@mistercrunch mistercrunch marked this pull request as ready for review July 17, 2025 17:52
Copy link

korbit-ai bot commented Jul 17, 2025

Korbit doesn't automatically review large (3000+ lines changed) pull requests such as this one. If you want me to review anyway, use /korbit-review.

@dosubot dosubot bot added dashboard:design Related to the Dashboard UI/UX global:theming Related to theming Superset labels Jul 17, 2025
Copy link
Contributor

@mistercrunch Ephemeral environment spinning up at http://54.244.28.232:8080. Credentials are 'admin'/'admin'. Please allow several minutes for bootstrapping and startup.


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're supposed to use the helper functions for creating tables and columns going forward

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, let me fix and see if I can add a linting rule (?) Though would love to spend some cycles improving migrations:

  • compact migration before say 3.0 (wondering where to draw the line)
  • making sure we use utils consistently
  • add linting rules to prevent not using utils

Copy link
Member

@msyavuz msyavuz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now it looks like we only use backend for storing the Theme config and name. It would be cool to add some kind of tagging system for light/dark to enable quick mode switching for users.

Comment on lines 249 to 370
/**
* Sets a CRUD theme by ID. This will fetch the theme from the API and apply it.
* @param themeId - The ID of the CRUD theme to apply
*/
public async setCrudTheme(themeId: string | null): Promise<void> {
this.crudThemeId = themeId;

if (themeId) {
this.storage.setItem(STORAGE_KEYS.CRUD_THEME_ID, themeId);
try {
const themeConfig = await this.fetchCrudTheme(themeId);
if (themeConfig) {
this.updateTheme(themeConfig);
}
} catch (error) {
console.error('Failed to load CRUD theme:', error);
this.fallbackToDefaultMode();
}
} else {
this.storage.removeItem(STORAGE_KEYS.CRUD_THEME_ID);
this.resetTheme();
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is used anywhere. All of the crud related stuff in this file seems unused, we should probably implement it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right, though we might need it in the future (?) might be attached to user prefs in the future. Can keep for now.

Copy link
Contributor

@mistercrunch Processing your ephemeral environment request here. Action: up. More information on how to use or configure ephemeral environments

Copy link
Contributor

@mistercrunch Ephemeral environment spinning up at http://44.245.7.189:8080. Credentials are 'admin'/'admin'. Please allow several minutes for bootstrapping and startup.

Copy link
Contributor

@mistercrunch Processing your ephemeral environment request here. Action: up. More information on how to use or configure ephemeral environments

Copy link
Contributor

@mistercrunch Ephemeral environment spinning up at http://54.203.44.180:8080. Credentials are 'admin'/'admin'. Please allow several minutes for bootstrapping and startup.

Copy link
Member

@msyavuz msyavuz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently we set some default tokens in packages/superset-ui-core/src/theme/Theme.tsx But they are not visible in the ui for the theme and i am not sure if they are applied to database either. Should we move them to default config options instead?

@mistercrunch
Copy link
Member Author

Currently we set some default tokens in packages/superset-ui-core/src/theme/Theme.tsx But they are not visible in the ui for the theme and i am not sure if they are applied to database either. Should we move them to default config options instead?

The theme constructor is (AFAIK) deterministic (well kinda), meaning when you set your theme to {algorithm: "dark"}, as it gets created, will go through its construction, and defaults get applied, so the defaults here https://github.com/apache/superset/blob/master/superset-frontend/packages/superset-ui-core/src/theme/Theme.tsx#L73-L101 will get applied. Now if you were to pass an override like {algorithm: "dark": token: { brandLogoUrl: "{some_url}" }}, it'll override the default, and generated tokens will end up the same, except for that one. Now across versions of Superset where defaults might change, the "compiled" theme might change as defaults change, but I'm pretty sure that's what we want in most (all?) cases.

Copy link
Contributor

@mistercrunch Processing your ephemeral environment request here. Action: up. More information on how to use or configure ephemeral environments

Copy link
Contributor

@mistercrunch Ephemeral environment spinning up at http://54.190.54.11:8080. Credentials are 'admin'/'admin'. Please allow several minutes for bootstrapping and startup.

@mistercrunch mistercrunch merged commit e741a31 into master Jul 25, 2025
59 checks passed
@mistercrunch mistercrunch deleted the theme_crud branch July 25, 2025 20:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api Related to the REST API dashboard:design Related to the Dashboard UI/UX dependencies:npm doc Namespace | Anything related to documentation global:theming Related to theming Superset packages plugins preset-io risk:db-migration PRs that require a DB migration size/XXL testenv-up
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants