mirror of https://github.com/apache/superset.git
Migrates Collapse component from Bootstrap to AntD (#12920)
This commit is contained in:
parent
e4a0233181
commit
9a05d6afe5
|
@ -27,8 +27,8 @@ import { supersetTheme, ThemeProvider } from '@superset-ui/core';
|
||||||
import '../src/theme.ts';
|
import '../src/theme.ts';
|
||||||
import './storybook.css';
|
import './storybook.css';
|
||||||
|
|
||||||
const themeDecorator = storyFn => (
|
const themeDecorator = Story => (
|
||||||
<ThemeProvider theme={supersetTheme}>{storyFn()}</ThemeProvider>
|
<ThemeProvider theme={supersetTheme}>{<Story />}</ThemeProvider>
|
||||||
);
|
);
|
||||||
|
|
||||||
addDecorator(jsxDecorator);
|
addDecorator(jsxDecorator);
|
||||||
|
|
|
@ -21,12 +21,13 @@ import { mount, shallow } from 'enzyme';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import configureStore from 'redux-mock-store';
|
import configureStore from 'redux-mock-store';
|
||||||
import { supersetTheme, ThemeProvider } from '@superset-ui/core';
|
import { supersetTheme, ThemeProvider } from '@superset-ui/core';
|
||||||
|
import Collapse from 'src/common/components/Collapse';
|
||||||
|
|
||||||
import { IconTooltip } from 'src/components/IconTooltip';
|
import { IconTooltip } from 'src/components/IconTooltip';
|
||||||
import Fade from 'src/common/components/Fade';
|
import Fade from 'src/common/components/Fade';
|
||||||
import TableElement from 'src/SqlLab/components/TableElement';
|
import TableElement from 'src/SqlLab/components/TableElement';
|
||||||
import ColumnElement from 'src/SqlLab/components/ColumnElement';
|
import ColumnElement from 'src/SqlLab/components/ColumnElement';
|
||||||
|
import waitForComponentToPaint from 'spec/helpers/waitForComponentToPaint';
|
||||||
import { mockedActions, table } from './fixtures';
|
import { mockedActions, table } from './fixtures';
|
||||||
|
|
||||||
describe('TableElement', () => {
|
describe('TableElement', () => {
|
||||||
|
@ -43,9 +44,19 @@ describe('TableElement', () => {
|
||||||
it('renders with props', () => {
|
it('renders with props', () => {
|
||||||
expect(React.isValidElement(<TableElement {...mockedProps} />)).toBe(true);
|
expect(React.isValidElement(<TableElement {...mockedProps} />)).toBe(true);
|
||||||
});
|
});
|
||||||
it('has 2 IconTooltip elements', () => {
|
it('has 4 IconTooltip elements', () => {
|
||||||
const wrapper = shallow(<TableElement {...mockedProps} />);
|
const wrapper = mount(
|
||||||
expect(wrapper.find(IconTooltip)).toHaveLength(2);
|
<Provider store={store}>
|
||||||
|
<TableElement {...mockedProps} />
|
||||||
|
</Provider>,
|
||||||
|
{
|
||||||
|
wrappingComponent: ThemeProvider,
|
||||||
|
wrappingComponentProps: {
|
||||||
|
theme: supersetTheme,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
expect(wrapper.find(IconTooltip)).toHaveLength(4);
|
||||||
});
|
});
|
||||||
it('has 14 columns', () => {
|
it('has 14 columns', () => {
|
||||||
const wrapper = shallow(<TableElement {...mockedProps} />);
|
const wrapper = shallow(<TableElement {...mockedProps} />);
|
||||||
|
@ -64,20 +75,45 @@ describe('TableElement', () => {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
it('fades table', () => {
|
it('fades table', async () => {
|
||||||
const wrapper = shallow(<TableElement {...mockedProps} />);
|
const wrapper = mount(
|
||||||
expect(wrapper.state().hovered).toBe(false);
|
<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);
|
expect(wrapper.find(Fade).props().hovered).toBe(false);
|
||||||
wrapper.find('div.TableElement').simulate('mouseEnter');
|
wrapper.find('.header-container').hostNodes().simulate('mouseEnter');
|
||||||
expect(wrapper.state().hovered).toBe(true);
|
await waitForComponentToPaint(wrapper, 300);
|
||||||
|
expect(wrapper.find(TableElement).state().hovered).toBe(true);
|
||||||
expect(wrapper.find(Fade).props().hovered).toBe(true);
|
expect(wrapper.find(Fade).props().hovered).toBe(true);
|
||||||
});
|
});
|
||||||
it('sorts columns', () => {
|
it('sorts columns', () => {
|
||||||
const wrapper = shallow(<TableElement {...mockedProps} />);
|
const wrapper = mount(
|
||||||
expect(wrapper.state().sortColumns).toBe(false);
|
<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');
|
expect(wrapper.find(ColumnElement).first().props().column.name).toBe('id');
|
||||||
wrapper.find('.sort-cols').simulate('click');
|
wrapper.find('.header-container').simulate('mouseEnter');
|
||||||
expect(wrapper.state().sortColumns).toBe(true);
|
wrapper.find('.sort-cols').hostNodes().simulate('click');
|
||||||
|
expect(wrapper.find(TableElement).state().sortColumns).toBe(true);
|
||||||
expect(wrapper.find(ColumnElement).first().props().column.name).toBe(
|
expect(wrapper.find(ColumnElement).first().props().column.name).toBe(
|
||||||
'active',
|
'active',
|
||||||
);
|
);
|
||||||
|
@ -99,10 +135,18 @@ describe('TableElement', () => {
|
||||||
expect(mockedActions.collapseTable.called).toBe(true);
|
expect(mockedActions.collapseTable.called).toBe(true);
|
||||||
});
|
});
|
||||||
it('removes the table', () => {
|
it('removes the table', () => {
|
||||||
const wrapper = shallow(<TableElement {...mockedProps} />);
|
const wrapper = mount(
|
||||||
expect(wrapper.state().expanded).toBe(true);
|
<Provider store={store}>
|
||||||
wrapper.find('.table-remove').simulate('click');
|
<TableElement {...mockedProps} />
|
||||||
expect(wrapper.state().expanded).toBe(false);
|
</Provider>,
|
||||||
|
{
|
||||||
|
wrappingComponent: ThemeProvider,
|
||||||
|
wrappingComponentProps: {
|
||||||
|
theme: supersetTheme,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
wrapper.find('.table-remove').hostNodes().simulate('click');
|
||||||
expect(mockedActions.removeDataPreview.called).toBe(true);
|
expect(mockedActions.removeDataPreview.called).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,7 +19,8 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import Button from 'src/components/Button';
|
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 TableElement from './TableElement';
|
||||||
import TableSelector from '../../components/TableSelector';
|
import TableSelector from '../../components/TableSelector';
|
||||||
|
|
||||||
|
@ -145,6 +146,30 @@ export default class SqlEditorLeftBar extends React.PureComponent {
|
||||||
<div className="divider" />
|
<div className="divider" />
|
||||||
<StyledScrollbarContainer>
|
<StyledScrollbarContainer>
|
||||||
<StyledScrollbarContent contentHeight={tableMetaDataHeight}>
|
<StyledScrollbarContent contentHeight={tableMetaDataHeight}>
|
||||||
|
<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 => (
|
{this.props.tables.map(table => (
|
||||||
<TableElement
|
<TableElement
|
||||||
table={table}
|
table={table}
|
||||||
|
@ -152,6 +177,7 @@ export default class SqlEditorLeftBar extends React.PureComponent {
|
||||||
actions={this.props.actions}
|
actions={this.props.actions}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
</Collapse>
|
||||||
</StyledScrollbarContent>
|
</StyledScrollbarContent>
|
||||||
</StyledScrollbarContainer>
|
</StyledScrollbarContainer>
|
||||||
{shouldShowReset && (
|
{shouldShowReset && (
|
||||||
|
|
|
@ -18,10 +18,12 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
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 ButtonGroup from 'src/components/ButtonGroup';
|
||||||
import shortid from 'shortid';
|
import shortid from 'shortid';
|
||||||
import { t, styled } from '@superset-ui/core';
|
import { t, styled } from '@superset-ui/core';
|
||||||
|
import { debounce } from 'lodash';
|
||||||
|
|
||||||
import Fade from 'src/common/components/Fade';
|
import Fade from 'src/common/components/Fade';
|
||||||
import { Tooltip } from 'src/common/components/Tooltip';
|
import { Tooltip } from 'src/common/components/Tooltip';
|
||||||
|
@ -35,13 +37,11 @@ import Loading from '../../components/Loading';
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
table: PropTypes.object,
|
table: PropTypes.object,
|
||||||
actions: PropTypes.object,
|
actions: PropTypes.object,
|
||||||
timeout: PropTypes.number, // used for tests
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultProps = {
|
const defaultProps = {
|
||||||
actions: {},
|
actions: {},
|
||||||
table: null,
|
table: null,
|
||||||
timeout: 500,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledSpan = styled.span`
|
const StyledSpan = styled.span`
|
||||||
|
@ -57,13 +57,11 @@ class TableElement extends React.PureComponent {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
sortColumns: false,
|
sortColumns: false,
|
||||||
expanded: true,
|
|
||||||
hovered: false,
|
hovered: false,
|
||||||
};
|
};
|
||||||
this.removeFromStore = this.removeFromStore.bind(this);
|
|
||||||
this.toggleSortColumns = this.toggleSortColumns.bind(this);
|
this.toggleSortColumns = this.toggleSortColumns.bind(this);
|
||||||
this.removeTable = this.removeTable.bind(this);
|
this.removeTable = this.removeTable.bind(this);
|
||||||
this.setHover = this.setHover.bind(this);
|
this.setHover = debounce(this.setHover.bind(this), 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
setHover(hovered) {
|
setHover(hovered) {
|
||||||
|
@ -91,18 +89,14 @@ class TableElement extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
removeTable() {
|
removeTable() {
|
||||||
this.setState({ expanded: false });
|
|
||||||
this.props.actions.removeDataPreview(this.props.table);
|
this.props.actions.removeDataPreview(this.props.table);
|
||||||
|
this.props.actions.removeTable(this.props.table);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleSortColumns() {
|
toggleSortColumns() {
|
||||||
this.setState(prevState => ({ sortColumns: !prevState.sortColumns }));
|
this.setState(prevState => ({ sortColumns: !prevState.sortColumns }));
|
||||||
}
|
}
|
||||||
|
|
||||||
removeFromStore() {
|
|
||||||
this.props.actions.removeTable(this.props.table);
|
|
||||||
}
|
|
||||||
|
|
||||||
renderWell() {
|
renderWell() {
|
||||||
const { table } = this.props;
|
const { table } = this.props;
|
||||||
let header;
|
let header;
|
||||||
|
@ -208,7 +202,11 @@ class TableElement extends React.PureComponent {
|
||||||
renderHeader() {
|
renderHeader() {
|
||||||
const { table } = this.props;
|
const { table } = this.props;
|
||||||
return (
|
return (
|
||||||
<div className="clearfix header-container">
|
<div
|
||||||
|
className="clearfix header-container"
|
||||||
|
onMouseEnter={() => this.setHover(true)}
|
||||||
|
onMouseLeave={() => this.setHover(false)}
|
||||||
|
>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
id="copy-to-clipboard-tooltip"
|
id="copy-to-clipboard-tooltip"
|
||||||
placement="top"
|
placement="top"
|
||||||
|
@ -231,21 +229,13 @@ class TableElement extends React.PureComponent {
|
||||||
{table.isMetadataLoading || table.isExtraMetadataLoading ? (
|
{table.isMetadataLoading || table.isExtraMetadataLoading ? (
|
||||||
<Loading position="inline" />
|
<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>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -270,39 +260,36 @@ class TableElement extends React.PureComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const metadata = (
|
const metadata = (
|
||||||
<Collapse in={table.expanded} timeout={this.props.timeout}>
|
<div
|
||||||
<div>
|
onMouseEnter={() => this.setHover(true)}
|
||||||
|
onMouseLeave={() => this.setHover(false)}
|
||||||
|
css={{ paddingTop: 6 }}
|
||||||
|
>
|
||||||
{this.renderWell()}
|
{this.renderWell()}
|
||||||
<div className="table-columns m-t-5">
|
<div>
|
||||||
{cols &&
|
{cols &&
|
||||||
cols.map(col => <ColumnElement column={col} key={col.name} />)}
|
cols.map(col => <ColumnElement column={col} key={col.name} />)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Collapse>
|
|
||||||
);
|
);
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Collapse
|
<Collapse.Panel
|
||||||
in={this.state.expanded}
|
{...this.props}
|
||||||
timeout={this.props.timeout}
|
header={this.renderHeader()}
|
||||||
onExited={this.removeFromStore}
|
className="TableElement"
|
||||||
>
|
>
|
||||||
<div
|
{this.renderBody()}
|
||||||
className="TableElement table-schema m-b-10"
|
</Collapse.Panel>
|
||||||
onMouseEnter={() => this.setHover(true)}
|
|
||||||
onMouseLeave={() => this.setHover(false)}
|
|
||||||
>
|
|
||||||
{this.renderHeader()}
|
|
||||||
<div>{this.renderBody()}</div>
|
|
||||||
</div>
|
|
||||||
</Collapse>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TableElement.propTypes = propTypes;
|
TableElement.propTypes = propTypes;
|
||||||
TableElement.defaultProps = defaultProps;
|
TableElement.defaultProps = defaultProps;
|
||||||
|
|
||||||
|
|
|
@ -413,8 +413,6 @@ div.tablePopover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.TableElement {
|
.TableElement {
|
||||||
margin-right: 10px;
|
|
||||||
|
|
||||||
.well {
|
.well {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
|
@ -428,18 +426,22 @@ div.tablePopover {
|
||||||
|
|
||||||
.header-container {
|
.header-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex: 1;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
.table-name {
|
.table-name {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.header-right-side {
|
.header-right-side {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
margin-right: 33px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
import React from 'react';
|
||||||
|
import { useTheme } from '@superset-ui/core';
|
||||||
|
import Collapse, { CollapseProps } from '.';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Collapse',
|
||||||
|
component: Collapse,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const InteractiveCollapse = (args: CollapseProps) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
return (
|
||||||
|
<Collapse
|
||||||
|
defaultActiveKey={['1']}
|
||||||
|
style={
|
||||||
|
args.light ? { background: theme.colors.grayscale.light2 } : undefined
|
||||||
|
}
|
||||||
|
{...args}
|
||||||
|
>
|
||||||
|
<Collapse.Panel header="Header 1" key="1">
|
||||||
|
Content 1
|
||||||
|
</Collapse.Panel>
|
||||||
|
<Collapse.Panel header="Header 2" key="2">
|
||||||
|
Content 2
|
||||||
|
</Collapse.Panel>
|
||||||
|
</Collapse>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
InteractiveCollapse.args = {
|
||||||
|
ghost: false,
|
||||||
|
bordered: true,
|
||||||
|
accordion: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
InteractiveCollapse.argTypes = {
|
||||||
|
theme: {
|
||||||
|
table: {
|
||||||
|
disable: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
InteractiveCollapse.story = {
|
||||||
|
parameters: {
|
||||||
|
actions: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
knobs: {
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,110 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
import React from 'react';
|
||||||
|
import { render, screen } from 'spec/helpers/testing-library';
|
||||||
|
import userEvent from '@testing-library/user-event';
|
||||||
|
import { supersetTheme } from '@superset-ui/core';
|
||||||
|
import { hexToRgb } from 'src/utils/colorUtils';
|
||||||
|
import Collapse, { CollapseProps } from '.';
|
||||||
|
|
||||||
|
function renderCollapse(props?: CollapseProps) {
|
||||||
|
return render(
|
||||||
|
<Collapse {...props}>
|
||||||
|
<Collapse.Panel header="Header 1" key="1">
|
||||||
|
Content 1
|
||||||
|
</Collapse.Panel>
|
||||||
|
<Collapse.Panel header="Header 2" key="2">
|
||||||
|
Content 2
|
||||||
|
</Collapse.Panel>
|
||||||
|
</Collapse>,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
test('renders collapsed with default props', () => {
|
||||||
|
renderCollapse();
|
||||||
|
|
||||||
|
const headers = screen.getAllByRole('button');
|
||||||
|
|
||||||
|
expect(headers[0]).toHaveTextContent('Header 1');
|
||||||
|
expect(headers[1]).toHaveTextContent('Header 2');
|
||||||
|
expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('renders with one item expanded by default', () => {
|
||||||
|
renderCollapse({ defaultActiveKey: ['1'] });
|
||||||
|
|
||||||
|
const headers = screen.getAllByRole('button');
|
||||||
|
|
||||||
|
expect(headers[0]).toHaveTextContent('Header 1');
|
||||||
|
expect(headers[1]).toHaveTextContent('Header 2');
|
||||||
|
expect(screen.getByText('Content 1')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('expands on click', () => {
|
||||||
|
renderCollapse();
|
||||||
|
|
||||||
|
expect(screen.queryByText('Content 1')).not.toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
userEvent.click(screen.getAllByRole('button')[0]);
|
||||||
|
|
||||||
|
expect(screen.getByText('Content 1')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('collapses on click', () => {
|
||||||
|
renderCollapse({ defaultActiveKey: ['1'] });
|
||||||
|
|
||||||
|
expect(screen.getByText('Content 1')).toBeInTheDocument();
|
||||||
|
expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
|
||||||
|
|
||||||
|
userEvent.click(screen.getAllByRole('button')[0]);
|
||||||
|
|
||||||
|
expect(screen.getByText('Content 1').parentNode).toHaveClass(
|
||||||
|
'ant-collapse-content-hidden',
|
||||||
|
);
|
||||||
|
expect(screen.queryByText('Content 2')).not.toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('renders with custom properties', () => {
|
||||||
|
renderCollapse({
|
||||||
|
light: true,
|
||||||
|
bigger: true,
|
||||||
|
bold: true,
|
||||||
|
animateArrows: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const header = document.getElementsByClassName('ant-collapse-header')[0];
|
||||||
|
const arrow = document.getElementsByClassName('ant-collapse-arrow')[0]
|
||||||
|
.children[0];
|
||||||
|
|
||||||
|
const headerStyle = window.getComputedStyle(header);
|
||||||
|
const arrowStyle = window.getComputedStyle(arrow);
|
||||||
|
|
||||||
|
expect(headerStyle.fontWeight).toBe(
|
||||||
|
supersetTheme.typography.weights.bold.toString(),
|
||||||
|
);
|
||||||
|
expect(headerStyle.fontSize).toBe(`${supersetTheme.gridUnit * 4}px`);
|
||||||
|
expect(headerStyle.color).toBe(
|
||||||
|
hexToRgb(supersetTheme.colors.grayscale.light4),
|
||||||
|
);
|
||||||
|
expect(arrowStyle.transition).toBe('transform 0.24s');
|
||||||
|
});
|
|
@ -18,11 +18,10 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { styled } from '@superset-ui/core';
|
import { styled } from '@superset-ui/core';
|
||||||
// eslint-disable-next-line no-restricted-imports
|
|
||||||
import { Collapse as AntdCollapse } from 'antd';
|
import { Collapse as AntdCollapse } from 'antd';
|
||||||
import { CollapseProps as AntdCollapseProps } from 'antd/lib/collapse';
|
import { CollapseProps as AntdCollapseProps } from 'antd/lib/collapse';
|
||||||
|
|
||||||
interface CollapseProps extends AntdCollapseProps {
|
export interface CollapseProps extends AntdCollapseProps {
|
||||||
light?: boolean;
|
light?: boolean;
|
||||||
bigger?: boolean;
|
bigger?: boolean;
|
||||||
bold?: boolean;
|
bold?: boolean;
|
||||||
|
@ -34,13 +33,7 @@ const Collapse = Object.assign(
|
||||||
styled(({ light, bigger, bold, animateArrows, ...props }: CollapseProps) => (
|
styled(({ light, bigger, bold, animateArrows, ...props }: CollapseProps) => (
|
||||||
<AntdCollapse {...props} />
|
<AntdCollapse {...props} />
|
||||||
))`
|
))`
|
||||||
height: 100%;
|
|
||||||
.ant-collapse-item {
|
.ant-collapse-item {
|
||||||
border: 0;
|
|
||||||
height: 100%;
|
|
||||||
&:last-of-type.ant-collapse-item-active {
|
|
||||||
padding-bottom: ${({ theme }) => theme.gridUnit * 3}px;
|
|
||||||
}
|
|
||||||
.ant-collapse-header {
|
.ant-collapse-header {
|
||||||
font-weight: ${({ bold, theme }) =>
|
font-weight: ${({ bold, theme }) =>
|
||||||
bold
|
bold
|
||||||
|
@ -80,9 +73,7 @@ const Collapse = Object.assign(
|
||||||
`}
|
`}
|
||||||
}
|
}
|
||||||
.ant-collapse-content {
|
.ant-collapse-content {
|
||||||
height: 100%;
|
|
||||||
.ant-collapse-content-box {
|
.ant-collapse-content-box {
|
||||||
height: 100%;
|
|
||||||
.loading.inline {
|
.loading.inline {
|
||||||
margin: ${({ theme }) => theme.gridUnit * 12}px auto;
|
margin: ${({ theme }) => theme.gridUnit * 12}px auto;
|
||||||
display: block;
|
display: block;
|
|
@ -17,9 +17,9 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import { styled } from '@superset-ui/core';
|
import { styled } from '@superset-ui/core';
|
||||||
import { Radio as BaseRadio } from 'src/common/components';
|
import { Radio as AntdRadio } from 'antd';
|
||||||
|
|
||||||
const StyledRadio = styled(BaseRadio)`
|
const StyledRadio = styled(AntdRadio)`
|
||||||
.ant-radio-inner {
|
.ant-radio-inner {
|
||||||
top: -1px;
|
top: -1px;
|
||||||
left: 2px;
|
left: 2px;
|
||||||
|
@ -51,7 +51,7 @@ const StyledRadio = styled(BaseRadio)`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
const StyledGroup = styled(BaseRadio.Group)`
|
const StyledGroup = styled(AntdRadio.Group)`
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
@ -18,13 +18,13 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTheme } from '@superset-ui/core';
|
import { useTheme } from '@superset-ui/core';
|
||||||
import { Tooltip as BaseTooltip } from 'src/common/components';
|
import { Tooltip as AntdTooltip } from 'antd';
|
||||||
import { TooltipProps } from 'antd/lib/tooltip';
|
import { TooltipProps } from 'antd/lib/tooltip';
|
||||||
|
|
||||||
export const Tooltip = (props: TooltipProps) => {
|
export const Tooltip = (props: TooltipProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
<BaseTooltip
|
<AntdTooltip
|
||||||
overlayStyle={{ fontSize: theme.typography.sizes.s, lineHeight: '1.6' }}
|
overlayStyle={{ fontSize: theme.typography.sizes.s, lineHeight: '1.6' }}
|
||||||
color={`${theme.colors.grayscale.dark2}e6`}
|
color={`${theme.colors.grayscale.dark2}e6`}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -34,7 +34,6 @@ import {
|
||||||
} from './DatePicker';
|
} from './DatePicker';
|
||||||
import Badge from './Badge';
|
import Badge from './Badge';
|
||||||
import ProgressBar from './ProgressBar';
|
import ProgressBar from './ProgressBar';
|
||||||
import Collapse from './Collapse';
|
|
||||||
import { CronPicker, CronError } from './CronPicker';
|
import { CronPicker, CronError } from './CronPicker';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -264,75 +263,6 @@ export const BadgeSuccess = () => <Badge status="success" text="Success" />;
|
||||||
export const BadgeError = () => <Badge status="error" text="Error" />;
|
export const BadgeError = () => <Badge status="error" text="Error" />;
|
||||||
export const BadgeSmall = () => <Badge count={100} size="small" />;
|
export const BadgeSmall = () => <Badge count={100} size="small" />;
|
||||||
|
|
||||||
export const CollapseDefault = () => (
|
|
||||||
<Collapse defaultActiveKey={['1']}>
|
|
||||||
<Collapse.Panel header="Hi! I am a header" key="1">
|
|
||||||
Hi! I am a sample content
|
|
||||||
</Collapse.Panel>
|
|
||||||
<Collapse.Panel header="Hi! I am another header" key="2">
|
|
||||||
Hi! I am another sample content
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
);
|
|
||||||
export const CollapseGhost = () => (
|
|
||||||
<Collapse defaultActiveKey={['1']} ghost>
|
|
||||||
<Collapse.Panel header="Hi! I am a header" key="1">
|
|
||||||
Hi! I am a sample content
|
|
||||||
</Collapse.Panel>
|
|
||||||
<Collapse.Panel header="Hi! I am another header" key="2">
|
|
||||||
Hi! I am another sample content
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
);
|
|
||||||
export const CollapseBold = () => (
|
|
||||||
<Collapse defaultActiveKey={['1']} bold>
|
|
||||||
<Collapse.Panel header="Hi! I am a header" key="1">
|
|
||||||
Hi! I am a sample content
|
|
||||||
</Collapse.Panel>
|
|
||||||
<Collapse.Panel header="Hi! I am another header" key="2">
|
|
||||||
Hi! I am another sample content
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
);
|
|
||||||
export const CollapseBigger = () => (
|
|
||||||
<Collapse defaultActiveKey={['1']} bigger>
|
|
||||||
<Collapse.Panel header="Hi! I am a header" key="1">
|
|
||||||
Hi! I am a sample content
|
|
||||||
</Collapse.Panel>
|
|
||||||
<Collapse.Panel header="Hi! I am another header" key="2">
|
|
||||||
Hi! I am another sample content
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
);
|
|
||||||
export const CollapseTextLight = () => (
|
|
||||||
<Collapse defaultActiveKey={['1']} light>
|
|
||||||
<Collapse.Panel
|
|
||||||
header="Hi! I am a header"
|
|
||||||
key="1"
|
|
||||||
style={{ background: '#BBB' }}
|
|
||||||
>
|
|
||||||
Hi! I am a sample content
|
|
||||||
</Collapse.Panel>
|
|
||||||
<Collapse.Panel
|
|
||||||
header="Hi! I am another header"
|
|
||||||
key="2"
|
|
||||||
style={{ background: '#BBB' }}
|
|
||||||
>
|
|
||||||
Hi! I am another sample content
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
);
|
|
||||||
export const CollapseAnimateArrows = () => (
|
|
||||||
<Collapse animateArrows defaultActiveKey={['1']}>
|
|
||||||
<Collapse.Panel header="Hi! I am a header" key="1">
|
|
||||||
Hi! I am a sample content
|
|
||||||
</Collapse.Panel>
|
|
||||||
<Collapse.Panel header="Hi! I am another header" key="2">
|
|
||||||
Hi! I am another sample content
|
|
||||||
</Collapse.Panel>
|
|
||||||
</Collapse>
|
|
||||||
);
|
|
||||||
|
|
||||||
export function StyledCronPicker() {
|
export function StyledCronPicker() {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const inputRef = useRef<Input>(null);
|
const inputRef = useRef<Input>(null);
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { styled } from '@superset-ui/core';
|
import { styled } from '@superset-ui/core';
|
||||||
// eslint-disable-next-line no-restricted-imports
|
|
||||||
import { Dropdown, Menu as AntdMenu, Input as AntdInput, Skeleton } from 'antd';
|
import { Dropdown, Menu as AntdMenu, Input as AntdInput, Skeleton } from 'antd';
|
||||||
import { DropDownProps } from 'antd/lib/dropdown';
|
import { DropDownProps } from 'antd/lib/dropdown';
|
||||||
/*
|
/*
|
||||||
|
@ -26,11 +25,9 @@ import { DropDownProps } from 'antd/lib/dropdown';
|
||||||
|
|
||||||
For documentation, see https://ant.design/components/overview/
|
For documentation, see https://ant.design/components/overview/
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line no-restricted-imports
|
|
||||||
export {
|
export {
|
||||||
AutoComplete,
|
AutoComplete,
|
||||||
Avatar,
|
Avatar,
|
||||||
Button,
|
|
||||||
Card,
|
Card,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Col,
|
Col,
|
||||||
|
@ -45,7 +42,6 @@ export {
|
||||||
Tree,
|
Tree,
|
||||||
Popover,
|
Popover,
|
||||||
Slider,
|
Slider,
|
||||||
Radio,
|
|
||||||
Row,
|
Row,
|
||||||
Space,
|
Space,
|
||||||
Select,
|
Select,
|
||||||
|
@ -60,7 +56,7 @@ export { default as Alert, AlertProps } from 'antd/lib/alert';
|
||||||
export { TreeProps } from 'antd/lib/tree';
|
export { TreeProps } from 'antd/lib/tree';
|
||||||
export { FormInstance } from 'antd/lib/form';
|
export { FormInstance } from 'antd/lib/form';
|
||||||
export { RadioChangeEvent } from 'antd/lib/radio';
|
export { RadioChangeEvent } from 'antd/lib/radio';
|
||||||
export { default as Collapse } from './Collapse';
|
|
||||||
export { default as Badge } from './Badge';
|
export { default as Badge } from './Badge';
|
||||||
export { default as Progress } from './ProgressBar';
|
export { default as Progress } from './ProgressBar';
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,7 +20,7 @@ import React, { CSSProperties, Children, ReactElement } from 'react';
|
||||||
import { kebabCase } from 'lodash';
|
import { kebabCase } from 'lodash';
|
||||||
import { mix } from 'polished';
|
import { mix } from 'polished';
|
||||||
import cx from 'classnames';
|
import cx from 'classnames';
|
||||||
import { Button as AntdButton } from 'src/common/components';
|
import { Button as AntdButton } from 'antd';
|
||||||
import { useTheme } from '@superset-ui/core';
|
import { useTheme } from '@superset-ui/core';
|
||||||
import { Tooltip } from 'src/common/components/Tooltip';
|
import { Tooltip } from 'src/common/components/Tooltip';
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,8 @@ import {
|
||||||
CheckCircleFilled,
|
CheckCircleFilled,
|
||||||
ExclamationCircleFilled,
|
ExclamationCircleFilled,
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import { Collapse, Popover } from 'src/common/components/index';
|
import { Popover } from 'src/common/components/index';
|
||||||
|
import Collapse from 'src/common/components/Collapse';
|
||||||
import { Global } from '@emotion/core';
|
import { Global } from '@emotion/core';
|
||||||
import {
|
import {
|
||||||
Indent,
|
Indent,
|
||||||
|
@ -173,7 +174,7 @@ const DetailsPanelPopover = ({
|
||||||
</Title>
|
</Title>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Indent>
|
<Indent css={{ paddingBottom: theme.gridUnit * 3 }}>
|
||||||
{appliedIndicators.map(indicator => (
|
{appliedIndicators.map(indicator => (
|
||||||
<Indicator
|
<Indicator
|
||||||
key={indicatorKey(indicator)}
|
key={indicatorKey(indicator)}
|
||||||
|
@ -197,7 +198,7 @@ const DetailsPanelPopover = ({
|
||||||
</Title>
|
</Title>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Indent>
|
<Indent css={{ paddingBottom: theme.gridUnit * 3 }}>
|
||||||
{incompatibleIndicators.map(indicator => (
|
{incompatibleIndicators.map(indicator => (
|
||||||
<Indicator
|
<Indicator
|
||||||
key={indicatorKey(indicator)}
|
key={indicatorKey(indicator)}
|
||||||
|
@ -219,7 +220,7 @@ const DetailsPanelPopover = ({
|
||||||
}
|
}
|
||||||
disabled={!unsetIndicators.length}
|
disabled={!unsetIndicators.length}
|
||||||
>
|
>
|
||||||
<Indent>
|
<Indent css={{ paddingBottom: theme.gridUnit * 3 }}>
|
||||||
{unsetIndicators.map(indicator => (
|
{unsetIndicators.map(indicator => (
|
||||||
<Indicator
|
<Indicator
|
||||||
key={indicatorKey(indicator)}
|
key={indicatorKey(indicator)}
|
||||||
|
|
|
@ -24,8 +24,8 @@ import { connect } from 'react-redux';
|
||||||
import { t, styled, getChartControlPanelRegistry } from '@superset-ui/core';
|
import { t, styled, getChartControlPanelRegistry } from '@superset-ui/core';
|
||||||
|
|
||||||
import Tabs from 'src/common/components/Tabs';
|
import Tabs from 'src/common/components/Tabs';
|
||||||
import { Collapse } from 'src/common/components';
|
|
||||||
import Alert from 'src/components/Alert';
|
import Alert from 'src/components/Alert';
|
||||||
|
import Collapse from 'src/common/components/Collapse';
|
||||||
import { PluginContext } from 'src/components/DynamicPlugins';
|
import { PluginContext } from 'src/components/DynamicPlugins';
|
||||||
import Loading from 'src/components/Loading';
|
import Loading from 'src/components/Loading';
|
||||||
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
import { InfoTooltipWithTrigger } from '@superset-ui/chart-controls';
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { styled, t } from '@superset-ui/core';
|
import { styled, t, css } from '@superset-ui/core';
|
||||||
import { Collapse } from 'src/common/components';
|
import Collapse from 'src/common/components/Collapse';
|
||||||
import Tabs from 'src/common/components/Tabs';
|
import Tabs from 'src/common/components/Tabs';
|
||||||
import Loading from 'src/components/Loading';
|
import Loading from 'src/components/Loading';
|
||||||
import TableView, { EmptyWrapperType } from 'src/components/TableView';
|
import TableView, { EmptyWrapperType } from 'src/components/TableView';
|
||||||
|
@ -264,8 +264,27 @@ export const DataTablesPane = ({
|
||||||
onChange={handleCollapseChange}
|
onChange={handleCollapseChange}
|
||||||
bold
|
bold
|
||||||
ghost
|
ghost
|
||||||
|
css={css`
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.ant-collapse-item {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.ant-collapse-content {
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.ant-collapse-content-box {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<Collapse.Panel
|
||||||
|
header={t('Data')}
|
||||||
|
key={DATAPANEL_KEY}
|
||||||
|
css={{ paddingBottom: 12 }}
|
||||||
>
|
>
|
||||||
<Collapse.Panel header={t('Data')} key={DATAPANEL_KEY}>
|
|
||||||
<Tabs
|
<Tabs
|
||||||
fullWidth={false}
|
fullWidth={false}
|
||||||
tabBarExtraContent={TableControls}
|
tabBarExtraContent={TableControls}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { styled, t } from '@superset-ui/core';
|
import { styled, t } from '@superset-ui/core';
|
||||||
import { Collapse } from 'src/common/components';
|
import Collapse from 'src/common/components/Collapse';
|
||||||
import {
|
import {
|
||||||
ColumnOption,
|
ColumnOption,
|
||||||
MetricOption,
|
MetricOption,
|
||||||
|
|
|
@ -18,9 +18,10 @@
|
||||||
*/
|
*/
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Panel } from 'react-bootstrap';
|
import { css } from '@emotion/core';
|
||||||
|
import { t } from '@superset-ui/core';
|
||||||
import Label from 'src/components/Label';
|
import Label from 'src/components/Label';
|
||||||
|
import Collapse from 'src/common/components/Collapse';
|
||||||
import TextControl from './TextControl';
|
import TextControl from './TextControl';
|
||||||
import MetricsControl from './MetricControl/MetricsControl';
|
import MetricsControl from './MetricControl/MetricsControl';
|
||||||
import ControlHeader from '../ControlHeader';
|
import ControlHeader from '../ControlHeader';
|
||||||
|
@ -54,7 +55,6 @@ export default class FixedOrMetricControl extends React.Component {
|
||||||
this.setType = this.setType.bind(this);
|
this.setType = this.setType.bind(this);
|
||||||
this.setFixedValue = this.setFixedValue.bind(this);
|
this.setFixedValue = this.setFixedValue.bind(this);
|
||||||
this.setMetric = this.setMetric.bind(this);
|
this.setMetric = this.setMetric.bind(this);
|
||||||
this.toggle = this.toggle.bind(this);
|
|
||||||
const type =
|
const type =
|
||||||
(props.value ? props.value.type : props.default.type) ||
|
(props.value ? props.value.type : props.default.type) ||
|
||||||
controlTypes.fixed;
|
controlTypes.fixed;
|
||||||
|
@ -89,12 +89,6 @@ export default class FixedOrMetricControl extends React.Component {
|
||||||
this.setState({ metricValue }, this.onChange);
|
this.setState({ metricValue }, this.onChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
toggle() {
|
|
||||||
this.setState(prevState => ({
|
|
||||||
expanded: !prevState.expanded,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const value = this.props.value || this.props.default;
|
const value = this.props.value || this.props.default;
|
||||||
const type = value.type || controlTypes.fixed;
|
const type = value.type || controlTypes.fixed;
|
||||||
|
@ -107,30 +101,52 @@ export default class FixedOrMetricControl extends React.Component {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ControlHeader {...this.props} />
|
<ControlHeader {...this.props} />
|
||||||
<Label onClick={this.toggle}>
|
<Collapse
|
||||||
|
ghost
|
||||||
|
css={theme => css`
|
||||||
|
&.ant-collapse
|
||||||
|
> .ant-collapse-item.ant-collapse-no-arrow
|
||||||
|
> .ant-collapse-header {
|
||||||
|
border: 0px;
|
||||||
|
padding: 0px 0px ${theme.gridUnit * 2}px 0px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
&.ant-collapse-ghost
|
||||||
|
> .ant-collapse-item
|
||||||
|
> .ant-collapse-content
|
||||||
|
> .ant-collapse-content-box {
|
||||||
|
padding: 0px;
|
||||||
|
|
||||||
|
& .well {
|
||||||
|
margin-bottom: 0px;
|
||||||
|
padding: ${theme.gridUnit * 2}px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<Collapse.Panel
|
||||||
|
showArrow={false}
|
||||||
|
header={
|
||||||
|
<Label onClick={() => undefined}>
|
||||||
{this.state.type === controlTypes.fixed && (
|
{this.state.type === controlTypes.fixed && (
|
||||||
<span>{this.state.fixedValue}</span>
|
<span>{this.state.fixedValue}</span>
|
||||||
)}
|
)}
|
||||||
{this.state.type === controlTypes.metric && (
|
{this.state.type === controlTypes.metric && (
|
||||||
<span>
|
<span>
|
||||||
<span style={{ fontWeight: 'normal' }}>metric: </span>
|
<span>metric: </span>
|
||||||
<strong>
|
<strong>
|
||||||
{this.state.metricValue ? this.state.metricValue.label : null}
|
{this.state.metricValue
|
||||||
|
? this.state.metricValue.label
|
||||||
|
: null}
|
||||||
</strong>
|
</strong>
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</Label>
|
</Label>
|
||||||
<Panel
|
}
|
||||||
className="panel-spreaded"
|
|
||||||
collapsible
|
|
||||||
expanded={this.state.expanded}
|
|
||||||
onToggle={this.toggle}
|
|
||||||
>
|
>
|
||||||
<Panel.Collapse>
|
|
||||||
<Panel.Body>
|
|
||||||
<div className="well">
|
<div className="well">
|
||||||
<PopoverSection
|
<PopoverSection
|
||||||
title="Fixed"
|
title={t('Fixed')}
|
||||||
isSelected={type === controlTypes.fixed}
|
isSelected={type === controlTypes.fixed}
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
this.setType(controlTypes.fixed);
|
this.setType(controlTypes.fixed);
|
||||||
|
@ -146,7 +162,7 @@ export default class FixedOrMetricControl extends React.Component {
|
||||||
/>
|
/>
|
||||||
</PopoverSection>
|
</PopoverSection>
|
||||||
<PopoverSection
|
<PopoverSection
|
||||||
title="Based on a metric"
|
title={t('Based on a metric')}
|
||||||
isSelected={type === controlTypes.metric}
|
isSelected={type === controlTypes.metric}
|
||||||
onSelect={() => {
|
onSelect={() => {
|
||||||
this.setType(controlTypes.metric);
|
this.setType(controlTypes.metric);
|
||||||
|
@ -165,9 +181,8 @@ export default class FixedOrMetricControl extends React.Component {
|
||||||
/>
|
/>
|
||||||
</PopoverSection>
|
</PopoverSection>
|
||||||
</div>
|
</div>
|
||||||
</Panel.Body>
|
</Collapse.Panel>
|
||||||
</Panel.Collapse>
|
</Collapse>
|
||||||
</Panel>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -233,15 +233,3 @@ h2.section-header {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.panel-spreaded,
|
|
||||||
.panel-spreaded .panel-body {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-spreaded .well {
|
|
||||||
margin-top: 8px;
|
|
||||||
margin-bottom: 0;
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
export function hexToRgb(h: string) {
|
||||||
|
let r = '0';
|
||||||
|
let g = '0';
|
||||||
|
let b = '0';
|
||||||
|
|
||||||
|
// 3 digits
|
||||||
|
if (h.length === 4) {
|
||||||
|
r = `0x${h[1]}${h[1]}`;
|
||||||
|
g = `0x${h[2]}${h[2]}`;
|
||||||
|
b = `0x${h[3]}${h[3]}`;
|
||||||
|
|
||||||
|
// 6 digits
|
||||||
|
} else if (h.length === 7) {
|
||||||
|
r = `0x${h[1]}${h[2]}`;
|
||||||
|
g = `0x${h[3]}${h[4]}`;
|
||||||
|
b = `0x${h[5]}${h[6]}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `rgb(${+r}, ${+g}, ${+b})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function rgbToHex(red: number, green: number, blue: number) {
|
||||||
|
let r = red.toString(16);
|
||||||
|
let g = green.toString(16);
|
||||||
|
let b = blue.toString(16);
|
||||||
|
|
||||||
|
if (r.length === 1) r = `0${r}`;
|
||||||
|
if (g.length === 1) g = `0${g}`;
|
||||||
|
if (b.length === 1) b = `0${b}`;
|
||||||
|
|
||||||
|
return `#${r}${g}${b}`;
|
||||||
|
}
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { styled, t } from '@superset-ui/core';
|
import { styled, t } from '@superset-ui/core';
|
||||||
import { Collapse } from 'src/common/components';
|
import Collapse from 'src/common/components/Collapse';
|
||||||
import { User } from 'src/types/bootstrapTypes';
|
import { User } from 'src/types/bootstrapTypes';
|
||||||
import { reject } from 'lodash';
|
import { reject } from 'lodash';
|
||||||
import withToasts from 'src/messageToasts/enhancers/withToasts';
|
import withToasts from 'src/messageToasts/enhancers/withToasts';
|
||||||
|
|
Loading…
Reference in New Issue