diff --git a/.changeset/itchy-walls-boil.md b/.changeset/itchy-walls-boil.md
new file mode 100644
index 0000000000..2afd0287fe
--- /dev/null
+++ b/.changeset/itchy-walls-boil.md
@@ -0,0 +1,5 @@
+---
+'@backstage/plugin-user-settings': minor
+---
+
+Added the ability to fully customize settings page. Deprecated UserSettingsTab in favour of SettingsLayout.Route
diff --git a/packages/app/src/App.tsx b/packages/app/src/App.tsx
index 2526f6740f..fd73e99bcb 100644
--- a/packages/app/src/App.tsx
+++ b/packages/app/src/App.tsx
@@ -80,8 +80,8 @@ import {
TextSize,
} from '@backstage/plugin-techdocs-module-addons-contrib';
import {
+ SettingsLayout,
UserSettingsPage,
- UserSettingsTab,
} from '@backstage/plugin-user-settings';
import { AdvancedSettings } from './components/advancedSettings';
import AlarmIcon from '@material-ui/icons/Alarm';
@@ -267,9 +267,9 @@ const routes = (
element={}
/>
}>
-
+
-
+
} />
} />
diff --git a/plugins/user-settings/README.md b/plugins/user-settings/README.md
index ce07d76257..9a99a69b36 100644
--- a/plugins/user-settings/README.md
+++ b/plugins/user-settings/README.md
@@ -16,7 +16,7 @@ for installation instructions.
Add the item to the Sidebar:
-```ts
+```tsx
import { Settings as SidebarSettings } from '@backstage/plugin-user-settings';
@@ -28,7 +28,7 @@ import { Settings as SidebarSettings } from '@backstage/plugin-user-settings';
Add the page to the App routing:
-```ts
+```tsx
import { UserSettingsPage } from '@backstage/plugin-user-settings';
const AppRoutes = () => (
@@ -46,7 +46,7 @@ By default, the plugin provides a list of configured authentication providers fe
If you want to supply your own custom list of Authentication Providers, use the `providerSettings` prop:
-```ts
+```tsx
const MyAuthProviders = () => (
@@ -71,20 +71,20 @@ const AppRoutes = () => (
By default, the plugin renders 3 tabs of settings; GENERAL, AUTHENTICATION PROVIDERS, and FEATURE FLAGS.
If you want to add more options for your users,
-just pass the extra tabs using `UserSettingsTab` components as children of the `UserSettingsPage` route.
+just pass the extra tabs using `SettingsLayout.Route` components as children of the `UserSettingsPage` route.
The path is in this case a child of the settings path,
in the example below it would be `/settings/advanced` so that you can easily link to it.
```tsx
import {
+ SettingsLayout,
UserSettingsPage,
- UserSettingsTab,
} from '@backstage/plugin-user-settings';
}>
-
+
-
+
;
```
@@ -93,3 +93,40 @@ make sure you use a similar component structure as the other tabs.
You can take a look at
[the example extra tab](https://github.com/backstage/backstage/blob/master/packages/app/src/components/advancedSettings/AdvancedSettings.tsx)
we have created in Backstage's demo app.
+
+To change the layout altogether, create a custom page in `packages/app/src/components/user-settings/SettingsPage.tsx`:
+
+```tsx
+import React from 'react';
+import {
+ SettingsLayout,
+ UserSettingsGeneral,
+} from '@backstage/plugin-user-settings';
+import { AdvancedSettings } from './advancedSettings';
+
+export const settingsPage = (
+
+
+
+
+
+
+
+
+);
+```
+
+Now register the new settings page in `packages/app/src/App.tsx`:
+
+```diff
++ import {settingsPage} from './components/settings/settingsPage';
+
+const routes = (
+
+- } />
++ }>
++ {settingsPage}
++
+
+);
+```
diff --git a/plugins/user-settings/api-report.md b/plugins/user-settings/api-report.md
index c51d4f992a..dd8f9428ca 100644
--- a/plugins/user-settings/api-report.md
+++ b/plugins/user-settings/api-report.md
@@ -18,10 +18,12 @@ import { Observable } from '@backstage/types';
import { ProfileInfo } from '@backstage/core-plugin-api';
import { ProfileInfoApi } from '@backstage/core-plugin-api';
import { PropsWithChildren } from 'react';
+import { default as React_2 } from 'react';
import { RouteRef } from '@backstage/core-plugin-api';
import { SessionApi } from '@backstage/core-plugin-api';
import { StorageApi } from '@backstage/core-plugin-api';
import { StorageValueSnapshot } from '@backstage/core-plugin-api';
+import { TabProps } from '@material-ui/core';
// @public (undocumented)
export const DefaultProviderSettings: (props: {
@@ -43,7 +45,33 @@ export const Router: (props: { providerSettings?: JSX.Element }) => JSX.Element;
export const Settings: (props: { icon?: IconComponent }) => JSX.Element;
// @public (undocumented)
-export const USER_SETTINGS_TAB_KEY = 'user-settings.tab';
+export const SettingsLayout: {
+ (props: SettingsLayoutProps): JSX.Element;
+ Route: (props: SettingsLayoutRouteProps) => null;
+};
+
+// @public (undocumented)
+export type SettingsLayoutProps = {
+ title?: string;
+ subtitle?: string;
+ children?: React_2.ReactNode;
+};
+
+// @public (undocumented)
+export type SettingsLayoutRouteProps = {
+ path: string;
+ title: string;
+ children: JSX.Element;
+ tabProps?: TabProps<
+ React_2.ElementType,
+ {
+ component?: React_2.ElementType;
+ }
+ >;
+};
+
+// @public @deprecated (undocumented)
+export const USER_SETTINGS_TAB_KEY = 'plugin.user-settings.settingsLayoutRoute';
// @public (undocumented)
export const UserSettingsAppearanceCard: () => JSX.Element;
@@ -116,10 +144,10 @@ export class UserSettingsStorage implements StorageApi {
snapshot(key: string): StorageValueSnapshot;
}
-// @public
+// @public @deprecated
export const UserSettingsTab: (props: UserSettingsTabProps) => JSX.Element;
-// @public (undocumented)
+// @public @deprecated (undocumented)
export type UserSettingsTabProps = PropsWithChildren<{
path: string;
title: string;
diff --git a/plugins/user-settings/src/components/SettingsPage.test.tsx b/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.test.tsx
similarity index 63%
rename from plugins/user-settings/src/components/SettingsPage.test.tsx
rename to plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.test.tsx
index 01810bcc8e..d4560bdd06 100644
--- a/plugins/user-settings/src/components/SettingsPage.test.tsx
+++ b/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.test.tsx
@@ -16,39 +16,53 @@
import React from 'react';
import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils';
-import { SettingsPage } from './SettingsPage';
-import { UserSettingsTab } from './UserSettingsTab';
+import { DefaultSettingsPage } from './DefaultSettingsPage';
+import { UserSettingsTab } from '../UserSettingsTab';
+import { useOutlet } from 'react-router';
+import { SettingsLayout } from '../SettingsLayout';
jest.mock('react-router', () => ({
...jest.requireActual('react-router'),
useOutlet: jest.fn().mockReturnValue(undefined),
}));
-import { useOutlet } from 'react-router';
-
-describe('', () => {
+describe('', () => {
beforeEach(() => {
(useOutlet as jest.Mock).mockReset();
});
it('should render the settings page with 3 tabs', async () => {
const { container } = await renderWithEffects(
- wrapInTestApp(),
+ wrapInTestApp(),
);
const tabs = container.querySelectorAll('[class*=MuiTabs-root] button');
expect(tabs).toHaveLength(3);
});
- it('should render the settings page with 4 tabs when extra tabs are provided', async () => {
+ it('should render the settings page with 4 tabs when extra tabs are provided via UserSettingsTab', async () => {
const advancedTabRoute = (
Advanced settings
);
- (useOutlet as jest.Mock).mockReturnValue(advancedTabRoute);
const { container } = await renderWithEffects(
- wrapInTestApp(),
+ wrapInTestApp(),
+ );
+
+ const tabs = container.querySelectorAll('[class*=MuiTabs-root] button');
+ expect(tabs).toHaveLength(4);
+ expect(tabs[3].textContent).toEqual('Advanced');
+ });
+
+ it('should render the settings page with 4 tabs when extra tabs are provided via SettingsLayout.Route', async () => {
+ const advancedTabRoute = (
+
+ Advanced settings
+
+ );
+ const { container } = await renderWithEffects(
+ wrapInTestApp(),
);
const tabs = container.querySelectorAll('[class*=MuiTabs-root] button');
diff --git a/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.tsx b/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.tsx
new file mode 100644
index 0000000000..6b5b63d6bd
--- /dev/null
+++ b/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.tsx
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { UserSettingsAuthProviders } from '../AuthProviders';
+import { UserSettingsFeatureFlags } from '../FeatureFlags';
+import { UserSettingsGeneral } from '../General';
+import { SettingsLayout, SettingsLayoutRouteProps } from '../SettingsLayout';
+
+/**
+ * @public
+ */
+export const DefaultSettingsPage = (props: {
+ tabs?: React.ReactElement[];
+ providerSettings?: JSX.Element;
+}) => {
+ const { providerSettings, tabs } = props;
+
+ return (
+
+
+
+
+
+
+
+
+
+
+ {tabs}
+
+ );
+};
diff --git a/plugins/user-settings/src/components/DefaultSettingsPage/index.ts b/plugins/user-settings/src/components/DefaultSettingsPage/index.ts
new file mode 100644
index 0000000000..34dcb9340d
--- /dev/null
+++ b/plugins/user-settings/src/components/DefaultSettingsPage/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export { DefaultSettingsPage } from './DefaultSettingsPage';
diff --git a/plugins/user-settings/src/components/SettingsLayout/SettingsLayout.tsx b/plugins/user-settings/src/components/SettingsLayout/SettingsLayout.tsx
new file mode 100644
index 0000000000..9855fdd048
--- /dev/null
+++ b/plugins/user-settings/src/components/SettingsLayout/SettingsLayout.tsx
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { TabProps } from '@material-ui/core';
+import {
+ Header,
+ Page,
+ RoutedTabs,
+ useSidebarPinState,
+} from '@backstage/core-components';
+import {
+ attachComponentData,
+ useElementFilter,
+} from '@backstage/core-plugin-api';
+
+/** @public */
+export type SettingsLayoutRouteProps = {
+ path: string;
+ title: string;
+ children: JSX.Element;
+ tabProps?: TabProps;
+};
+
+export const LAYOUT_DATA_KEY = 'plugin.user-settings.settingsLayout';
+export const LAYOUT_ROUTE_DATA_KEY = 'plugin.user-settings.settingsLayoutRoute';
+
+const Route: (props: SettingsLayoutRouteProps) => null = () => null;
+attachComponentData(Route, LAYOUT_ROUTE_DATA_KEY, true);
+
+// This causes all mount points that are discovered within this route to use the path of the route itself
+attachComponentData(Route, 'core.gatherMountPoints', true);
+
+/** @public */
+export type SettingsLayoutProps = {
+ title?: string;
+ subtitle?: string;
+ children?: React.ReactNode;
+};
+
+/**
+ * @public
+ */
+export const SettingsLayout = (props: SettingsLayoutProps) => {
+ const { title, children } = props;
+ const { isMobile } = useSidebarPinState();
+
+ const routes = useElementFilter(children, elements =>
+ elements
+ .selectByComponentData({
+ key: LAYOUT_ROUTE_DATA_KEY,
+ withStrictError:
+ 'Child of SettingsLayout must be an SettingsLayout.Route',
+ })
+ .getElements()
+ .map(child => child.props),
+ );
+
+ return (
+
+ {!isMobile && }
+
+
+ );
+};
+
+attachComponentData(SettingsLayout, LAYOUT_DATA_KEY, true);
+
+SettingsLayout.Route = Route;
diff --git a/plugins/user-settings/src/components/SettingsLayout/index.ts b/plugins/user-settings/src/components/SettingsLayout/index.ts
new file mode 100644
index 0000000000..6e610f8078
--- /dev/null
+++ b/plugins/user-settings/src/components/SettingsLayout/index.ts
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+export type {
+ SettingsLayoutProps,
+ SettingsLayoutRouteProps,
+} from './SettingsLayout';
+export { SettingsLayout } from './SettingsLayout';
diff --git a/plugins/user-settings/src/components/SettingsPage.tsx b/plugins/user-settings/src/components/SettingsPage.tsx
deleted file mode 100644
index 9803bf4761..0000000000
--- a/plugins/user-settings/src/components/SettingsPage.tsx
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2020 The Backstage Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import {
- Header,
- Page,
- TabbedLayout,
- useSidebarPinState,
-} from '@backstage/core-components';
-import React from 'react';
-import { useOutlet } from 'react-router';
-import { useElementFilter } from '@backstage/core-plugin-api';
-import { UserSettingsAuthProviders } from './AuthProviders';
-import { UserSettingsFeatureFlags } from './FeatureFlags';
-import { UserSettingsGeneral } from './General';
-import { USER_SETTINGS_TAB_KEY, UserSettingsTabProps } from './UserSettingsTab';
-
-/**
- * @public
- */
-export const SettingsPage = (props: { providerSettings?: JSX.Element }) => {
- const { providerSettings } = props;
- const { isMobile } = useSidebarPinState();
- const outlet = useOutlet();
-
- const tabs = useElementFilter(outlet, elements =>
- elements
- .selectByComponentData({
- key: USER_SETTINGS_TAB_KEY,
- })
- .getElements(),
- );
-
- return (
-
- {!isMobile && }
-
-
-
-
-
-
-
-
-
-
-
- {tabs.map((child, i) => (
-
- {child}
-
- ))}
-
-
- );
-};
diff --git a/plugins/user-settings/src/components/SettingsPage/SettingsPage.test.tsx b/plugins/user-settings/src/components/SettingsPage/SettingsPage.test.tsx
new file mode 100644
index 0000000000..b6277f0b59
--- /dev/null
+++ b/plugins/user-settings/src/components/SettingsPage/SettingsPage.test.tsx
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils';
+import { SettingsPage } from './SettingsPage';
+import { UserSettingsTab } from '../UserSettingsTab';
+import { useOutlet } from 'react-router';
+import { SettingsLayout } from '../SettingsLayout';
+import { screen } from '@testing-library/react';
+import userEvent from '@testing-library/user-event';
+
+jest.mock('react-router', () => ({
+ ...jest.requireActual('react-router'),
+ useOutlet: jest.fn().mockReturnValue(undefined),
+}));
+
+describe('', () => {
+ beforeEach(() => {
+ (useOutlet as jest.Mock).mockReset();
+ });
+
+ it('should render the default settings page with 3 tabs', async () => {
+ const { container } = await renderWithEffects(
+ wrapInTestApp(),
+ );
+
+ const tabs = container.querySelectorAll('[class*=MuiTabs-root] button');
+ expect(tabs).toHaveLength(3);
+ });
+
+ it('should render the default settings page with 4 tabs when extra tabs are provided via UserSettingsTab', async () => {
+ const advancedTabRoute = (
+
+ Advanced settings
+
+ );
+ (useOutlet as jest.Mock).mockReturnValue(advancedTabRoute);
+ const { container } = await renderWithEffects(
+ wrapInTestApp(),
+ );
+
+ const tabs = container.querySelectorAll('[class*=MuiTabs-root] button');
+ expect(tabs).toHaveLength(4);
+ expect(tabs[3].textContent).toEqual('Advanced');
+ });
+
+ it('should render the default settings page with 4 tabs when extra tabs are provided via SettingsLayout.Route', async () => {
+ const advancedTabRoute = (
+
+ Advanced settings
+
+ );
+ (useOutlet as jest.Mock).mockReturnValue(advancedTabRoute);
+ const { container } = await renderWithEffects(
+ wrapInTestApp(),
+ );
+
+ const tabs = container.querySelectorAll('[class*=MuiTabs-root] button');
+ expect(tabs).toHaveLength(4);
+ expect(tabs[3].textContent).toEqual('Advanced');
+ const user = userEvent.setup();
+ await user.click(screen.getByText(/Advanced/i));
+ const content = container.querySelectorAll('article');
+ expect(content[0].textContent).toEqual('Advanced settings');
+ });
+
+ it('should render the custom settings page when custom layout is provided', async () => {
+ const customLayout = (
+
+
+ User settings
+
+
+ Advanced settings
+
+
+ );
+ (useOutlet as jest.Mock).mockReturnValue(customLayout);
+ const { container } = await renderWithEffects(
+ wrapInTestApp(),
+ );
+
+ const tabs = container.querySelectorAll('[class*=MuiTabs-root] button');
+ expect(tabs).toHaveLength(2);
+ expect(tabs[0].textContent).toEqual('General');
+ expect(tabs[1].textContent).toEqual('Advanced');
+ const user = userEvent.setup();
+ await user.click(screen.getByText(/Advanced/i));
+ const content = container.querySelectorAll('article');
+ expect(content[0].textContent).toEqual('Advanced settings');
+ });
+});
diff --git a/plugins/user-settings/src/components/SettingsPage/SettingsPage.tsx b/plugins/user-settings/src/components/SettingsPage/SettingsPage.tsx
new file mode 100644
index 0000000000..eec386d60e
--- /dev/null
+++ b/plugins/user-settings/src/components/SettingsPage/SettingsPage.tsx
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { useOutlet } from 'react-router';
+import React from 'react';
+import { DefaultSettingsPage } from '../DefaultSettingsPage';
+import { useElementFilter } from '@backstage/core-plugin-api';
+import {
+ SettingsLayoutProps,
+ SettingsLayoutRouteProps,
+} from '../SettingsLayout';
+import {
+ LAYOUT_DATA_KEY,
+ LAYOUT_ROUTE_DATA_KEY,
+} from '../SettingsLayout/SettingsLayout';
+
+/** @public */
+export const SettingsPage = (props: { providerSettings?: JSX.Element }) => {
+ const { providerSettings } = props;
+ const outlet = useOutlet();
+ const layout = useElementFilter(outlet, elements =>
+ elements
+ .selectByComponentData({
+ key: LAYOUT_DATA_KEY,
+ })
+ .getElements(),
+ );
+ const tabs = useElementFilter(outlet, elements =>
+ elements
+ .selectByComponentData({
+ key: LAYOUT_ROUTE_DATA_KEY,
+ })
+ .getElements(),
+ );
+
+ return (
+ <>
+ {(layout.length !== 0 && layout) || (
+
+ )}
+ >
+ );
+};
diff --git a/plugins/user-settings/src/components/SettingsPage/index.ts b/plugins/user-settings/src/components/SettingsPage/index.ts
new file mode 100644
index 0000000000..e957a1bf09
--- /dev/null
+++ b/plugins/user-settings/src/components/SettingsPage/index.ts
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2022 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export { SettingsPage } from './SettingsPage';
diff --git a/plugins/user-settings/src/components/UserSettingsTab/UserSettingsTab.tsx b/plugins/user-settings/src/components/UserSettingsTab/UserSettingsTab.tsx
index 171c54ecf3..ebddac00c1 100644
--- a/plugins/user-settings/src/components/UserSettingsTab/UserSettingsTab.tsx
+++ b/plugins/user-settings/src/components/UserSettingsTab/UserSettingsTab.tsx
@@ -15,11 +15,15 @@
*/
import React, { PropsWithChildren } from 'react';
import { attachComponentData } from '@backstage/core-plugin-api';
+import {
+ LAYOUT_ROUTE_DATA_KEY,
+ SettingsLayout,
+} from '../SettingsLayout/SettingsLayout';
-/** @public */
-export const USER_SETTINGS_TAB_KEY = 'user-settings.tab';
+/** @public @deprecated Use SettingsLayout.Route approach instead */
+export const USER_SETTINGS_TAB_KEY = LAYOUT_ROUTE_DATA_KEY;
-/** @public */
+/** @public @deprecated Use SettingsLayoutRouteProps instead */
export type UserSettingsTabProps = PropsWithChildren<{
/**
* The path to the tab in the settings route
@@ -34,9 +38,12 @@ export type UserSettingsTabProps = PropsWithChildren<{
* Renders a tab inside the settings page
* @param props - Component props
* @public
+ * @deprecated Use SettingsLayout.Route instead
*/
-export const UserSettingsTab = (props: UserSettingsTabProps) => {
- return <>{props.children}>;
-};
+export const UserSettingsTab = (props: UserSettingsTabProps) => (
+
+ <>props.children>
+
+);
attachComponentData(UserSettingsTab, USER_SETTINGS_TAB_KEY, 'UserSettingsTab');
diff --git a/plugins/user-settings/src/components/index.ts b/plugins/user-settings/src/components/index.ts
index 8dc76ee7f1..8eb43a7a10 100644
--- a/plugins/user-settings/src/components/index.ts
+++ b/plugins/user-settings/src/components/index.ts
@@ -21,3 +21,4 @@ export * from './General';
export * from './FeatureFlags';
export { useUserProfile } from './useUserProfileInfo';
export * from './UserSettingsTab';
+export * from './SettingsLayout';