refactor: Replace react-bootstrap MenuItems with Antd Menu (#11555)

* Remove MenuItem from SubMenu

* Fix tests

* Refactor PopoverDropdown

* Refactor Button

* Remove redundant Menu import
This commit is contained in:
Kamil Gabryjelski 2020-11-04 23:32:38 +01:00 committed by GitHub
parent ef7087adb6
commit 3e35ddd609
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 78 additions and 38 deletions

View File

@ -19,7 +19,7 @@
import React from 'react'; import React from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { shallow } from 'enzyme'; import { shallow } from 'enzyme';
import { Navbar, MenuItem } from 'react-bootstrap'; import { Navbar } from 'react-bootstrap';
import SubMenu from 'src/components/Menu/SubMenu'; import SubMenu from 'src/components/Menu/SubMenu';
const defaultProps = { const defaultProps = {
@ -66,7 +66,7 @@ describe('SubMenu', () => {
}); });
it('renders 3 MenuItems (when usesRouter === false)', () => { it('renders 3 MenuItems (when usesRouter === false)', () => {
expect(wrapper.find(MenuItem)).toHaveLength(3); expect(wrapper.find('li')).toHaveLength(3);
}); });
it('renders the menu title', () => { it('renders the menu title', () => {
@ -83,7 +83,7 @@ describe('SubMenu', () => {
expect(routerWrapper.find(Link)).toExist(); expect(routerWrapper.find(Link)).toExist();
expect(routerWrapper.find(Link)).toHaveLength(2); expect(routerWrapper.find(Link)).toHaveLength(2);
expect(routerWrapper.find(MenuItem)).toHaveLength(1); expect(routerWrapper.find('li.no-router')).toHaveLength(1);
}); });
it('renders buttons in the right nav of the submenu', () => { it('renders buttons in the right nav of the submenu', () => {

View File

@ -18,7 +18,7 @@
*/ */
import React from 'react'; import React from 'react';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import { mount } from 'enzyme'; import { styledMount as mount } from 'spec/helpers/theming';
import sinon from 'sinon'; import sinon from 'sinon';
import DeleteComponentButton from 'src/dashboard/components/DeleteComponentButton'; import DeleteComponentButton from 'src/dashboard/components/DeleteComponentButton';

View File

@ -18,7 +18,7 @@
*/ */
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import React from 'react'; import React from 'react';
import { mount } from 'enzyme'; import { styledMount as mount } from 'spec/helpers/theming';
import sinon from 'sinon'; import sinon from 'sinon';
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from 'react-markdown';

View File

@ -69,10 +69,10 @@ describe('DashboardTable', () => {
it('render a submenu with clickable tabs and buttons', async () => { it('render a submenu with clickable tabs and buttons', async () => {
expect(wrapper.find(SubMenu)).toExist(); expect(wrapper.find(SubMenu)).toExist();
expect(wrapper.find('MenuItem')).toHaveLength(2); expect(wrapper.find('li')).toHaveLength(2);
expect(wrapper.find('Button')).toHaveLength(4); expect(wrapper.find('Button')).toHaveLength(4);
act(() => { act(() => {
wrapper.find('MenuItem').at(1).simulate('click'); wrapper.find('li').at(1).simulate('click');
}); });
await waitForComponentToPaint(wrapper); await waitForComponentToPaint(wrapper);
expect(fetchMock.calls(/dashboard\/\?q/)).toHaveLength(1); expect(fetchMock.calls(/dashboard\/\?q/)).toHaveLength(1);

View File

@ -89,10 +89,10 @@ describe('SavedQueries', () => {
it('it renders a submenu with clickable tables and buttons', async () => { it('it renders a submenu with clickable tables and buttons', async () => {
expect(wrapper.find(SubMenu)).toExist(); expect(wrapper.find(SubMenu)).toExist();
expect(wrapper.find('MenuItem')).toHaveLength(2); expect(wrapper.find('li')).toHaveLength(2);
expect(wrapper.find('button')).toHaveLength(2); expect(wrapper.find('button')).toHaveLength(2);
act(() => { act(() => {
wrapper.find('MenuItem').at(1).simulate('click'); wrapper.find('li').at(1).simulate('click');
}); });
await waitForComponentToPaint(wrapper); await waitForComponentToPaint(wrapper);

View File

@ -24,9 +24,9 @@ import {
Button as BootstrapButton, Button as BootstrapButton,
Tooltip, Tooltip,
OverlayTrigger, OverlayTrigger,
MenuItem,
} from 'react-bootstrap'; } from 'react-bootstrap';
import { styled } from '@superset-ui/core'; import { styled } from '@superset-ui/core';
import { Menu } from 'src/common/components';
export type OnClickHandler = React.MouseEventHandler<BootstrapButton>; export type OnClickHandler = React.MouseEventHandler<BootstrapButton>;
@ -285,12 +285,16 @@ export default function Button({
{children} {children}
</SupersetButton> </SupersetButton>
<ul className="dropdown-menu"> <ul className="dropdown-menu">
{dropdownItems.map((dropdownItem: DropdownItemProps) => ( <Menu>
<MenuItem key={`${dropdownItem.label}`} href={dropdownItem.url}> {dropdownItems.map((dropdownItem: DropdownItemProps) => (
<i className={`fa ${dropdownItem.icon}`} /> <Menu.Item key={`${dropdownItem.label}`}>
&nbsp; {dropdownItem.label} <a href={dropdownItem.url}>
</MenuItem> <i className={`fa ${dropdownItem.icon}`} />
))} &nbsp; {dropdownItem.label}
</a>
</Menu.Item>
))}
</Menu>
</ul> </ul>
</div> </div>
); );

View File

@ -19,7 +19,8 @@
import React, { ReactNode } from 'react'; import React, { ReactNode } from 'react';
import { Link, useHistory } from 'react-router-dom'; import { Link, useHistory } from 'react-router-dom';
import { styled } from '@superset-ui/core'; import { styled } from '@superset-ui/core';
import { Nav, Navbar, MenuItem } from 'react-bootstrap'; import cx from 'classnames';
import { Nav, Navbar } from 'react-bootstrap';
import Button, { OnClickHandler } from 'src/components/Button'; import Button, { OnClickHandler } from 'src/components/Button';
const StyledHeader = styled.header` const StyledHeader = styled.header`
@ -139,15 +140,16 @@ const SubMenu: React.FunctionComponent<SubMenuProps> = props => {
} }
return ( return (
<MenuItem <li
className="no-router" className={cx('no-router', {
active={tab.name === props.activeChild} active: tab.name === props.activeChild,
})}
key={`${tab.label}`} key={`${tab.label}`}
href={tab.url}
onClick={tab.onClick}
> >
{tab.label} <a href={tab.url} onClick={tab.onClick}>
</MenuItem> {tab.label}
</a>
</li>
); );
})} })}
</Nav> </Nav>

View File

@ -18,7 +18,10 @@
*/ */
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { DropdownButton, MenuItem } from 'react-bootstrap'; import cx from 'classnames';
import { styled } from '@superset-ui/core';
import { DropdownButton } from 'react-bootstrap';
import { Menu } from 'src/common/components';
const propTypes = { const propTypes = {
id: PropTypes.string.isRequired, id: PropTypes.string.isRequired,
@ -42,14 +45,44 @@ const defaultProps = {
), ),
}; };
const MenuItem = styled(Menu.Item)`
&.ant-menu-item {
height: auto;
line-height: 1.4;
padding-top: ${({ theme }) => theme.gridUnit}px;
padding-bottom: ${({ theme }) => theme.gridUnit}px;
margin-top: 0;
margin-bottom: 0;
&:not(:last-child) {
margin-bottom: 0;
}
&:hover {
background: ${({ theme }) => theme.colors.grayscale.light3};
}
&.active {
font-weight: ${({ theme }) => theme.typography.weights.bold};
background: ${({ theme }) => theme.colors.grayscale.light2};
}
}
&.ant-menu-item-selected {
color: unset;
}
`;
class PopoverDropdown extends React.PureComponent { class PopoverDropdown extends React.PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.handleSelect = this.handleSelect.bind(this); this.handleSelect = this.handleSelect.bind(this);
} }
handleSelect(nextValue) { handleSelect({ key }) {
this.props.onChange(nextValue); this.props.onChange(key);
} }
render() { render() {
@ -62,17 +95,18 @@ class PopoverDropdown extends React.PureComponent {
title={renderButton(selected)} title={renderButton(selected)}
className="popover-dropdown" className="popover-dropdown"
> >
{options.map(option => ( <Menu onClick={this.handleSelect}>
<MenuItem {options.map(option => (
key={option.value} <MenuItem
eventKey={option.value} key={option.value}
active={option.value === value} className={cx('dropdown-item', {
onSelect={this.handleSelect} active: option.value === value,
className="dropdown-item" })}
> >
{renderOption(option)} {renderOption(option)}
</MenuItem> </MenuItem>
))} ))}
</Menu>
</DropdownButton> </DropdownButton>
); );
} }