diff --git a/plugins/user-settings/api-report.md b/plugins/user-settings/api-report.md index f83c97ff73..dd8f9428ca 100644 --- a/plugins/user-settings/api-report.md +++ b/plugins/user-settings/api-report.md @@ -17,6 +17,7 @@ import { JsonValue } from '@backstage/types'; 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'; @@ -69,6 +70,9 @@ export type SettingsLayoutRouteProps = { >; }; +// @public @deprecated (undocumented) +export const USER_SETTINGS_TAB_KEY = 'plugin.user-settings.settingsLayoutRoute'; + // @public (undocumented) export const UserSettingsAppearanceCard: () => JSX.Element; @@ -140,6 +144,15 @@ export class UserSettingsStorage implements StorageApi { snapshot(key: string): StorageValueSnapshot; } +// @public @deprecated +export const UserSettingsTab: (props: UserSettingsTabProps) => JSX.Element; + +// @public @deprecated (undocumented) +export type UserSettingsTabProps = PropsWithChildren<{ + path: string; + title: string; +}>; + // @public (undocumented) export const UserSettingsThemeToggle: () => JSX.Element; diff --git a/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.test.tsx b/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.test.tsx index 54f10a4c5a..d4560bdd06 100644 --- a/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.test.tsx +++ b/plugins/user-settings/src/components/DefaultSettingsPage/DefaultSettingsPage.test.tsx @@ -17,6 +17,7 @@ import React from 'react'; import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils'; import { DefaultSettingsPage } from './DefaultSettingsPage'; +import { UserSettingsTab } from '../UserSettingsTab'; import { useOutlet } from 'react-router'; import { SettingsLayout } from '../SettingsLayout'; @@ -39,7 +40,22 @@ describe('', () => { 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
+
+ ); + 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 settings page with 4 tabs when extra tabs are provided via SettingsLayout.Route', async () => { const advancedTabRoute = (
Advanced settings
diff --git a/plugins/user-settings/src/components/SettingsLayout/SettingsLayout.tsx b/plugins/user-settings/src/components/SettingsLayout/SettingsLayout.tsx index ac6e34ced9..9855fdd048 100644 --- a/plugins/user-settings/src/components/SettingsLayout/SettingsLayout.tsx +++ b/plugins/user-settings/src/components/SettingsLayout/SettingsLayout.tsx @@ -35,8 +35,8 @@ export type SettingsLayoutRouteProps = { tabProps?: TabProps; }; -export const LAYOUT_ROUTE_DATA_KEY = 'plugin.user-settings.settingsLayoutRoute'; 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); diff --git a/plugins/user-settings/src/components/SettingsPage/SettingsPage.test.tsx b/plugins/user-settings/src/components/SettingsPage/SettingsPage.test.tsx index c2fc3d63b0..b6277f0b59 100644 --- a/plugins/user-settings/src/components/SettingsPage/SettingsPage.test.tsx +++ b/plugins/user-settings/src/components/SettingsPage/SettingsPage.test.tsx @@ -17,8 +17,11 @@ 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'), @@ -39,7 +42,23 @@ describe('', () => { expect(tabs).toHaveLength(3); }); - it('should render the default settings page with 4 tabs when extra tabs are provided', async () => { + 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
@@ -53,6 +72,10 @@ describe('', () => { 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 () => { @@ -75,5 +98,9 @@ describe('', () => { 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/UserSettingsTab/UserSettingsTab.tsx b/plugins/user-settings/src/components/UserSettingsTab/UserSettingsTab.tsx new file mode 100644 index 0000000000..ebddac00c1 --- /dev/null +++ b/plugins/user-settings/src/components/UserSettingsTab/UserSettingsTab.tsx @@ -0,0 +1,49 @@ +/* + * 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 React, { PropsWithChildren } from 'react'; +import { attachComponentData } from '@backstage/core-plugin-api'; +import { + LAYOUT_ROUTE_DATA_KEY, + SettingsLayout, +} from '../SettingsLayout/SettingsLayout'; + +/** @public @deprecated Use SettingsLayout.Route approach instead */ +export const USER_SETTINGS_TAB_KEY = LAYOUT_ROUTE_DATA_KEY; + +/** @public @deprecated Use SettingsLayoutRouteProps instead */ +export type UserSettingsTabProps = PropsWithChildren<{ + /** + * The path to the tab in the settings route + * @example `/settings/advanced` + */ + path: string; + /** The title of the tab. It will also reflect in the document title when the tab is active */ + title: string; +}>; + +/** + * Renders a tab inside the settings page + * @param props - Component props + * @public + * @deprecated Use SettingsLayout.Route instead + */ +export const UserSettingsTab = (props: UserSettingsTabProps) => ( + + <>props.children + +); + +attachComponentData(UserSettingsTab, USER_SETTINGS_TAB_KEY, 'UserSettingsTab'); diff --git a/plugins/user-settings/src/components/UserSettingsTab/index.ts b/plugins/user-settings/src/components/UserSettingsTab/index.ts new file mode 100644 index 0000000000..d0645d4efb --- /dev/null +++ b/plugins/user-settings/src/components/UserSettingsTab/index.ts @@ -0,0 +1,17 @@ +/* + * 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. + */ + +export * from './UserSettingsTab'; diff --git a/plugins/user-settings/src/components/index.ts b/plugins/user-settings/src/components/index.ts index deb2761628..8eb43a7a10 100644 --- a/plugins/user-settings/src/components/index.ts +++ b/plugins/user-settings/src/components/index.ts @@ -20,4 +20,5 @@ export * from './AuthProviders'; export * from './General'; export * from './FeatureFlags'; export { useUserProfile } from './useUserProfileInfo'; +export * from './UserSettingsTab'; export * from './SettingsLayout';