From 689840dcbe028b23748ec1c04a9a6f0e50bfacf7 Mon Sep 17 00:00:00 2001 From: Jonathan Ash Date: Wed, 16 Feb 2022 10:52:17 +0000 Subject: [PATCH] Added the ability for SidebarSubmenuItem to use external links via "to" property Signed-off-by: Jonathan Ash --- .changeset/unlucky-queens-brush.md | 5 ++++ .../src/layout/Sidebar/Bar.test.tsx | 26 +++++++++++++++++++ .../src/layout/Sidebar/SidebarSubmenuItem.tsx | 7 +++-- .../src/layout/Sidebar/utils.test.ts | 14 +++++++++- .../src/layout/Sidebar/utils.ts | 2 ++ 5 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 .changeset/unlucky-queens-brush.md diff --git a/.changeset/unlucky-queens-brush.md b/.changeset/unlucky-queens-brush.md new file mode 100644 index 0000000000..c080856246 --- /dev/null +++ b/.changeset/unlucky-queens-brush.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + +Added ability for SidebarSubmenuItem to handle external links correctly via the "to" prop diff --git a/packages/core-components/src/layout/Sidebar/Bar.test.tsx b/packages/core-components/src/layout/Sidebar/Bar.test.tsx index 89133997f9..fc42e7a94e 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.test.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.test.tsx @@ -46,6 +46,11 @@ async function renderScalableSidebar() { {}} text="Catalog"> + @@ -112,5 +121,22 @@ describe('Sidebar', () => { '/dropdownitemlink', ); }); + + it('Submenu item renders an external link when `to` value is provided', async () => { + userEvent.hover(screen.getByTestId('item-with-submenu')); + expect(screen.getByText('External Link').closest('a')).toHaveAttribute( + 'href', + 'https://backstage.io/', + ); + }); + + it('Dropdown item in submenu renders an external link when `to` value is provided', async () => { + userEvent.hover(screen.getByTestId('item-with-submenu')); + userEvent.click(screen.getByText('Misc')); + expect(screen.getByText('dropdown item 3').closest('a')).toHaveAttribute( + 'href', + 'https://backstage.io/', + ); + }); }); }); diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx index 1ede5f887e..1d697ead14 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx @@ -30,6 +30,8 @@ import ArrowDropDownIcon from '@material-ui/icons/ArrowDropDown'; import ArrowDropUpIcon from '@material-ui/icons/ArrowDropUp'; import { SidebarItemWithSubmenuContext } from './config'; import { isLocationMatch } from './utils'; +import { Link as BackstageLink } from '../../'; +import { isExternalLink } from './utils'; const useStyles = makeStyles(theme => ({ item: { @@ -133,6 +135,7 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => { const handleClickDropdown = () => { setShowDropDown(!showDropDown); }; + if (dropdownItems !== undefined) { dropdownItems.some(item => { const resolvedPath = resolvePath(item.to); @@ -163,7 +166,7 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => {
{dropdownItems.map((object, key) => ( { return (
{ let currentLocation: Location; @@ -96,3 +96,15 @@ describe('isLocationMatching', () => { expect(isLocationMatch(currentLocation, toLocation)).toBe(true); }); }); + +describe('isExternalLink', () => { + beforeEach(() => expect.hasAssertions()); + + it('should return true if provided with an external link', () => { + expect(isExternalLink('https://backstage.io/')).toEqual(true); + }); + + it('should return false if provided with a relative link', () => { + expect(isExternalLink('catalog')).toEqual(false); + }); +}); diff --git a/packages/core-components/src/layout/Sidebar/utils.ts b/packages/core-components/src/layout/Sidebar/utils.ts index 1afebe796d..7c85110aca 100644 --- a/packages/core-components/src/layout/Sidebar/utils.ts +++ b/packages/core-components/src/layout/Sidebar/utils.ts @@ -33,3 +33,5 @@ export function isLocationMatch(currentLocation: Location, toLocation: Path) { return matching; } + +export const isExternalLink = (link: string) => /^http/.test(link);