Added the ability for SidebarSubmenuItem to use external links via "to" property
Signed-off-by: Jonathan Ash <jonathan-ash@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/core-components': patch
|
||||
---
|
||||
|
||||
Added ability for SidebarSubmenuItem to handle external links correctly via the "to" prop
|
||||
@@ -46,6 +46,11 @@ async function renderScalableSidebar() {
|
||||
<SidebarItem icon={MenuBookIcon} onClick={() => {}} text="Catalog">
|
||||
<SidebarSubmenu title="Catalog">
|
||||
<SidebarSubmenuItem title="Tools" to="/1" icon={BuildRoundedIcon} />
|
||||
<SidebarSubmenuItem
|
||||
title="External Link"
|
||||
to="https://backstage.io/"
|
||||
icon={BuildRoundedIcon}
|
||||
/>
|
||||
<SidebarSubmenuItem
|
||||
title="Misc"
|
||||
to="/6"
|
||||
@@ -59,6 +64,10 @@ async function renderScalableSidebar() {
|
||||
title: 'dropdown item 2',
|
||||
to: '/dropdownitemlink2',
|
||||
},
|
||||
{
|
||||
title: 'dropdown item 3',
|
||||
to: 'https://backstage.io/',
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</SidebarSubmenu>
|
||||
@@ -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/',
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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<BackstageTheme>(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) => {
|
||||
<div className={classes.dropdown}>
|
||||
{dropdownItems.map((object, key) => (
|
||||
<Link
|
||||
component={NavLink}
|
||||
component={isExternalLink(object.to) ? BackstageLink : NavLink}
|
||||
to={object.to}
|
||||
underline="none"
|
||||
className={classes.dropdownItem}
|
||||
@@ -185,7 +188,7 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => {
|
||||
return (
|
||||
<div className={classes.itemContainer}>
|
||||
<Link
|
||||
component={NavLink}
|
||||
component={isExternalLink(to) ? BackstageLink : NavLink}
|
||||
to={to}
|
||||
underline="none"
|
||||
className={classnames(
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { Location, Path } from 'history';
|
||||
import { isLocationMatch } from './utils';
|
||||
import { isExternalLink, isLocationMatch } from './utils';
|
||||
|
||||
describe('isLocationMatching', () => {
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,3 +33,5 @@ export function isLocationMatch(currentLocation: Location, toLocation: Path) {
|
||||
|
||||
return matching;
|
||||
}
|
||||
|
||||
export const isExternalLink = (link: string) => /^http/.test(link);
|
||||
|
||||
Reference in New Issue
Block a user