Skip to content

Commit

Permalink
Migrates Collapse component from Bootstrap to AntD (#12920)
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-s-molina authored Feb 23, 2021
1 parent e4a0233 commit 9a05d6a
Show file tree
Hide file tree
Showing 23 changed files with 529 additions and 253 deletions.
4 changes: 2 additions & 2 deletions superset-frontend/.storybook/preview.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ import { supersetTheme, ThemeProvider } from '@superset-ui/core';
import '../src/theme.ts';
import './storybook.css';

const themeDecorator = storyFn => (
<ThemeProvider theme={supersetTheme}>{storyFn()}</ThemeProvider>
const themeDecorator = Story => (
<ThemeProvider theme={supersetTheme}>{<Story />}</ThemeProvider>
);

addDecorator(jsxDecorator);
Expand Down
78 changes: 61 additions & 17 deletions superset-frontend/spec/javascripts/sqllab/TableElement_spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ import { mount, shallow } from 'enzyme';
import { Provider } from 'react-redux';
import configureStore from 'redux-mock-store';
import { supersetTheme, ThemeProvider } from '@superset-ui/core';
import Collapse from 'src/common/components/Collapse';

import { IconTooltip } from 'src/components/IconTooltip';
import Fade from 'src/common/components/Fade';
import TableElement from 'src/SqlLab/components/TableElement';
import ColumnElement from 'src/SqlLab/components/ColumnElement';

import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint';
import { mockedActions, table } from './fixtures';

describe('TableElement', () => {
Expand All @@ -43,9 +44,19 @@ describe('TableElement', () => {
it('renders with props', () => {
expect(React.isValidElement(<TableElement {...mockedProps} />)).toBe(true);
});
it('has 2 IconTooltip elements', () => {
const wrapper = shallow(<TableElement {...mockedProps} />);
expect(wrapper.find(IconTooltip)).toHaveLength(2);
it('has 4 IconTooltip elements', () => {
const wrapper = mount(
<Provider store={store}>
<TableElement {...mockedProps} />
</Provider>,
{
wrappingComponent: ThemeProvider,
wrappingComponentProps: {
theme: supersetTheme,
},
},
);
expect(wrapper.find(IconTooltip)).toHaveLength(4);
});
it('has 14 columns', () => {
const wrapper = shallow(<TableElement {...mockedProps} />);
Expand All @@ -64,20 +75,45 @@ describe('TableElement', () => {
},
);
});
it('fades table', () => {
const wrapper = shallow(<TableElement {...mockedProps} />);
expect(wrapper.state().hovered).toBe(false);
it('fades table', async () => {
const wrapper = mount(
<Provider store={store}>
<TableElement {...mockedProps} />
</Provider>,
{
wrappingComponent: ThemeProvider,
wrappingComponentProps: {
theme: supersetTheme,
},
},
);
expect(wrapper.find(TableElement).state().hovered).toBe(false);
expect(wrapper.find(Fade).props().hovered).toBe(false);
wrapper.find('div.TableElement').simulate('mouseEnter');
expect(wrapper.state().hovered).toBe(true);
wrapper.find('.header-container').hostNodes().simulate('mouseEnter');
await waitForComponentToPaint(wrapper, 300);
expect(wrapper.find(TableElement).state().hovered).toBe(true);
expect(wrapper.find(Fade).props().hovered).toBe(true);
});
it('sorts columns', () => {
const wrapper = shallow(<TableElement {...mockedProps} />);
expect(wrapper.state().sortColumns).toBe(false);
const wrapper = mount(
<Provider store={store}>
<Collapse>
<TableElement {...mockedProps} />
</Collapse>
</Provider>,
{
wrappingComponent: ThemeProvider,
wrappingComponentProps: {
theme: supersetTheme,
},
},
);
expect(wrapper.find(TableElement).state().sortColumns).toBe(false);
wrapper.find('.header-container').hostNodes().simulate('click');
expect(wrapper.find(ColumnElement).first().props().column.name).toBe('id');
wrapper.find('.sort-cols').simulate('click');
expect(wrapper.state().sortColumns).toBe(true);
wrapper.find('.header-container').simulate('mouseEnter');
wrapper.find('.sort-cols').hostNodes().simulate('click');
expect(wrapper.find(TableElement).state().sortColumns).toBe(true);
expect(wrapper.find(ColumnElement).first().props().column.name).toBe(
'active',
);
Expand All @@ -99,10 +135,18 @@ describe('TableElement', () => {
expect(mockedActions.collapseTable.called).toBe(true);
});
it('removes the table', () => {
const wrapper = shallow(<TableElement {...mockedProps} />);
expect(wrapper.state().expanded).toBe(true);
wrapper.find('.table-remove').simulate('click');
expect(wrapper.state().expanded).toBe(false);
const wrapper = mount(
<Provider store={store}>
<TableElement {...mockedProps} />
</Provider>,
{
wrappingComponent: ThemeProvider,
wrappingComponentProps: {
theme: supersetTheme,
},
},
);
wrapper.find('.table-remove').hostNodes().simulate('click');
expect(mockedActions.removeDataPreview.called).toBe(true);
});
});
42 changes: 34 additions & 8 deletions superset-frontend/src/SqlLab/components/SqlEditorLeftBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
import React from 'react';
import PropTypes from 'prop-types';
import Button from 'src/components/Button';
import { t, styled } from '@superset-ui/core';
import { t, styled, css } from '@superset-ui/core';
import Collapse from 'src/common/components/Collapse';
import TableElement from './TableElement';
import TableSelector from '../../components/TableSelector';

Expand Down Expand Up @@ -145,13 +146,38 @@ export default class SqlEditorLeftBar extends React.PureComponent {
<div className="divider" />
<StyledScrollbarContainer>
<StyledScrollbarContent contentHeight={tableMetaDataHeight}>
{this.props.tables.map(table => (
<TableElement
table={table}
key={table.id}
actions={this.props.actions}
/>
))}
<Collapse
ghost
expandIconPosition="right"
css={theme => css`
.ant-collapse-item {
margin-bottom: ${theme.gridUnit * 3}px;
}
.ant-collapse-header {
padding: 0px !important;
display: flex;
align-items: center;
}
.ant-collapse-content-box {
padding: 0px ${theme.gridUnit * 4}px 0px 0px !important;
}
.ant-collapse-arrow {
top: ${theme.gridUnit * 2}px !important;
color: ${theme.colors.primary.dark1} !important;
&: hover {
color: ${theme.colors.primary.dark2} !important;
}
}
`}
>
{this.props.tables.map(table => (
<TableElement
table={table}
key={table.id}
actions={this.props.actions}
/>
))}
</Collapse>
</StyledScrollbarContent>
</StyledScrollbarContainer>
{shouldShowReset && (
Expand Down
79 changes: 33 additions & 46 deletions superset-frontend/src/SqlLab/components/TableElement.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import { Collapse, Well } from 'react-bootstrap';
import { Well } from 'react-bootstrap';
import Collapse from 'src/common/components/Collapse';
import ButtonGroup from 'src/components/ButtonGroup';
import shortid from 'shortid';
import { t, styled } from '@superset-ui/core';
import { debounce } from 'lodash';

import Fade from 'src/common/components/Fade';
import { Tooltip } from 'src/common/components/Tooltip';
Expand All @@ -35,13 +37,11 @@ import Loading from '../../components/Loading';
const propTypes = {
table: PropTypes.object,
actions: PropTypes.object,
timeout: PropTypes.number, // used for tests
};

const defaultProps = {
actions: {},
table: null,
timeout: 500,
};

const StyledSpan = styled.span`
Expand All @@ -57,13 +57,11 @@ class TableElement extends React.PureComponent {
super(props);
this.state = {
sortColumns: false,
expanded: true,
hovered: false,
};
this.removeFromStore = this.removeFromStore.bind(this);
this.toggleSortColumns = this.toggleSortColumns.bind(this);
this.removeTable = this.removeTable.bind(this);
this.setHover = this.setHover.bind(this);
this.setHover = debounce(this.setHover.bind(this), 100);
}

setHover(hovered) {
Expand Down Expand Up @@ -91,18 +89,14 @@ class TableElement extends React.PureComponent {
}

removeTable() {
this.setState({ expanded: false });
this.props.actions.removeDataPreview(this.props.table);
this.props.actions.removeTable(this.props.table);
}

toggleSortColumns() {
this.setState(prevState => ({ sortColumns: !prevState.sortColumns }));
}

removeFromStore() {
this.props.actions.removeTable(this.props.table);
}

renderWell() {
const { table } = this.props;
let header;
Expand Down Expand Up @@ -208,7 +202,11 @@ class TableElement extends React.PureComponent {
renderHeader() {
const { table } = this.props;
return (
<div className="clearfix header-container">
<div
className="clearfix header-container"
onMouseEnter={() => this.setHover(true)}
onMouseLeave={() => this.setHover(false)}
>
<Tooltip
id="copy-to-clipboard-tooltip"
placement="top"
Expand All @@ -231,21 +229,13 @@ class TableElement extends React.PureComponent {
{table.isMetadataLoading || table.isExtraMetadataLoading ? (
<Loading position="inline" />
) : (
<Fade hovered={this.state.hovered}>{this.renderControls()}</Fade>
<Fade
hovered={this.state.hovered}
onClick={e => e.stopPropagation()}
>
{this.renderControls()}
</Fade>
)}
<i
role="button"
aria-label="Toggle table"
tabIndex={0}
onClick={e => {
this.toggleTable(e);
}}
className={
'text-primary pointer m-l-10 ' +
'fa fa-lg ' +
`fa-angle-${table.expanded ? 'up' : 'down'}`
}
/>
</div>
</div>
);
Expand All @@ -270,39 +260,36 @@ class TableElement extends React.PureComponent {
});
}
}

const metadata = (
<Collapse in={table.expanded} timeout={this.props.timeout}>
<div
onMouseEnter={() => this.setHover(true)}
onMouseLeave={() => this.setHover(false)}
css={{ paddingTop: 6 }}
>
{this.renderWell()}
<div>
{this.renderWell()}
<div className="table-columns m-t-5">
{cols &&
cols.map(col => <ColumnElement column={col} key={col.name} />)}
</div>
{cols &&
cols.map(col => <ColumnElement column={col} key={col.name} />)}
</div>
</Collapse>
</div>
);
return metadata;
}

render() {
return (
<Collapse
in={this.state.expanded}
timeout={this.props.timeout}
onExited={this.removeFromStore}
<Collapse.Panel
{...this.props}
header={this.renderHeader()}
className="TableElement"
>
<div
className="TableElement table-schema m-b-10"
onMouseEnter={() => this.setHover(true)}
onMouseLeave={() => this.setHover(false)}
>
{this.renderHeader()}
<div>{this.renderBody()}</div>
</div>
</Collapse>
{this.renderBody()}
</Collapse.Panel>
);
}
}

TableElement.propTypes = propTypes;
TableElement.defaultProps = defaultProps;

Expand Down
6 changes: 4 additions & 2 deletions superset-frontend/src/SqlLab/main.less
Original file line number Diff line number Diff line change
Expand Up @@ -413,8 +413,6 @@ div.tablePopover {
}

.TableElement {
margin-right: 10px;

.well {
margin-top: 5px;
margin-bottom: 5px;
Expand All @@ -428,18 +426,22 @@ div.tablePopover {

.header-container {
display: flex;
flex: 1;
align-items: center;

.table-name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: 16px;
flex: 1;
}

.header-right-side {
margin-left: auto;
display: flex;
align-items: center;
margin-right: 33px;
}
}
}
Expand Down
23 changes: 23 additions & 0 deletions superset-frontend/src/common/components/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
{
"rules": {
"no-restricted-imports": 0
}
}
Loading

0 comments on commit 9a05d6a

Please sign in to comment.