diff --git a/superset-frontend/src/SqlLab/App.jsx b/superset-frontend/src/SqlLab/App.jsx index 10f1e51bb38c9..82132b79be8bf 100644 --- a/superset-frontend/src/SqlLab/App.jsx +++ b/superset-frontend/src/SqlLab/App.jsx @@ -21,7 +21,7 @@ import { createStore, compose, applyMiddleware } from 'redux'; import { Provider } from 'react-redux'; import thunkMiddleware from 'redux-thunk'; import { hot } from 'react-hot-loader/root'; -import { supersetTheme, ThemeProvider } from '@superset-ui/core'; +import { ThemeProvider } from '@superset-ui/core'; import { initFeatureFlags, isFeatureEnabled, @@ -41,6 +41,7 @@ import setupApp from '../setup/setupApp'; import './main.less'; import '../../stylesheets/reactable-pagination.less'; import '../components/FilterableTable/FilterableTableStyles.less'; +import { theme } from '../preamble'; setupApp(); @@ -109,7 +110,7 @@ if (sqlLabMenu) { const Application = () => ( - + diff --git a/superset-frontend/src/addSlice/App.tsx b/superset-frontend/src/addSlice/App.tsx index 1e57e171858d8..9602670a08902 100644 --- a/superset-frontend/src/addSlice/App.tsx +++ b/superset-frontend/src/addSlice/App.tsx @@ -18,12 +18,13 @@ */ import React from 'react'; import { hot } from 'react-hot-loader/root'; -import { supersetTheme, ThemeProvider } from '@superset-ui/core'; +import { ThemeProvider } from '@superset-ui/core'; import setupApp from '../setup/setupApp'; import setupPlugins from '../setup/setupPlugins'; import { DynamicPluginProvider } from '../components/DynamicPlugins'; import AddSliceContainer from './AddSliceContainer'; import { initFeatureFlags } from '../featureFlags'; +import { theme } from '../preamble'; setupApp(); setupPlugins(); @@ -36,7 +37,7 @@ const bootstrapData = JSON.parse( initFeatureFlags(bootstrapData.common.feature_flags); const App = () => ( - + diff --git a/superset-frontend/src/dashboard/App.jsx b/superset-frontend/src/dashboard/App.jsx index 336473a64c8d3..da06a0130fa31 100644 --- a/superset-frontend/src/dashboard/App.jsx +++ b/superset-frontend/src/dashboard/App.jsx @@ -19,13 +19,14 @@ import { hot } from 'react-hot-loader/root'; import React from 'react'; import { Provider } from 'react-redux'; -import { supersetTheme, ThemeProvider } from '@superset-ui/core'; +import { ThemeProvider } from '@superset-ui/core'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; import { DynamicPluginProvider } from 'src/components/DynamicPlugins'; import setupApp from '../setup/setupApp'; import setupPlugins from '../setup/setupPlugins'; import DashboardContainer from './containers/Dashboard'; +import { theme } from '../preamble'; setupApp(); setupPlugins(); @@ -33,7 +34,7 @@ setupPlugins(); const App = ({ store }) => ( - + diff --git a/superset-frontend/src/explore/App.jsx b/superset-frontend/src/explore/App.jsx index f0a3db4fe3f3d..e7973fe91f479 100644 --- a/superset-frontend/src/explore/App.jsx +++ b/superset-frontend/src/explore/App.jsx @@ -21,7 +21,7 @@ import { hot } from 'react-hot-loader/root'; import { Provider } from 'react-redux'; import { DndProvider } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; -import { supersetTheme, ThemeProvider } from '@superset-ui/core'; +import { ThemeProvider } from '@superset-ui/core'; import { DynamicPluginProvider } from 'src/components/DynamicPlugins'; import ToastPresenter from '../messageToasts/containers/ToastPresenter'; import ExploreViewContainer from './components/ExploreViewContainer'; @@ -29,6 +29,7 @@ import setupApp from '../setup/setupApp'; import setupPlugins from '../setup/setupPlugins'; import './main.less'; import '../../stylesheets/reactable-pagination.less'; +import { theme } from '../preamble'; setupApp(); setupPlugins(); @@ -36,7 +37,7 @@ setupPlugins(); const App = ({ store }) => ( - + diff --git a/superset-frontend/src/preamble.ts b/superset-frontend/src/preamble.ts index 31d547dff0747..8fad06599e732 100644 --- a/superset-frontend/src/preamble.ts +++ b/superset-frontend/src/preamble.ts @@ -19,7 +19,8 @@ import { setConfig as setHotLoaderConfig } from 'react-hot-loader'; import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'; import moment from 'moment'; -import { configure } from '@superset-ui/core'; +import { configure, supersetTheme } from '@superset-ui/core'; +import { merge } from 'lodash'; import setupClient from './setup/setupClient'; import setupColors from './setup/setupColors'; import setupFormatters from './setup/setupFormatters'; @@ -57,3 +58,8 @@ setupColors( // Setup number formatters setupFormatters(); + +export const theme = merge( + supersetTheme, + bootstrapData?.common?.theme_overrides ?? {}, +); diff --git a/superset-frontend/src/profile/App.tsx b/superset-frontend/src/profile/App.tsx index 8fe5754dd0228..8774d63aeb5a5 100644 --- a/superset-frontend/src/profile/App.tsx +++ b/superset-frontend/src/profile/App.tsx @@ -21,13 +21,13 @@ import { hot } from 'react-hot-loader/root'; import thunk from 'redux-thunk'; import { createStore, applyMiddleware, compose, combineReducers } from 'redux'; import { Provider } from 'react-redux'; -import { supersetTheme, ThemeProvider } from '@superset-ui/core'; +import { ThemeProvider } from '@superset-ui/core'; import App from './components/App'; import messageToastReducer from '../messageToasts/reducers'; import { initEnhancer } from '../reduxUtils'; import setupApp from '../setup/setupApp'; - import './main.less'; +import { theme } from '../preamble'; setupApp(); @@ -46,7 +46,7 @@ const store = createStore( const Application = () => ( - + diff --git a/superset-frontend/src/views/App.tsx b/superset-frontend/src/views/App.tsx index 3d45d261af7dc..b0c54fe30a93e 100644 --- a/superset-frontend/src/views/App.tsx +++ b/superset-frontend/src/views/App.tsx @@ -24,7 +24,7 @@ import { Provider as ReduxProvider } from 'react-redux'; import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'; import { QueryParamProvider } from 'use-query-params'; import { initFeatureFlags } from 'src/featureFlags'; -import { supersetTheme, ThemeProvider } from '@superset-ui/core'; +import { ThemeProvider } from '@superset-ui/core'; import { DynamicPluginProvider } from 'src/components/DynamicPlugins'; import ErrorBoundary from 'src/components/ErrorBoundary'; import Menu from 'src/components/Menu/Menu'; @@ -47,6 +47,7 @@ import setupApp from '../setup/setupApp'; import setupPlugins from '../setup/setupPlugins'; import Welcome from './CRUD/welcome/Welcome'; import ToastPresenter from '../messageToasts/containers/ToastPresenter'; +import { theme } from '../preamble'; setupApp(); setupPlugins(); @@ -68,7 +69,7 @@ const store = createStore( const App = () => ( - + diff --git a/superset-frontend/src/views/menu.tsx b/superset-frontend/src/views/menu.tsx index 63a920327b314..887b5b76d4dde 100644 --- a/superset-frontend/src/views/menu.tsx +++ b/superset-frontend/src/views/menu.tsx @@ -18,15 +18,16 @@ */ import React from 'react'; import ReactDOM from 'react-dom'; -import { supersetTheme, ThemeProvider } from '@superset-ui/core'; +import { ThemeProvider } from '@superset-ui/core'; import Menu from 'src/components/Menu/Menu'; +import { theme } from '../preamble'; const container = document.getElementById('app'); const bootstrapJson = container?.getAttribute('data-bootstrap') ?? '{}'; const bootstrap = JSON.parse(bootstrapJson); const menu = { ...bootstrap.common.menu_data }; const app = ( - + ); diff --git a/superset/config.py b/superset/config.py index d7c8d5ef86802..f320f2df3c4bb 100644 --- a/superset/config.py +++ b/superset/config.py @@ -373,7 +373,7 @@ def _try_json_readsha( # pylint: disable=unused-argument # EXTRA_CATEGORICAL_COLOR_SCHEMES is used for adding custom categorical color schemes # example code for "My custom warm to hot" color scheme -# EXTRA_CATEGORICAL_COLOR_SCHEMES = [ +# EXTRA_CATEGORICAL_COLOR_SCHEMES = [ # { # "id": 'myVisualizationColors', # "description": '', @@ -382,11 +382,29 @@ def _try_json_readsha( # pylint: disable=unused-argument # ['#006699', '#009DD9', '#5AAA46', '#44AAAA', '#DDAA77', '#7799BB', '#88AA77', # '#552288', '#5AAA46', '#CC7788', '#EEDD55', '#9977BB', '#BBAA44', '#DDCCDD'] # }] -# # This is merely a default EXTRA_CATEGORICAL_COLOR_SCHEMES: List[Dict[str, Any]] = [] +# THEME_OVERRIDES is used for adding custom theme to superset +# example code for "My theme" custom scheme +# THEME_OVERRIDES = { +# "borderRadius": 4, +# "colors": { +# "primary": { +# "base": 'red', +# }, +# "secondary": { +# "base": 'green', +# }, +# "grayscale": { +# "base": 'orange', +# } +# } +# } + +THEME_OVERRIDES: Dict[str, Any] = {} + # EXTRA_SEQUENTIAL_COLOR_SCHEMES is used for adding custom sequential color schemes # EXTRA_SEQUENTIAL_COLOR_SCHEMES = [ # { diff --git a/superset/views/base.py b/superset/views/base.py index 267bdb8ab614f..69c9383ffccc1 100644 --- a/superset/views/base.py +++ b/superset/views/base.py @@ -322,6 +322,7 @@ def common_bootstrap_payload() -> Dict[str, Any]: "feature_flags": get_feature_flags(), "extra_sequential_color_schemes": conf["EXTRA_SEQUENTIAL_COLOR_SCHEMES"], "extra_categorical_color_schemes": conf["EXTRA_CATEGORICAL_COLOR_SCHEMES"], + "theme_overrides": conf["THEME_OVERRIDES"], "menu_data": menu_data(), }