refactor: Use Antd Menu in Menu component (#11528)

* Menu dropdown refactored

* MenuObject refactored

* Fix unit tests

* Style menu

* Use theme variables
This commit is contained in:
Kamil Gabryjelski 2020-11-04 01:19:15 +01:00 committed by GitHub
parent 536346ff5e
commit 15111db6c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 86 additions and 135 deletions

View File

@ -18,7 +18,8 @@
*/ */
import React from 'react'; import React from 'react';
import { shallow, mount } from 'enzyme'; import { shallow, mount } from 'enzyme';
import { Nav, MenuItem } from 'react-bootstrap'; import { Nav } from 'react-bootstrap';
import { Menu as DropdownMenu } from 'src/common/components';
import NavDropdown from 'src/components/NavDropdown'; import NavDropdown from 'src/components/NavDropdown';
import { supersetTheme, ThemeProvider } from '@superset-ui/core'; import { supersetTheme, ThemeProvider } from '@superset-ui/core';
@ -165,7 +166,7 @@ describe('Menu', () => {
wrappingComponentProps: { theme: supersetTheme }, wrappingComponentProps: { theme: supersetTheme },
}); });
expect(versionedWrapper.find('.version-info div')).toHaveLength(2); expect(versionedWrapper.find('.version-info span')).toHaveLength(2);
}); });
it('renders a NavDropdown (settings)', () => { it('renders a NavDropdown (settings)', () => {
@ -173,6 +174,6 @@ describe('Menu', () => {
}); });
it('renders MenuItems in NavDropdown (settings)', () => { it('renders MenuItems in NavDropdown (settings)', () => {
expect(wrapper.find(NavDropdown).find(MenuItem)).toHaveLength(6); expect(wrapper.find(NavDropdown).find(DropdownMenu.Item)).toHaveLength(3);
}); });
}); });

View File

@ -44,6 +44,11 @@ export const MenuItem = styled(AntdMenu.Item)`
> a { > a {
text-decoration: none; text-decoration: none;
} }
&.ant-menu-item {
height: ${({ theme }) => theme.gridUnit * 7}px;
line-height: ${({ theme }) => theme.gridUnit * 7}px;
}
`; `;
export const Menu = Object.assign(AntdMenu, { export const Menu = Object.assign(AntdMenu, {

View File

@ -18,8 +18,9 @@
*/ */
import React from 'react'; import React from 'react';
import { t, styled } from '@superset-ui/core'; import { t, styled } from '@superset-ui/core';
import { Nav, Navbar, NavItem, MenuItem } from 'react-bootstrap'; import { Nav, Navbar, NavItem } from 'react-bootstrap';
import NavDropdown from 'src/components/NavDropdown'; import NavDropdown from 'src/components/NavDropdown';
import { Menu as DropdownMenu } from 'src/common/components';
import MenuObject, { import MenuObject, {
MenuObjectProps, MenuObjectProps,
MenuObjectChildProps, MenuObjectChildProps,
@ -71,7 +72,10 @@ const StyledHeader = styled.header`
} }
.version-info { .version-info {
padding: 5px 20px; padding: ${({ theme }) => theme.gridUnit * 1.5}px
${({ theme }) => theme.gridUnit * 4}px
${({ theme }) => theme.gridUnit * 1.5}px
${({ theme }) => theme.gridUnit * 7}px;
color: ${({ theme }) => theme.colors.grayscale.base}; color: ${({ theme }) => theme.colors.grayscale.base};
font-size: ${({ theme }) => theme.typography.sizes.xs}px; font-size: ${({ theme }) => theme.typography.sizes.xs}px;
@ -107,7 +111,6 @@ const StyledHeader = styled.header`
left: 50%; left: 50%;
width: 0; width: 0;
height: 3px; height: 3px;
background-color: ${({ theme }) => theme.colors.primary.base};
opacity: 0; opacity: 0;
transform: translateX(-50%); transform: translateX(-50%);
transition: all ${({ theme }) => theme.transitionTiming}s; transition: all ${({ theme }) => theme.transitionTiming}s;
@ -127,10 +130,6 @@ const StyledHeader = styled.header`
} }
} }
.settings-divider {
margin-bottom: 8px;
border-bottom: 1px solid ${({ theme }) => theme.colors.grayscale.light2};
}
.navbar-right { .navbar-right {
display: flex; display: flex;
align-items: center; align-items: center;
@ -140,34 +139,6 @@ const StyledHeader = styled.header`
export function Menu({ export function Menu({
data: { menu, brand, navbar_right: navbarRight, settings }, data: { menu, brand, navbar_right: navbarRight, settings },
}: MenuProps) { }: MenuProps) {
// Flatten settings
const flatSettings: any[] = [];
if (settings) {
settings.forEach((section: object, index: number) => {
const newSection: MenuObjectProps = {
...section,
index,
isHeader: true,
};
flatSettings.push(newSection);
// Filter out '-'
if (newSection.childs) {
newSection.childs.forEach((child: any) => {
if (child !== '-') {
flatSettings.push(child);
}
});
}
if (index !== settings.length - 1) {
flatSettings.push('-');
}
});
}
return ( return (
<StyledHeader className="top" id="main-menu"> <StyledHeader className="top" id="main-menu">
<Navbar inverse fluid staticTop role="navigation"> <Navbar inverse fluid staticTop role="navigation">
@ -188,76 +159,56 @@ export function Menu({
{!navbarRight.user_is_anonymous && <NewMenu />} {!navbarRight.user_is_anonymous && <NewMenu />}
{settings && settings.length > 0 && ( {settings && settings.length > 0 && (
<NavDropdown id="settings-dropdown" title={t('Settings')}> <NavDropdown id="settings-dropdown" title={t('Settings')}>
{flatSettings.map((section, index) => { <DropdownMenu>
if (section === '-') { {settings.map((section, index) => [
return ( <DropdownMenu.ItemGroup
<MenuItem
key={`$${index}`}
divider
disabled
className="settings-divider"
/>
);
}
if (section.isHeader) {
return (
<MenuItem key={`${section.label}`} header>
{section.label}
</MenuItem>
);
}
return (
<MenuItem
key={`${section.label}`} key={`${section.label}`}
href={section.url} title={section.label}
eventKey={index}
> >
{section.label} {section.childs?.map(child => {
</MenuItem> if (typeof child !== 'string') {
); return (
})} <DropdownMenu.Item key={`${child.label}`}>
<a href={child.url}>{child.label}</a>
</DropdownMenu.Item>
);
}
return null;
})}
</DropdownMenu.ItemGroup>,
index < settings.length - 1 && <DropdownMenu.Divider />,
])}
{!navbarRight.user_is_anonymous && ( {!navbarRight.user_is_anonymous && [
<> <DropdownMenu.Divider key="user-divider" />,
<MenuItem <DropdownMenu.ItemGroup key="user-section" title={t('User')}>
key="user-divider" <DropdownMenu.Item key="profile">
divider <a href={navbarRight.user_info_url}>{t('Profile')}</a>
disabled </DropdownMenu.Item>
className="settings-divider" <DropdownMenu.Item key="logout">
/> <a href={navbarRight.user_logout_url}>{t('Logout')}</a>
<MenuItem key="user-section" header> </DropdownMenu.Item>
{t('User')} </DropdownMenu.ItemGroup>,
</MenuItem> ]}
<MenuItem href={navbarRight.user_info_url}> {(navbarRight.version_string || navbarRight.version_sha) && [
{t('Profile')} <DropdownMenu.Divider key="user-divider" />,
</MenuItem> <DropdownMenu.ItemGroup
<MenuItem href={navbarRight.user_logout_url}> key="about-section"
{t('Logout')} title={t('About')}
</MenuItem> >
</>
)}
{(navbarRight.version_string || navbarRight.version_sha) && (
<>
<MenuItem
key="user-divider"
divider
disabled
className="settings-divider"
/>
<MenuItem key="about-section" header>
{t('About')}
</MenuItem>
<li className="version-info">
{navbarRight.version_string && ( {navbarRight.version_string && (
<div>Version: {navbarRight.version_string}</div> <li className="version-info">
<span>Version: {navbarRight.version_string}</span>
</li>
)} )}
{navbarRight.version_sha && ( {navbarRight.version_sha && (
<div>SHA: {navbarRight.version_sha}</div> <li className="version-info">
<span>SHA: {navbarRight.version_sha}</span>
</li>
)} )}
</li> </DropdownMenu.ItemGroup>,
</> ]}
)} </DropdownMenu>
</NavDropdown> </NavDropdown>
)} )}
{navbarRight.documentation_url && ( {navbarRight.documentation_url && (

View File

@ -17,7 +17,8 @@
* under the License. * under the License.
*/ */
import React from 'react'; import React from 'react';
import { NavItem, MenuItem } from 'react-bootstrap'; import { NavItem } from 'react-bootstrap';
import { Menu } from 'src/common/components';
import NavDropdown from '../NavDropdown'; import NavDropdown from '../NavDropdown';
export interface MenuObjectChildProps { export interface MenuObjectChildProps {
@ -52,24 +53,22 @@ export default function MenuObject({
} }
return ( return (
<NavDropdown id={`menu-dropdown-${label}`} eventKey={index} title={label}> <NavDropdown id={`menu-dropdown-${label}`} title={label}>
{childs?.map((child: MenuObjectChildProps | string, index1: number) => { <Menu>
if (typeof child === 'string' && child === '-') { {childs?.map((child: MenuObjectChildProps | string, index1: number) => {
return <MenuItem key={`$${index1}`} divider />; if (typeof child === 'string' && child === '-') {
} return <Menu.Divider key={`$${index1}`} />;
if (typeof child !== 'string') { }
return ( if (typeof child !== 'string') {
<MenuItem return (
key={`${child.label}`} <Menu.Item key={`${child.label}`}>
href={child.url} <a href={child.url}>&nbsp; {child.label}</a>
eventKey={parseFloat(`${index}.${index1}`)} </Menu.Item>
> );
&nbsp; {child.label} }
</MenuItem> return null;
); })}
} </Menu>
return null;
})}
</NavDropdown> </NavDropdown>
); );
} }

View File

@ -18,7 +18,7 @@
*/ */
import React from 'react'; import React from 'react';
import { t, styled } from '@superset-ui/core'; import { t, styled } from '@superset-ui/core';
import { MenuItem } from 'react-bootstrap'; import { Menu } from 'src/common/components';
import NavDropdown from 'src/components/NavDropdown'; import NavDropdown from 'src/components/NavDropdown';
const dropdownItems = [ const dropdownItems = [
@ -45,11 +45,15 @@ const StyledI = styled.div`
export default function NewMenu() { export default function NewMenu() {
return ( return (
<NavDropdown id="new-dropdown" title={<StyledI className="fa fa-plus" />}> <NavDropdown id="new-dropdown" title={<StyledI className="fa fa-plus" />}>
{dropdownItems.map((menu, i) => ( <Menu>
<MenuItem key={i} href={menu.url}> {dropdownItems.map((menu, i) => (
<i className={`fa ${menu.icon}`} /> {menu.label} <Menu.Item key={i}>
</MenuItem> <a href={menu.url}>
))} <i className={`fa ${menu.icon}`} /> {menu.label}
</a>
</Menu.Item>
))}
</Menu>
</NavDropdown> </NavDropdown>
); );
} }

View File

@ -57,15 +57,6 @@ const NavDropdown = styled(ReactBootstrapNavDropdown)`
padding: ${({ theme }) => theme.gridUnit}px 0; padding: ${({ theme }) => theme.gridUnit}px 0;
top: 100%; top: 100%;
border: none; border: none;
& li a {
padding: ${({ theme }) => theme.gridUnit}px
${({ theme }) => theme.gridUnit * 4}px;
transition: all ${({ theme }) => theme.transitionTiming}s;
&:hover {
background: ${({ theme }) => theme.colors.primary.light4};
color: ${({ theme }) => theme.colors.grayscale.dark1};
}
}
} }
`; `;