Skip to content

Commit 9d2b55e

Browse files
committed
feat(frontend): create theme provider
1 parent 5d8e9e1 commit 9d2b55e

23 files changed

Lines changed: 133 additions & 72 deletions

clients/ui/frontend/src/app/App.tsx

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
} from '@patternfly/react-core';
1515
import ToastNotifications from '~/shared/components/ToastNotifications';
1616
import { useSettings } from '~/shared/hooks/useSettings';
17-
import { isMUITheme, Theme, AUTH_HEADER, MOCK_AUTH, isStandalone } from '~/shared/utilities/const';
17+
import { AUTH_HEADER, MOCK_AUTH, isStandalone } from '~/shared/utilities/const';
1818
import { logout } from '~/shared/utilities/appUtils';
1919
import { NamespaceSelectorContext } from '~/shared/context/NamespaceSelectorContext';
2020
import NavSidebar from './NavSidebar';
@@ -36,15 +36,6 @@ const App: React.FC = () => {
3636

3737
const username = userSettings?.userId;
3838

39-
React.useEffect(() => {
40-
// Apply the theme based on the value of STYLE_THEME
41-
if (isMUITheme()) {
42-
document.documentElement.classList.add(Theme.MUI);
43-
} else {
44-
document.documentElement.classList.remove(Theme.MUI);
45-
}
46-
}, []);
47-
4839
React.useEffect(() => {
4940
if (MOCK_AUTH && username) {
5041
localStorage.setItem(AUTH_HEADER, username);

clients/ui/frontend/src/app/NavBar.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@ import {
2121
import { SimpleSelect } from '@patternfly/react-templates';
2222
import { BarsIcon } from '@patternfly/react-icons';
2323
import { NamespaceSelectorContext } from '~/shared/context/NamespaceSelectorContext';
24-
import { isMUITheme } from '~/shared/utilities/const';
2524
import logoDarkTheme from '~/images/logo-dark-theme.svg';
25+
import { useThemeContext } from './ThemeContext';
2626

2727
interface NavBarProps {
2828
username?: string;
2929
onLogout: () => void;
3030
}
3131

3232
const NavBar: React.FC<NavBarProps> = ({ username, onLogout }) => {
33+
const { isMUITheme } = useThemeContext();
3334
const { namespaces, preferredNamespace, updatePreferredNamespace } =
3435
React.useContext(NamespaceSelectorContext);
3536

@@ -60,7 +61,7 @@ const NavBar: React.FC<NavBarProps> = ({ username, onLogout }) => {
6061
<BarsIcon />
6162
</PageToggleButton>
6263
</MastheadToggle>
63-
{!isMUITheme() ? (
64+
{!isMUITheme ? (
6465
<MastheadBrand>
6566
<MastheadLogo component="a">
6667
<Brand src={logoDarkTheme} alt="Kubeflow" heights={{ default: '36px' }} />

clients/ui/frontend/src/app/NavSidebar.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ import {
99
PageSidebar,
1010
PageSidebarBody,
1111
} from '@patternfly/react-core';
12-
import { isMUITheme, LOGO_LIGHT } from '~/shared/utilities/const';
12+
import { LOGO_LIGHT } from '~/shared/utilities/const';
1313
import { useNavData, isNavDataGroup, NavDataHref, NavDataGroup } from './AppRoutes';
14+
import { useThemeContext } from './ThemeContext';
1415

1516
const NavHref: React.FC<{ item: NavDataHref }> = ({ item }) => (
1617
<NavItem key={item.label} data-id={item.label} itemId={item.label}>
@@ -42,13 +43,14 @@ const NavGroup: React.FC<{ item: NavDataGroup }> = ({ item }) => {
4243

4344
const NavSidebar: React.FC = () => {
4445
const navData = useNavData();
46+
const { isMUITheme } = useThemeContext();
4547

4648
return (
4749
<PageSidebar>
4850
<PageSidebarBody>
4951
<Nav id="nav-primary-simple">
5052
<NavList id="nav-list-simple">
51-
{isMUITheme() ? (
53+
{isMUITheme ? (
5254
<NavItem>
5355
<Brand
5456
className="kubeflow_brand"
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as React from 'react';
2+
3+
type ThemeContextProps = {
4+
isMUITheme: boolean;
5+
};
6+
7+
export const ThemeContext = React.createContext({
8+
isMUITheme: true,
9+
});
10+
11+
export const useThemeContext = (): ThemeContextProps => React.useContext(ThemeContext);
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import * as React from 'react';
2+
import { createTheme, Theme as MUITheme } from '@mui/material';
3+
import { isMUITheme, Theme } from '~/shared/utilities/const';
4+
import { ThemeContext } from './ThemeContext';
5+
6+
type ThemeProviderProps = {
7+
children: React.ReactNode;
8+
theme?: MUITheme;
9+
};
10+
11+
const ThemeProvider: React.FC<ThemeProviderProps> = ({ children, theme }) => {
12+
const themeValue = React.useMemo(() => ({ isMUITheme: isMUITheme() }), []);
13+
const createMUITheme = createTheme({ cssVariables: true });
14+
15+
React.useEffect(() => {
16+
// Apply the theme based on the value of STYLE_THEME
17+
if (isMUITheme()) {
18+
document.documentElement.classList.add(Theme.MUI);
19+
} else {
20+
document.documentElement.classList.remove(Theme.MUI);
21+
}
22+
}, []);
23+
24+
const appliedTheme = theme || createMUITheme;
25+
26+
return (
27+
<ThemeContext.Provider value={themeValue}>
28+
{isMUITheme() ? <ThemeProvider theme={appliedTheme}>{children}</ThemeProvider> : children}
29+
</ThemeContext.Provider>
30+
);
31+
};
32+
33+
export default ThemeProvider;

clients/ui/frontend/src/app/pages/modelRegistry/ModelRegistryCoreLoader.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import { ProjectObjectType, typedEmptyImage } from '~/shared/components/design/u
77
import { ModelRegistryContextProvider } from '~/app/context/ModelRegistryContext';
88
import TitleWithIcon from '~/shared/components/design/TitleWithIcon';
99
import WhosMyAdministrator from '~/shared/components/WhosMyAdministrator';
10-
import { isMUITheme } from '~/shared/utilities/const';
1110
import KubeflowDocs from '~/shared/components/KubeflowDocs';
11+
import { useThemeContext } from '~/app/ThemeContext';
1212
import EmptyModelRegistryState from './screens/components/EmptyModelRegistryState';
1313
import InvalidModelRegistry from './screens/InvalidModelRegistry';
1414
import ModelRegistrySelectorNavigator from './screens/ModelRegistrySelectorNavigator';
@@ -36,6 +36,7 @@ const ModelRegistryCoreLoader: React.FC<ModelRegistryCoreLoaderProps> = ({
3636
preferredModelRegistry,
3737
updatePreferredModelRegistry,
3838
} = React.useContext(ModelRegistrySelectorContext);
39+
const { isMUITheme } = useThemeContext();
3940

4041
const modelRegistryFromRoute = modelRegistries.find((mr) => mr.name === modelRegistry);
4142

@@ -65,16 +66,16 @@ const ModelRegistryCoreLoader: React.FC<ModelRegistryCoreLoaderProps> = ({
6566
emptyStatePage: (
6667
<EmptyModelRegistryState
6768
testid="empty-model-registries-state"
68-
title={isMUITheme() ? 'Deploy a model registry' : 'Request access to model registries'}
69+
title={isMUITheme ? 'Deploy a model registry' : 'Request access to model registries'}
6970
description={
70-
isMUITheme()
71+
isMUITheme
7172
? 'To deploy a new model registry, follow the instructions in the docs below.'
7273
: 'To request a new model registry, or to request permission to access an existing model registry, contact your administrator.'
7374
}
7475
headerIcon={() => (
7576
<img src={typedEmptyImage(ProjectObjectType.registeredModels)} alt="" />
7677
)}
77-
customAction={isMUITheme() ? <KubeflowDocs /> : <WhosMyAdministrator />}
78+
customAction={isMUITheme ? <KubeflowDocs /> : <WhosMyAdministrator />}
7879
/>
7980
),
8081
headerContent: null,
@@ -103,14 +104,14 @@ const ModelRegistryCoreLoader: React.FC<ModelRegistryCoreLoaderProps> = ({
103104
return (
104105
<ApplicationsPage
105106
title={
106-
!isMUITheme() ? (
107+
!isMUITheme ? (
107108
<TitleWithIcon title="Model Registry" objectType={ProjectObjectType.registeredModels} />
108109
) : (
109110
'Model Registry'
110111
)
111112
}
112113
description={
113-
!isMUITheme() ? (
114+
!isMUITheme ? (
114115
'Select a model registry to view and manage your registered models. Model registries provide a structured and organized way to store, share, version, deploy, and track models.'
115116
) : (
116117
<Divider />

clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelPropertiesTableRow.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { CheckIcon, ExternalLinkAltIcon, TimesIcon } from '@patternfly/react-ico
1515
import { KeyValuePair } from '~/shared/types';
1616
import { EitherNotBoth } from '~/shared/typeHelpers';
1717
import FormFieldset from '~/app/pages/modelRegistry/screens/components/FormFieldset';
18-
import { isMUITheme } from '~/shared/utilities/const';
18+
import { useThemeContext } from '~/app/ThemeContext';
1919
import { isValidHttpUrl } from './utils';
2020

2121
type ModelPropertiesTableRowProps = {
@@ -47,6 +47,8 @@ const ModelPropertiesTableRow: React.FC<ModelPropertiesTableRowProps> = ({
4747
saveEditedProperty,
4848
}) => {
4949
const { key, value } = keyValuePair;
50+
const { isMUITheme } = useThemeContext();
51+
5052
const [unsavedKey, setUnsavedKey] = React.useState(key);
5153
const [unsavedValue, setUnsavedValue] = React.useState(value);
5254

@@ -128,7 +130,7 @@ const ModelPropertiesTableRow: React.FC<ModelPropertiesTableRowProps> = ({
128130
<Td dataLabel="Key" width={45} modifier="breakWord">
129131
{isEditing ? (
130132
<>
131-
{isMUITheme() ? (
133+
{isMUITheme ? (
132134
<FormFieldset className="tr-fieldset-wrapper" component={propertyKeyInput} />
133135
) : (
134136
propertyKeyInput
@@ -148,7 +150,7 @@ const ModelPropertiesTableRow: React.FC<ModelPropertiesTableRowProps> = ({
148150
</Td>
149151
<Td dataLabel="Value" width={45} modifier="breakWord">
150152
{isEditing ? (
151-
isMUITheme() ? (
153+
isMUITheme ? (
152154
<FormFieldset className="tr-fieldset-wrapper" component={propertyValueInput} />
153155
) : (
154156
propertyValueInput

clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelRegistry.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ import { Divider } from '@patternfly/react-core';
33
import ApplicationsPage from '~/shared/components/ApplicationsPage';
44
import useRegisteredModels from '~/app/hooks/useRegisteredModels';
55
import useModelVersions from '~/app/hooks/useModelVersions';
6-
import { isMUITheme } from '~/shared/utilities/const';
76
import TitleWithIcon from '~/shared/components/design/TitleWithIcon';
87
import { ProjectObjectType } from '~/shared/components/design/utils';
8+
import { useThemeContext } from '~/app/ThemeContext';
99
import ModelRegistrySelectorNavigator from './ModelRegistrySelectorNavigator';
1010
import RegisteredModelListView from './RegisteredModels/RegisteredModelListView';
1111
import { modelRegistryUrl } from './routeUtils';
@@ -25,6 +25,7 @@ const ModelRegistry: React.FC<ModelRegistryProps> = ({ ...pageProps }) => {
2525
const [registeredModels, modelsLoaded, modelsLoadError, refreshModels] = useRegisteredModels();
2626
const [modelVersions, versionsLoaded, versionsLoadError, refreshVersions] = useModelVersions();
2727

28+
const { isMUITheme } = useThemeContext();
2829
const loaded = modelsLoaded && versionsLoaded;
2930
const loadError = modelsLoadError || versionsLoadError;
3031

@@ -37,14 +38,14 @@ const ModelRegistry: React.FC<ModelRegistryProps> = ({ ...pageProps }) => {
3738
<ApplicationsPage
3839
{...pageProps}
3940
title={
40-
!isMUITheme() ? (
41+
!isMUITheme ? (
4142
<TitleWithIcon title="Model Registry" objectType={ProjectObjectType.registeredModels} />
4243
) : (
4344
'Model Registry'
4445
)
4546
}
4647
description={
47-
!isMUITheme() ? (
48+
!isMUITheme ? (
4849
'Select a model registry to view and manage your registered models. Model registries provide a structured and organized way to store, share, version, deploy, and track models.'
4950
) : (
5051
<Divider />

clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelRegistrySelector.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ import { ModelRegistrySelectorContext } from '~/app/context/ModelRegistrySelecto
2121
import { ModelRegistry } from '~/app/types';
2222
import SimpleSelect, { SimpleSelectOption } from '~/shared/components/SimpleSelect';
2323
import WhosMyAdministrator from '~/shared/components/WhosMyAdministrator';
24-
import { isMUITheme } from '~/shared/utilities/const';
2524
import KubeflowDocs from '~/shared/components/KubeflowDocs';
25+
import { useThemeContext } from '~/app/ThemeContext';
2626

2727
const MODEL_REGISTRY_FAVORITE_STORAGE_KEY = 'kubeflow.dashboard.model.registry.favorite';
2828

@@ -42,6 +42,7 @@ const ModelRegistrySelector: React.FC<ModelRegistrySelectorProps> = ({
4242
const { modelRegistries, updatePreferredModelRegistry } = React.useContext(
4343
ModelRegistrySelectorContext,
4444
);
45+
const { isMUITheme } = useThemeContext();
4546

4647
const selection = modelRegistries.find((mr) => mr.name === modelRegistry);
4748
const [favorites, setFavorites] = useBrowserStorage<string[]>(
@@ -175,7 +176,7 @@ const ModelRegistrySelector: React.FC<ModelRegistrySelectorProps> = ({
175176
</FlexItem>
176177
)}
177178
<FlexItem align={{ default: 'alignRight' }}>
178-
{isMUITheme() ? (
179+
{isMUITheme ? (
179180
<KubeflowDocs
180181
buttonLabel="Need another registry?"
181182
linkTestId="model-registry-help-button"

clients/ui/frontend/src/app/pages/modelRegistry/screens/ModelVersions/ModelVersionListView.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ import { asEnumMember } from '~/shared/utilities/utils';
3434
import ModelVersionsTable from '~/app/pages/modelRegistry/screens/ModelVersions/ModelVersionsTable';
3535
import SimpleSelect from '~/shared/components/SimpleSelect';
3636
import FormFieldset from '~/app/pages/modelRegistry/screens/components/FormFieldset';
37-
import { isMUITheme } from '~/shared/utilities/const';
3837
import { filterArchiveVersions, filterLiveVersions } from '~/app/utils';
38+
import { useThemeContext } from '~/app/ThemeContext';
3939

4040
type ModelVersionListViewProps = {
4141
modelVersions: ModelVersion[];
@@ -57,6 +57,7 @@ const ModelVersionListView: React.FC<ModelVersionListViewProps> = ({
5757
const archiveModelVersions = filterArchiveVersions(modelVersions);
5858
const navigate = useNavigate();
5959
const { preferredModelRegistry } = React.useContext(ModelRegistrySelectorContext);
60+
const { isMUITheme } = useThemeContext();
6061

6162
const [searchType, setSearchType] = React.useState<SearchType>(SearchType.KEYWORD);
6263
const [search, setSearch] = React.useState('');
@@ -158,7 +159,7 @@ const ModelVersionListView: React.FC<ModelVersionListViewProps> = ({
158159
/>
159160
</ToolbarFilter>
160161
<ToolbarItem>
161-
{isMUITheme() ? (
162+
{isMUITheme ? (
162163
<FormFieldset
163164
className="toolbar-fieldset-wrapper"
164165
component={

0 commit comments

Comments
 (0)