mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Sidemenu: Refactor TopSectionItem and BottomNavLinks into SideMenuItem (#38755)
* Sidemenu: Refactor TopSectionItem and BottomNavLinks into SideMenuItem * Update failing snapshot * BottomSection: Convert tests to RTL + add some extra unit tests
This commit is contained in:
parent
92934af741
commit
205c672417
@ -1,115 +0,0 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import appEvents from '../../app_events';
|
||||
import { ShowModalReactEvent } from '../../../types/events';
|
||||
import { HelpModal } from '../help/HelpModal';
|
||||
import BottomNavLinks from './BottomNavLinks';
|
||||
|
||||
jest.mock('../../app_events', () => ({
|
||||
publish: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('BottomNavLinks', () => {
|
||||
const mockUser = {
|
||||
id: 1,
|
||||
isGrafanaAdmin: false,
|
||||
isSignedIn: false,
|
||||
orgCount: 2,
|
||||
orgRole: '',
|
||||
orgId: 1,
|
||||
login: 'hello',
|
||||
orgName: 'mockOrganization',
|
||||
timezone: 'UTC',
|
||||
helpFlags1: 1,
|
||||
lightTheme: false,
|
||||
hasEditPermissionInFolders: false,
|
||||
};
|
||||
|
||||
it('renders the link text', () => {
|
||||
const mockLink = {
|
||||
text: 'Hello',
|
||||
};
|
||||
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<BottomNavLinks link={mockLink} user={mockUser} />
|
||||
</BrowserRouter>
|
||||
);
|
||||
const linkText = screen.getByText(mockLink.text);
|
||||
expect(linkText).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('attaches the link url to the text if provided', () => {
|
||||
const mockLink = {
|
||||
text: 'Hello',
|
||||
url: '/route',
|
||||
};
|
||||
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<BottomNavLinks link={mockLink} user={mockUser} />
|
||||
</BrowserRouter>
|
||||
);
|
||||
const link = screen.getByRole('link', { name: mockLink.text });
|
||||
expect(link).toBeInTheDocument();
|
||||
expect(link).toHaveAttribute('href', mockLink.url);
|
||||
});
|
||||
|
||||
it('creates the correct children for the help link', () => {
|
||||
const mockLink = {
|
||||
id: 'help',
|
||||
text: 'Hello',
|
||||
};
|
||||
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<BottomNavLinks link={mockLink} user={mockUser} />
|
||||
</BrowserRouter>
|
||||
);
|
||||
const documentation = screen.getByRole('link', { name: 'Documentation' });
|
||||
const support = screen.getByRole('link', { name: 'Support' });
|
||||
const community = screen.getByRole('link', { name: 'Community' });
|
||||
const keyboardShortcuts = screen.getByText('Keyboard shortcuts');
|
||||
|
||||
expect(documentation).toBeInTheDocument();
|
||||
expect(support).toBeInTheDocument();
|
||||
expect(community).toBeInTheDocument();
|
||||
expect(keyboardShortcuts).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('clicking the keyboard shortcuts button shows the modal', () => {
|
||||
const mockLink = {
|
||||
id: 'help',
|
||||
text: 'Hello',
|
||||
};
|
||||
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<BottomNavLinks link={mockLink} user={mockUser} />
|
||||
</BrowserRouter>
|
||||
);
|
||||
const keyboardShortcuts = screen.getByText('Keyboard shortcuts');
|
||||
expect(keyboardShortcuts).toBeInTheDocument();
|
||||
userEvent.click(keyboardShortcuts);
|
||||
expect(appEvents.publish).toHaveBeenCalledWith(new ShowModalReactEvent({ component: HelpModal }));
|
||||
});
|
||||
|
||||
it('shows the current organization and organization switcher if showOrgSwitcher is true', () => {
|
||||
const mockLink = {
|
||||
showOrgSwitcher: true,
|
||||
text: 'Hello',
|
||||
};
|
||||
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<BottomNavLinks link={mockLink} user={mockUser} />
|
||||
</BrowserRouter>
|
||||
);
|
||||
const currentOrg = screen.getByText(new RegExp(mockUser.orgName, 'i'));
|
||||
const orgSwitcher = screen.getByText('Switch organization');
|
||||
expect(currentOrg).toBeInTheDocument();
|
||||
expect(orgSwitcher).toBeInTheDocument();
|
||||
});
|
||||
});
|
@ -1,83 +0,0 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import appEvents from '../../app_events';
|
||||
import { User } from '../../services/context_srv';
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { Icon, IconName, Link } from '@grafana/ui';
|
||||
import { OrgSwitcher } from '../OrgSwitcher';
|
||||
import { getFooterLinks } from '../Footer/Footer';
|
||||
import { ShowModalReactEvent } from '../../../types/events';
|
||||
import { HelpModal } from '../help/HelpModal';
|
||||
import SideMenuDropDown from './SideMenuDropDown';
|
||||
|
||||
export interface Props {
|
||||
link: NavModelItem;
|
||||
user: User;
|
||||
}
|
||||
|
||||
interface State {
|
||||
showSwitcherModal: boolean;
|
||||
}
|
||||
|
||||
export default class BottomNavLinks extends PureComponent<Props, State> {
|
||||
state: State = {
|
||||
showSwitcherModal: false,
|
||||
};
|
||||
|
||||
onOpenShortcuts = () => {
|
||||
appEvents.publish(new ShowModalReactEvent({ component: HelpModal }));
|
||||
};
|
||||
|
||||
toggleSwitcherModal = () => {
|
||||
this.setState((prevState) => ({
|
||||
showSwitcherModal: !prevState.showSwitcherModal,
|
||||
}));
|
||||
};
|
||||
|
||||
render() {
|
||||
const { link, user } = this.props;
|
||||
const { showSwitcherModal } = this.state;
|
||||
|
||||
let children = link.children || [];
|
||||
|
||||
if (link.id === 'help') {
|
||||
children = [
|
||||
...getFooterLinks(),
|
||||
{
|
||||
text: 'Keyboard shortcuts',
|
||||
icon: 'keyboard',
|
||||
onClick: this.onOpenShortcuts,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (link.showOrgSwitcher) {
|
||||
children = [
|
||||
...children,
|
||||
{
|
||||
text: 'Switch organization',
|
||||
icon: 'arrow-random',
|
||||
onClick: this.toggleSwitcherModal,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="sidemenu-item dropdown dropup">
|
||||
<Link href={link.url} className="sidemenu-link" target={link.target}>
|
||||
<span className="icon-circle sidemenu-icon">
|
||||
{link.icon && <Icon name={link.icon as IconName} size="xl" title="Help icon" />}
|
||||
{link.img && <img src={link.img} alt="Profile picture" />}
|
||||
</span>
|
||||
</Link>
|
||||
<SideMenuDropDown
|
||||
headerText={link.text}
|
||||
headerUrl={link.url}
|
||||
items={children}
|
||||
reverseDirection
|
||||
subtitleText={link.showOrgSwitcher ? `Current Org.: ${user.orgName}` : link.subTitle}
|
||||
/>
|
||||
{showSwitcherModal && <OrgSwitcher onDismiss={this.toggleSwitcherModal} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -1,7 +1,14 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { ShowModalReactEvent } from '../../../types/events';
|
||||
import { HelpModal } from '../help/HelpModal';
|
||||
import appEvents from '../../app_events';
|
||||
import BottomSection from './BottomSection';
|
||||
|
||||
jest.mock('../../app_events', () => ({
|
||||
publish: jest.fn(),
|
||||
}));
|
||||
jest.mock('../../config', () => ({
|
||||
bootData: {
|
||||
navTree: [
|
||||
@ -10,6 +17,7 @@ jest.mock('../../config', () => ({
|
||||
hideFromMenu: true,
|
||||
},
|
||||
{
|
||||
id: 'help',
|
||||
hideFromMenu: true,
|
||||
},
|
||||
{
|
||||
@ -20,25 +28,56 @@ jest.mock('../../config', () => ({
|
||||
},
|
||||
],
|
||||
},
|
||||
user: {
|
||||
orgCount: 5,
|
||||
orgName: 'Grafana',
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('app/core/services/context_srv', () => ({
|
||||
contextSrv: {
|
||||
sidemenu: true,
|
||||
isSignedIn: false,
|
||||
isSignedIn: true,
|
||||
isGrafanaAdmin: false,
|
||||
hasEditPermissionFolders: false,
|
||||
user: {
|
||||
orgCount: 5,
|
||||
orgName: 'Grafana',
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe('Render', () => {
|
||||
it('should render component', () => {
|
||||
const wrapper = shallow(<BottomSection />);
|
||||
describe('BottomSection', () => {
|
||||
it('should render the correct children', () => {
|
||||
render(<BottomSection />);
|
||||
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(screen.getByTestId('bottom-section-items').children.length).toBe(3);
|
||||
});
|
||||
|
||||
it('creates the correct children for the help link', () => {
|
||||
render(<BottomSection />);
|
||||
|
||||
const documentation = screen.getByRole('link', { name: 'Documentation' });
|
||||
const support = screen.getByRole('link', { name: 'Support' });
|
||||
const community = screen.getByRole('link', { name: 'Community' });
|
||||
const keyboardShortcuts = screen.getByText('Keyboard shortcuts');
|
||||
expect(documentation).toBeInTheDocument();
|
||||
expect(support).toBeInTheDocument();
|
||||
expect(community).toBeInTheDocument();
|
||||
expect(keyboardShortcuts).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('clicking the keyboard shortcuts button shows the modal', () => {
|
||||
render(<BottomSection />);
|
||||
|
||||
const keyboardShortcuts = screen.getByText('Keyboard shortcuts');
|
||||
expect(keyboardShortcuts).toBeInTheDocument();
|
||||
|
||||
userEvent.click(keyboardShortcuts);
|
||||
expect(appEvents.publish).toHaveBeenCalledWith(new ShowModalReactEvent({ component: HelpModal }));
|
||||
});
|
||||
|
||||
it('shows the current organization and organization switcher if showOrgSwitcher is true', () => {
|
||||
render(<BottomSection />);
|
||||
|
||||
const currentOrg = screen.getByText(new RegExp('Grafana', 'i'));
|
||||
const orgSwitcher = screen.getByText('Switch organization');
|
||||
expect(currentOrg).toBeInTheDocument();
|
||||
expect(orgSwitcher).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -1,30 +1,85 @@
|
||||
import React from 'react';
|
||||
import { cloneDeep, find } from 'lodash';
|
||||
import { SignIn } from './SignIn';
|
||||
import BottomNavLinks from './BottomNavLinks';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import config from '../../config';
|
||||
import React, { useState } from 'react';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { Icon, IconName } from '@grafana/ui';
|
||||
import appEvents from '../../app_events';
|
||||
import { SignIn } from './SignIn';
|
||||
import SideMenuItem from './SideMenuItem';
|
||||
import { ShowModalReactEvent } from '../../../types/events';
|
||||
import { contextSrv } from 'app/core/services/context_srv';
|
||||
import { OrgSwitcher } from '../OrgSwitcher';
|
||||
import { getFooterLinks } from '../Footer/Footer';
|
||||
import { HelpModal } from '../help/HelpModal';
|
||||
import config from '../../config';
|
||||
|
||||
export default function BottomSection() {
|
||||
const navTree: NavModelItem[] = cloneDeep(config.bootData.navTree);
|
||||
const bottomNav: NavModelItem[] = navTree.filter((item) => item.hideFromMenu);
|
||||
const bottomNav = navTree.filter((item) => item.hideFromMenu);
|
||||
const isSignedIn = contextSrv.isSignedIn;
|
||||
const user = contextSrv.user;
|
||||
const [showSwitcherModal, setShowSwitcherModal] = useState(false);
|
||||
|
||||
const toggleSwitcherModal = () => {
|
||||
setShowSwitcherModal(!showSwitcherModal);
|
||||
};
|
||||
|
||||
const onOpenShortcuts = () => {
|
||||
appEvents.publish(new ShowModalReactEvent({ component: HelpModal }));
|
||||
};
|
||||
|
||||
if (user && user.orgCount > 1) {
|
||||
const profileNode: any = find(bottomNav, { id: 'profile' });
|
||||
const profileNode = bottomNav.find((bottomNavItem) => bottomNavItem.id === 'profile');
|
||||
if (profileNode) {
|
||||
profileNode.showOrgSwitcher = true;
|
||||
profileNode.subTitle = `Current Org.: ${user?.orgName}`;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="sidemenu__bottom">
|
||||
<div data-testid="bottom-section-items" className="sidemenu__bottom">
|
||||
{!isSignedIn && <SignIn />}
|
||||
{bottomNav.map((link, index) => {
|
||||
return <BottomNavLinks link={link} user={user} key={`${link.url}-${index}`} />;
|
||||
let menuItems = link.children || [];
|
||||
|
||||
if (link.id === 'help') {
|
||||
menuItems = [
|
||||
...getFooterLinks(),
|
||||
{
|
||||
text: 'Keyboard shortcuts',
|
||||
icon: 'keyboard',
|
||||
onClick: onOpenShortcuts,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (link.showOrgSwitcher) {
|
||||
menuItems = [
|
||||
...menuItems,
|
||||
{
|
||||
text: 'Switch organization',
|
||||
icon: 'arrow-random',
|
||||
onClick: toggleSwitcherModal,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return (
|
||||
<SideMenuItem
|
||||
key={`${link.url}-${index}`}
|
||||
label={link.text}
|
||||
menuItems={menuItems}
|
||||
menuSubTitle={link.subTitle}
|
||||
onClick={link.onClick}
|
||||
reverseMenuDirection
|
||||
target={link.target}
|
||||
url={link.url}
|
||||
>
|
||||
{link.icon && <Icon name={link.icon as IconName} size="xl" />}
|
||||
{link.img && <img src={link.img} />}
|
||||
</SideMenuItem>
|
||||
);
|
||||
})}
|
||||
{showSwitcherModal && <OrgSwitcher onDismiss={toggleSwitcherModal} />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
55
public/app/core/components/sidemenu/SideMenuItem.test.tsx
Normal file
55
public/app/core/components/sidemenu/SideMenuItem.test.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import SideMenuItem from './SideMenuItem';
|
||||
|
||||
describe('SideMenuItem', () => {
|
||||
it('renders the children', () => {
|
||||
const mockLabel = 'Hello';
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<SideMenuItem label={mockLabel}>
|
||||
<div data-testid="mockChild" />
|
||||
</SideMenuItem>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
const child = screen.getByTestId('mockChild');
|
||||
expect(child).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('wraps the children in a link to the url if provided', () => {
|
||||
const mockLabel = 'Hello';
|
||||
const mockUrl = '/route';
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<SideMenuItem label={mockLabel} url={mockUrl}>
|
||||
<div data-testid="mockChild" />
|
||||
</SideMenuItem>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
const child = screen.getByTestId('mockChild');
|
||||
expect(child).toBeInTheDocument();
|
||||
userEvent.click(child);
|
||||
expect(window.location.pathname).toEqual(mockUrl);
|
||||
});
|
||||
|
||||
it('wraps the children in an onClick if provided', () => {
|
||||
const mockLabel = 'Hello';
|
||||
const mockOnClick = jest.fn();
|
||||
render(
|
||||
<BrowserRouter>
|
||||
<SideMenuItem label={mockLabel} onClick={mockOnClick}>
|
||||
<div data-testid="mockChild" />
|
||||
</SideMenuItem>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
||||
const child = screen.getByTestId('mockChild');
|
||||
expect(child).toBeInTheDocument();
|
||||
userEvent.click(child);
|
||||
expect(mockOnClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
67
public/app/core/components/sidemenu/SideMenuItem.tsx
Normal file
67
public/app/core/components/sidemenu/SideMenuItem.tsx
Normal file
@ -0,0 +1,67 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import SideMenuDropDown from './SideMenuDropDown';
|
||||
import { Link, useStyles2 } from '@grafana/ui';
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { css, cx } from '@emotion/css';
|
||||
|
||||
export interface Props {
|
||||
children: ReactNode;
|
||||
label: string;
|
||||
menuItems?: NavModelItem[];
|
||||
menuSubTitle?: string;
|
||||
onClick?: () => void;
|
||||
reverseMenuDirection?: boolean;
|
||||
target?: HTMLAnchorElement['target'];
|
||||
url?: string;
|
||||
}
|
||||
|
||||
const SideMenuItem = ({
|
||||
children,
|
||||
label,
|
||||
menuItems = [],
|
||||
menuSubTitle,
|
||||
onClick,
|
||||
reverseMenuDirection = false,
|
||||
target,
|
||||
url,
|
||||
}: Props) => {
|
||||
const resetButtonStyles = useStyles2(
|
||||
() =>
|
||||
css`
|
||||
background-color: transparent;
|
||||
`
|
||||
);
|
||||
|
||||
const anchor = url ? (
|
||||
<Link
|
||||
className="sidemenu-link"
|
||||
href={url}
|
||||
target={target}
|
||||
aria-label={label}
|
||||
onClick={onClick}
|
||||
aria-haspopup="true"
|
||||
>
|
||||
<span className="icon-circle sidemenu-icon">{children}</span>
|
||||
</Link>
|
||||
) : (
|
||||
<button className={cx(resetButtonStyles, 'sidemenu-link')} onClick={onClick} aria-label={label}>
|
||||
<span className="icon-circle sidemenu-icon">{children}</span>
|
||||
</button>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={cx('sidemenu-item', 'dropdown', { dropup: reverseMenuDirection })}>
|
||||
{anchor}
|
||||
<SideMenuDropDown
|
||||
headerText={label}
|
||||
headerUrl={url}
|
||||
items={menuItems}
|
||||
onHeaderClick={onClick}
|
||||
reverseDirection={reverseMenuDirection}
|
||||
subtitleText={menuSubTitle}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SideMenuItem;
|
@ -1,16 +1,14 @@
|
||||
import React, { FC } from 'react';
|
||||
import { cloneDeep, filter } from 'lodash';
|
||||
import TopSectionItem from './TopSectionItem';
|
||||
import config from '../../config';
|
||||
import React from 'react';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { Icon, IconName } from '@grafana/ui';
|
||||
import SideMenuItem from './SideMenuItem';
|
||||
import config from '../../config';
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
|
||||
const TopSection: FC<any> = () => {
|
||||
const navTree = cloneDeep(config.bootData.navTree);
|
||||
const mainLinks = filter(navTree, (item) => !item.hideFromMenu);
|
||||
const searchLink = {
|
||||
text: 'Search dashboards',
|
||||
icon: 'search',
|
||||
};
|
||||
const TopSection = () => {
|
||||
const navTree: NavModelItem[] = cloneDeep(config.bootData.navTree);
|
||||
const mainLinks = navTree.filter((item) => !item.hideFromMenu);
|
||||
|
||||
const onOpenSearch = () => {
|
||||
locationService.partial({ search: 'open' });
|
||||
@ -18,9 +16,22 @@ const TopSection: FC<any> = () => {
|
||||
|
||||
return (
|
||||
<div data-testid="top-section-items" className="sidemenu__top">
|
||||
<TopSectionItem link={searchLink} onClick={onOpenSearch} />
|
||||
<SideMenuItem label="Search dashboards" onClick={onOpenSearch}>
|
||||
<Icon name="search" size="xl" />
|
||||
</SideMenuItem>
|
||||
{mainLinks.map((link, index) => {
|
||||
return <TopSectionItem link={link} key={`${link.id}-${index}`} />;
|
||||
return (
|
||||
<SideMenuItem
|
||||
key={`${link.id}-${index}`}
|
||||
label={link.text}
|
||||
menuItems={link.children}
|
||||
target={link.target}
|
||||
url={link.url}
|
||||
>
|
||||
{link.icon && <Icon name={link.icon as IconName} size="xl" />}
|
||||
{link.img && <img src={link.img} />}
|
||||
</SideMenuItem>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
|
@ -1,31 +0,0 @@
|
||||
import React from 'react';
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import TopSectionItem from './TopSectionItem';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props = Object.assign(
|
||||
{
|
||||
link: {
|
||||
text: 'Hello',
|
||||
icon: 'cloud',
|
||||
url: '/asd',
|
||||
},
|
||||
},
|
||||
propOverrides
|
||||
);
|
||||
|
||||
return render(
|
||||
<MemoryRouter initialEntries={[{ pathname: '/', key: 'testKey' }]}>
|
||||
<TopSectionItem {...props} />
|
||||
</MemoryRouter>
|
||||
);
|
||||
};
|
||||
|
||||
describe('Render', () => {
|
||||
it('should render component', () => {
|
||||
setup();
|
||||
expect(screen.getByText('Hello')).toBeInTheDocument();
|
||||
expect(screen.getByRole('menu')).toHaveTextContent('Hello');
|
||||
});
|
||||
});
|
@ -1,51 +0,0 @@
|
||||
import React, { FC } from 'react';
|
||||
import SideMenuDropDown from './SideMenuDropDown';
|
||||
import { Icon, Link, useStyles2 } from '@grafana/ui';
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { css, cx } from '@emotion/css';
|
||||
|
||||
export interface Props {
|
||||
link: NavModelItem;
|
||||
onClick?: () => void;
|
||||
}
|
||||
|
||||
const TopSectionItem: FC<Props> = ({ link, onClick }) => {
|
||||
const resetButtonStyles = useStyles2(
|
||||
() =>
|
||||
css`
|
||||
background-color: transparent;
|
||||
`
|
||||
);
|
||||
|
||||
const linkContent = (
|
||||
<span className="icon-circle sidemenu-icon">
|
||||
{link.icon && <Icon name={link.icon as any} size="xl" />}
|
||||
{link.img && <img src={link.img} />}
|
||||
</span>
|
||||
);
|
||||
|
||||
const anchor = link.url ? (
|
||||
<Link
|
||||
className="sidemenu-link"
|
||||
href={link.url}
|
||||
target={link.target}
|
||||
aria-label={link.text}
|
||||
onClick={onClick}
|
||||
aria-haspopup="true"
|
||||
>
|
||||
{linkContent}
|
||||
</Link>
|
||||
) : (
|
||||
<button className={cx(resetButtonStyles, 'sidemenu-link')} onClick={onClick} aria-label={link.text}>
|
||||
{linkContent}
|
||||
</button>
|
||||
);
|
||||
return (
|
||||
<div className="sidemenu-item dropdown">
|
||||
{anchor}
|
||||
<SideMenuDropDown items={link.children} headerText={link.text} headerUrl={link.url} onHeaderClick={onClick} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default TopSectionItem;
|
@ -1,34 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<div
|
||||
className="sidemenu__bottom"
|
||||
>
|
||||
<SignIn />
|
||||
<BottomNavLinks
|
||||
key="undefined-0"
|
||||
link={
|
||||
Object {
|
||||
"hideFromMenu": true,
|
||||
"id": "profile",
|
||||
}
|
||||
}
|
||||
/>
|
||||
<BottomNavLinks
|
||||
key="undefined-1"
|
||||
link={
|
||||
Object {
|
||||
"hideFromMenu": true,
|
||||
}
|
||||
}
|
||||
/>
|
||||
<BottomNavLinks
|
||||
key="undefined-2"
|
||||
link={
|
||||
Object {
|
||||
"hideFromMenu": true,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
`;
|
Loading…
Reference in New Issue
Block a user