This is an automated email from the ASF dual-hosted git repository.
christine pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-superset.git
The following commit(s) were added to refs/heads/master by this push:
new ec6657a Relayout SQL Editor (#6872)
ec6657a is described below
commit ec6657ab2d07d6982a454e20745445ab673a6a0f
Author: Christine Chambers <[email protected]>
AuthorDate: Thu Feb 14 18:03:43 2019 -0800
Relayout SQL Editor (#6872)
* Relayout SQL Editor
- Refactor SQL editor to remove usage of bootstrap col, row and collapse to
simplify the layout
- Replace the react-split-pane libraray with react-split to allow custom
styling of the gutter area without sacrifice correctness of the ace editor
height calculation
- Rewrite the left pane animation via plain css transition and animate it
to slide in and out
- General code and css clean up
* Smooth out the visual transition during dragging
(cherry picked from commit 19f82b729c7a939f12b1c5da6022c0fd76fa3ec9)
* Adjust how the height of the south pane is computed, fixing cypress tests
---
superset/assets/package-lock.json | 25 +++
superset/assets/package.json | 3 +-
.../spec/javascripts/sqllab/SouthPane_spec.jsx | 9 +-
.../spec/javascripts/sqllab/SqlEditor_spec.jsx | 5 +
superset/assets/src/SqlLab/components/App.jsx | 2 +-
.../assets/src/SqlLab/components/SouthPane.jsx | 25 ++-
.../assets/src/SqlLab/components/SqlEditor.jsx | 186 ++++++++++-----------
.../src/SqlLab/components/SqlEditorLeftBar.jsx | 3 +-
.../src/SqlLab/components/TabbedSqlEditors.jsx | 2 -
superset/assets/src/SqlLab/main.less | 70 ++++++--
superset/assets/src/components/AsyncSelect.jsx | 20 +--
superset/assets/src/components/TableSelector.css | 18 +-
superset/assets/src/components/TableSelector.jsx | 87 ++++------
13 files changed, 272 insertions(+), 183 deletions(-)
diff --git a/superset/assets/package-lock.json
b/superset/assets/package-lock.json
index f6ba04f..ba19bac 100644
--- a/superset/assets/package-lock.json
+++ b/superset/assets/package-lock.json
@@ -17339,6 +17339,15 @@
"prop-types": "^15.5.7"
}
},
+ "react-split": {
+ "version": "2.0.4",
+ "resolved":
"https://registry.npmjs.org/react-split/-/react-split-2.0.4.tgz",
+ "integrity":
"sha512-NBKm9MaqzG/00laMUaS8GS9RnItVSekNNwItgGLMbFTeUa9w4bIY8Co/LszNBnpza9n2am0MXIw3SmyiMnhs+w==",
+ "requires": {
+ "prop-types": "^15.5.7",
+ "split.js": "^1.5.9"
+ }
+ },
"react-split-pane": {
"version": "0.1.85",
"resolved":
"https://registry.npmjs.org/react-split-pane/-/react-split-pane-0.1.85.tgz",
@@ -17380,6 +17389,17 @@
"refractor": "^2.4.1"
}
},
+ "react-transition-group": {
+ "version": "2.5.3",
+ "resolved":
"https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.3.tgz",
+ "integrity":
"sha512-2DGFck6h99kLNr8pOFk+z4Soq3iISydwOFeeEVPjTN6+Y01CmvbWmnN02VuTWyFdnRtIDPe+wy2q6Ui8snBPZg==",
+ "requires": {
+ "dom-helpers": "^3.3.1",
+ "loose-envify": "^1.4.0",
+ "prop-types": "^15.6.2",
+ "react-lifecycles-compat": "^3.0.4"
+ }
+ },
"react-virtualized": {
"version": "9.19.1",
"resolved":
"https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.19.1.tgz",
@@ -19391,6 +19411,11 @@
}
}
},
+ "split.js": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/split.js/-/split.js-1.5.10.tgz",
+ "integrity":
"sha512-/J52X5c4ZypVwu4WAhD8E1T9uXQtNokvG6mIBHauzyA1aKH6bmETVSv3RPjBXEz6Gcc4mIThgmjGQL39LD16jQ=="
+ },
"sprintf-js": {
"version": "1.0.3",
"resolved":
"http://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
diff --git a/superset/assets/package.json b/superset/assets/package.json
index c791fb6..02a9fdc 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -123,9 +123,10 @@
"react-select": "1.2.1",
"react-select-fast-filter-options": "^0.2.1",
"react-sortable-hoc": "^0.8.3",
- "react-split-pane": "^0.1.66",
+ "react-split": "^2.0.4",
"react-sticky": "^6.0.2",
"react-syntax-highlighter": "^7.0.4",
+ "react-transition-group": "^2.5.3",
"react-virtualized": "9.19.1",
"react-virtualized-select": "^3.1.3",
"reactable-arc": "0.14.42",
diff --git a/superset/assets/spec/javascripts/sqllab/SouthPane_spec.jsx
b/superset/assets/spec/javascripts/sqllab/SouthPane_spec.jsx
index 7b920f6..da6da52 100644
--- a/superset/assets/spec/javascripts/sqllab/SouthPane_spec.jsx
+++ b/superset/assets/spec/javascripts/sqllab/SouthPane_spec.jsx
@@ -24,7 +24,7 @@ import { shallow } from 'enzyme';
import { STATUS_OPTIONS } from '../../../src/SqlLab/constants';
import { initialState } from './fixtures';
-import SouthPane from '../../../src/SqlLab/components/SouthPane';
+import SouthPaneContainer, { SouthPane } from
'../../../src/SqlLab/components/SouthPane';
describe('SouthPane', () => {
const middlewares = [thunk];
@@ -42,11 +42,16 @@ describe('SouthPane', () => {
};
const getWrapper = () => (
- shallow(<SouthPane {...mockedProps} />, {
+ shallow(<SouthPaneContainer {...mockedProps} />, {
context: { store },
}).dive());
let wrapper;
+
+ beforeAll(() => {
+ jest.spyOn(SouthPane.prototype,
'getSouthPaneHeight').mockImplementation(() => 500);
+ });
+
it('should render offline when the state is offline', () => {
wrapper = getWrapper();
wrapper.setProps({ offline: true });
diff --git a/superset/assets/spec/javascripts/sqllab/SqlEditor_spec.jsx
b/superset/assets/spec/javascripts/sqllab/SqlEditor_spec.jsx
index 933524f..046b2e6 100644
--- a/superset/assets/spec/javascripts/sqllab/SqlEditor_spec.jsx
+++ b/superset/assets/spec/javascripts/sqllab/SqlEditor_spec.jsx
@@ -38,6 +38,11 @@ describe('SqlEditor', () => {
defaultQueryLimit: 1000,
maxRow: 100000,
};
+
+ beforeAll(() => {
+ jest.spyOn(SqlEditor.prototype,
'getSqlEditorHeight').mockImplementation(() => 500);
+ });
+
it('is valid', () => {
expect(
React.isValidElement(<SqlEditor {...mockedProps} />),
diff --git a/superset/assets/src/SqlLab/components/App.jsx
b/superset/assets/src/SqlLab/components/App.jsx
index bf50caf..25c61de 100644
--- a/superset/assets/src/SqlLab/components/App.jsx
+++ b/superset/assets/src/SqlLab/components/App.jsx
@@ -84,7 +84,7 @@ class App extends React.PureComponent {
content = (
<div>
<QueryAutoRefresh />
- <TabbedSqlEditors getHeight={this.getHeight} />
+ <TabbedSqlEditors />
</div>
);
}
diff --git a/superset/assets/src/SqlLab/components/SouthPane.jsx
b/superset/assets/src/SqlLab/components/SouthPane.jsx
index 0dd1626..40d46da 100644
--- a/superset/assets/src/SqlLab/components/SouthPane.jsx
+++ b/superset/assets/src/SqlLab/components/SouthPane.jsx
@@ -48,7 +48,24 @@ const defaultProps = {
offline: false,
};
-class SouthPane extends React.PureComponent {
+export class SouthPane extends React.PureComponent {
+ constructor(props) {
+ super(props);
+ this.state = {
+ height: props.height,
+ };
+ this.southPaneRef = React.createRef();
+ this.getSouthPaneHeight = this.getSouthPaneHeight.bind(this);
+ this.switchTab = this.switchTab.bind(this);
+ }
+ componentWillReceiveProps() {
+ // south pane expands the entire height of the tab content on mount
+ this.setState({ height: this.getSouthPaneHeight() });
+ }
+ // One layer of abstraction for easy spying in unit tests
+ getSouthPaneHeight() {
+ return this.southPaneRef.current.clientHeight;
+ }
switchTab(id) {
this.props.actions.setActiveSouthPaneTab(id);
}
@@ -59,7 +76,7 @@ class SouthPane extends React.PureComponent {
{ STATUS_OPTIONS.offline }
</Label>);
}
- const innerTabHeight = this.props.height - 55;
+ const innerTabHeight = this.state.height - 55;
let latestQuery;
const props = this.props;
if (props.editorQueries.length > 0) {
@@ -98,12 +115,12 @@ class SouthPane extends React.PureComponent {
));
return (
- <div className="SouthPane">
+ <div className="SouthPane" ref={this.southPaneRef}>
<Tabs
bsStyle="tabs"
id={shortid.generate()}
activeKey={this.props.activeSouthPaneTab}
- onSelect={this.switchTab.bind(this)}
+ onSelect={this.switchTab}
>
<Tab
title={t('Results')}
diff --git a/superset/assets/src/SqlLab/components/SqlEditor.jsx
b/superset/assets/src/SqlLab/components/SqlEditor.jsx
index 07344a5..dccad0b 100644
--- a/superset/assets/src/SqlLab/components/SqlEditor.jsx
+++ b/superset/assets/src/SqlLab/components/SqlEditor.jsx
@@ -17,21 +17,18 @@
* under the License.
*/
import React from 'react';
+import { CSSTransition } from 'react-transition-group';
import PropTypes from 'prop-types';
-import { throttle } from 'lodash';
import {
- Col,
FormGroup,
InputGroup,
Form,
FormControl,
Label,
OverlayTrigger,
- Row,
Tooltip,
- Collapse,
} from 'react-bootstrap';
-import SplitPane from 'react-split-pane';
+import Split from 'react-split';
import { t } from '@superset-ui/translation';
import Button from '../../components/Button';
@@ -47,9 +44,13 @@ import AceEditorWrapper from './AceEditorWrapper';
import { STATE_BSSTYLE_MAP } from '../constants';
import RunQueryActionButton from './RunQueryActionButton';
+const SQL_TOOLBAR_HEIGHT = 51;
+const GUTTER_HEIGHT = 5;
+const INITIAL_NORTH_PERCENT = 30;
+const INITIAL_SOUTH_PERCENT = 70;
+
const propTypes = {
actions: PropTypes.object.isRequired,
- getHeight: PropTypes.func.isRequired,
database: PropTypes.object,
latestQuery: PropTypes.object,
tables: PropTypes.array.isRequired,
@@ -75,13 +76,18 @@ class SqlEditor extends React.PureComponent {
ctas: '',
sql: props.queryEditor.sql,
};
+ this.sqlEditorRef = React.createRef();
+ this.northPaneRef = React.createRef();
- this.onResize = this.onResize.bind(this);
- this.throttledResize = throttle(this.onResize, 250);
+ this.onResizeStart = this.onResizeStart.bind(this);
+ this.onResizeEnd = this.onResizeEnd.bind(this);
this.runQuery = this.runQuery.bind(this);
this.stopQuery = this.stopQuery.bind(this);
this.onSqlChanged = this.onSqlChanged.bind(this);
this.setQueryEditorSql = this.setQueryEditorSql.bind(this);
+ this.queryPane = this.queryPane.bind(this);
+ this.getAceEditorAndSouthPaneHeights =
this.getAceEditorAndSouthPaneHeights.bind(this);
+ this.getSqlEditorHeight = this.getSqlEditorHeight.bind(this);
}
componentWillMount() {
if (this.state.autorun) {
@@ -91,29 +97,41 @@ class SqlEditor extends React.PureComponent {
}
}
componentDidMount() {
- this.onResize();
- window.addEventListener('resize', this.throttledResize);
+ // We need to measure the height of the sql editor post render to figure
the height of
+ // the south pane so it gets rendered properly
+ // eslint-disable-next-line react/no-did-mount-set-state
+ this.setState({ height: this.getSqlEditorHeight() });
}
- componentWillUnmount() {
- window.removeEventListener('resize', this.throttledResize);
+ onResizeStart() {
+ // Set the heights on the ace editor and the ace content area after drag
starts
+ // to smooth out the visual transition to the new heights when drag ends
+ document.getElementById('brace-editor').style.height = `calc(100% -
${SQL_TOOLBAR_HEIGHT}px)`;
+ document.getElementsByClassName('ace_content')[0].style.height = '100%';
}
- onResize() {
- const height = this.sqlEditorHeight();
- const editorPaneHeight = this.props.queryEditor.height || 200;
- const splitPaneHandlerHeight = 8; // 4px of height + 4px of top-margin
- this.setState({
- editorPaneHeight,
- southPaneHeight: height - editorPaneHeight - splitPaneHandlerHeight,
- height,
- });
+ onResizeEnd([northPercent, southPercent]) {
+ this.setState(this.getAceEditorAndSouthPaneHeights(
+ this.state.height, northPercent, southPercent));
- if (this.refs.ace && this.refs.ace.clientHeight) {
- this.props.actions.persistEditorHeight(this.props.queryEditor,
this.refs.ace.clientHeight);
+ if (this.northPaneRef.current && this.northPaneRef.current.clientHeight) {
+ this.props.actions.persistEditorHeight(this.props.queryEditor,
+ this.northPaneRef.current.clientHeight);
}
}
onSqlChanged(sql) {
this.setState({ sql });
}
+ // One layer of abstraction for easy spying in unit tests
+ getSqlEditorHeight() {
+ return this.sqlEditorRef.current.clientHeight;
+ }
+ // Return the heights for the ace editor and the south pane as an object
+ // given the height of the sql editor, north pane percent and south pane
percent.
+ getAceEditorAndSouthPaneHeights(height, northPercent, southPercent) {
+ return {
+ aceEditorHeight: height * northPercent / 100 - SQL_TOOLBAR_HEIGHT -
GUTTER_HEIGHT / 2,
+ southPaneHeight: height * southPercent / 100,
+ };
+ }
getHotkeyConfig() {
return [
{
@@ -187,9 +205,42 @@ class SqlEditor extends React.PureComponent {
ctasChanged(event) {
this.setState({ ctas: event.target.value });
}
- sqlEditorHeight() {
- const horizontalScrollbarHeight = 25;
- return parseInt(this.props.getHeight(), 10) - horizontalScrollbarHeight;
+ queryPane() {
+ const hotkeys = this.getHotkeyConfig();
+ const { aceEditorHeight, southPaneHeight } =
this.getAceEditorAndSouthPaneHeights(
+ this.state.height, INITIAL_NORTH_PERCENT, INITIAL_SOUTH_PERCENT);
+ return (
+ <div className="queryPane">
+ <Split
+ sizes={[INITIAL_NORTH_PERCENT, INITIAL_SOUTH_PERCENT]}
+ minSize={200}
+ direction="vertical"
+ gutterSize={GUTTER_HEIGHT}
+ onDragStart={this.onResizeStart}
+ onDragEnd={this.onResizeEnd}
+ >
+ <div ref={this.northPaneRef}>
+ <AceEditorWrapper
+ actions={this.props.actions}
+ onBlur={this.setQueryEditorSql}
+ onChange={this.onSqlChanged}
+ queryEditor={this.props.queryEditor}
+ sql={this.props.queryEditor.sql}
+ tables={this.props.tables}
+ height={`${this.state.aceEditorHeight || aceEditorHeight}px`}
+ hotkeys={hotkeys}
+ />
+ {this.renderEditorBottomBar(hotkeys)}
+ </div>
+ <SouthPane
+ editorQueries={this.props.editorQueries}
+ dataPreviewQueries={this.props.dataPreviewQueries}
+ actions={this.props.actions}
+ height={this.state.southPaneHeight || southPaneHeight}
+ />
+ </Split>
+ </div>
+ );
}
renderEditorBottomBar(hotkeys) {
let ctasControls;
@@ -305,74 +356,23 @@ class SqlEditor extends React.PureComponent {
);
}
render() {
- const height = this.sqlEditorHeight();
- const defaultNorthHeight = this.props.queryEditor.height || 200;
- const hotkeys = this.getHotkeyConfig();
return (
- <div
- className="SqlEditor"
- style={{
- height: height + 'px',
- }}
- >
- <Row>
- <Collapse
- in={!this.props.hideLeftBar}
- >
- <Col
- xs={6}
- sm={5}
- md={4}
- lg={3}
- >
- <SqlEditorLeftBar
- height={height}
- database={this.props.database}
- queryEditor={this.props.queryEditor}
- tables={this.props.tables}
- actions={this.props.actions}
- />
- </Col>
- </Collapse>
- <Col
- xs={this.props.hideLeftBar ? 12 : 6}
- sm={this.props.hideLeftBar ? 12 : 7}
- md={this.props.hideLeftBar ? 12 : 8}
- lg={this.props.hideLeftBar ? 12 : 9}
- style={{ height: this.state.height }}
- >
- <SplitPane
- split="horizontal"
- defaultSize={defaultNorthHeight}
- minSize={100}
- onChange={this.onResize}
- >
- <div ref="ace" style={{ width: '100%' }}>
- <div>
- <AceEditorWrapper
- actions={this.props.actions}
- onBlur={this.setQueryEditorSql}
- onChange={this.onSqlChanged}
- queryEditor={this.props.queryEditor}
- sql={this.props.queryEditor.sql}
- tables={this.props.tables}
- height={((this.state.editorPaneHeight ||
defaultNorthHeight) - 50) + 'px'}
- hotkeys={hotkeys}
- />
- {this.renderEditorBottomBar(hotkeys)}
- </div>
- </div>
- <div ref="south">
- <SouthPane
- editorQueries={this.props.editorQueries}
- dataPreviewQueries={this.props.dataPreviewQueries}
- actions={this.props.actions}
- height={this.state.southPaneHeight || 0}
- />
- </div>
- </SplitPane>
- </Col>
- </Row>
+ <div ref={this.sqlEditorRef} className="SqlEditor">
+ <CSSTransition
+ classNames="schemaPane"
+ in={!this.props.hideLeftBar}
+ timeout={300}
+ >
+ <div className="schemaPane">
+ <SqlEditorLeftBar
+ database={this.props.database}
+ queryEditor={this.props.queryEditor}
+ tables={this.props.tables}
+ actions={this.props.actions}
+ />
+ </div>
+ </CSSTransition>
+ {this.queryPane()}
</div>
);
}
diff --git a/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx
b/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx
index 16170a6..0de18b0 100644
--- a/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx
+++ b/superset/assets/src/SqlLab/components/SqlEditorLeftBar.jsx
@@ -20,7 +20,6 @@ import React from 'react';
import PropTypes from 'prop-types';
import { Button } from 'react-bootstrap';
import { t } from '@superset-ui/translation';
-
import TableElement from './TableElement';
import TableSelector from '../../components/TableSelector';
@@ -106,7 +105,7 @@ export default class SqlEditorLeftBar extends
React.PureComponent {
const tableMetaDataHeight = this.props.height - 130; // 130 is the height
of the selects above
const qe = this.props.queryEditor;
return (
- <div className="clearfix">
+ <div className="sqlEditorLeftBar">
<TableSelector
dbId={qe.dbId}
schema={qe.schema}
diff --git a/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
b/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
index a90a2bf..a0a991c 100644
--- a/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
+++ b/superset/assets/src/SqlLab/components/TabbedSqlEditors.jsx
@@ -39,7 +39,6 @@ const propTypes = {
queryEditors: PropTypes.array,
tabHistory: PropTypes.array.isRequired,
tables: PropTypes.array.isRequired,
- getHeight: PropTypes.func.isRequired,
offline: PropTypes.bool,
};
const defaultProps = {
@@ -238,7 +237,6 @@ class TabbedSqlEditors extends React.PureComponent {
<div className="panel-body">
{isSelected && (
<SqlEditor
- getHeight={this.props.getHeight}
tables={this.props.tables.filter(xt => xt.queryEditorId ===
qe.id)}
queryEditor={qe}
editorQueries={this.state.queriesArray}
diff --git a/superset/assets/src/SqlLab/main.less
b/superset/assets/src/SqlLab/main.less
index cd2cdd8..28755a3 100644
--- a/superset/assets/src/SqlLab/main.less
+++ b/superset/assets/src/SqlLab/main.less
@@ -135,7 +135,8 @@ div.Workspace {
background-color: #e8e8e8;
display: flex;
justify-content: space-between;
- border-bottom: 2px solid #ccc;
+ border: 1px solid #ccc;
+ border-top: 0;
form {
margin-block-end: 0;
@@ -193,21 +194,67 @@ div.Workspace {
background-color: transparent !important;
}
+.SqlLab {
+ .tab-content {
+ height: 100%;
+ }
+
+ #brace-editor {
+ height: calc(100% - 51px);
+ }
+
+ .ace_content {
+ height: 100%;
+ }
+
+ .SouthPane {
+ height: 100%;
+ }
+}
+
.SqlEditor {
- .Resizer {
- -moz-box-sizing: border-box;
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
+ display: flex;
+ flex-direction: row;
+ height: 100%;
+
+ .schemaPane {
+ flex-grow: 1;
+ transition: all .3s ease-in-out;
}
- .Resizer.horizontal {
- height: 4px;
+ .schemaPane-enter-done, .schemaPane-exit {
+ transform: translateX(0);
+ }
+
+ .schemaPane-enter-active, .schemaPane-exit-active {
+ transform: translateX(-50%);
+ }
+
+ .schemaPane-enter, .schemaPane-exit-done {
+ transform: translateX(-100%);
+ max-width: 0;
+ overflow: hidden;
+ }
+
+ .queryPane {
+ flex-grow: 8;
+ position: relative;
+ margin-left: 15px;
+ }
+
+ .schemaPane-exit-done + .queryPane {
+ margin-left: 0;
+ }
+
+ .gutter {
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
+ width: 3%;
+ margin: 3px 47%;
+ }
+
+ .gutter.gutter-vertical {
cursor: row-resize;
- width: 4%;
- margin-top: 4px;
- margin-left: 47%;
}
}
@@ -298,9 +345,6 @@ a.Link {
.tooltip-inner {
max-width: 500px;
}
-.SplitPane.horizontal {
- padding-right: 4px;
-}
.SouthPane {
margin-top: 10px;
position: absolute;
diff --git a/superset/assets/src/components/AsyncSelect.jsx
b/superset/assets/src/components/AsyncSelect.jsx
index 1106402..da32fab 100644
--- a/superset/assets/src/components/AsyncSelect.jsx
+++ b/superset/assets/src/components/AsyncSelect.jsx
@@ -83,17 +83,15 @@ class AsyncSelect extends React.PureComponent {
render() {
return (
- <div>
- <Select
- placeholder={this.props.placeholder}
- options={this.state.options}
- value={this.props.value}
- isLoading={this.state.isLoading}
- onChange={this.onChange}
- valueRenderer={this.props.valueRenderer}
- {...this.props}
- />
- </div>
+ <Select
+ placeholder={this.props.placeholder}
+ options={this.state.options}
+ value={this.props.value}
+ isLoading={this.state.isLoading}
+ onChange={this.onChange}
+ valueRenderer={this.props.valueRenderer}
+ {...this.props}
+ />
);
}
}
diff --git a/superset/assets/src/components/TableSelector.css
b/superset/assets/src/components/TableSelector.css
index b4636de..41b8d11 100644
--- a/superset/assets/src/components/TableSelector.css
+++ b/superset/assets/src/components/TableSelector.css
@@ -17,8 +17,22 @@
* under the License.
*/
.TableSelector .fa-refresh {
- padding-top: 7px
+ padding-left: 9px;
}
.TableSelector .refresh-col {
- padding-left: 0px;
+ display: flex;
+ align-items: center;
+ width: 30px;
+}
+.TableSelector .section {
+ padding-bottom: 5px;
+ display: flex;
+ flex-direction: row;
+}
+.TableSelector .select {
+ flex-grow: 1;
+}
+.TableSelector .divider {
+ border-bottom: 1px solid #f2f2f2;
+ margin: 10px 0;
}
diff --git a/superset/assets/src/components/TableSelector.jsx
b/superset/assets/src/components/TableSelector.jsx
index 9031d1a..6130fc6 100644
--- a/superset/assets/src/components/TableSelector.jsx
+++ b/superset/assets/src/components/TableSelector.jsx
@@ -20,7 +20,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import Select from 'react-virtualized-select';
import createFilterOptions from 'react-select-fast-filter-options';
-import { ControlLabel, Col, Label, Row } from 'react-bootstrap';
+import { ControlLabel, Label } from 'react-bootstrap';
import { t } from '@superset-ui/translation';
import { SupersetClient } from '@superset-ui/connection';
@@ -38,7 +38,6 @@ const propTypes = {
tableNameSticky: PropTypes.bool,
tableName: PropTypes.string,
database: PropTypes.object,
- horizontal: PropTypes.bool,
sqlLabMode: PropTypes.bool,
onChange: PropTypes.func,
clearable: PropTypes.bool,
@@ -52,7 +51,6 @@ const defaultProps = {
onTableChange: () => {},
onChange: () => {},
tableNameSticky: true,
- horizontal: false,
sqlLabMode: true,
clearable: true,
};
@@ -199,10 +197,10 @@ export default class TableSelector extends
React.PureComponent {
}
renderSelectRow(select, refreshBtn) {
return (
- <Row>
- <Col md={11}>{select}</Col>
- <Col md={1} className="refresh-col">{refreshBtn}</Col>
- </Row>
+ <div className="section">
+ <span className="select">{select}</span>
+ <span className="refresh-col">{refreshBtn}</span>
+ </div>
);
}
renderDatabaseSelect() {
@@ -232,29 +230,25 @@ export default class TableSelector extends
React.PureComponent {
/>);
}
renderSchema() {
- return (
- <div className="m-t-5">
- {this.renderSelectRow(
- <Select
- name="select-schema"
- placeholder={t('Select a schema (%s)',
this.state.schemaOptions.length)}
- options={this.state.schemaOptions}
- value={this.props.schema}
- valueRenderer={o => (
- <div>
- <span className="text-muted">{t('Schema:')}</span> {o.label}
- </div>
- )}
- isLoading={this.state.schemaLoading}
- autosize={false}
- onChange={this.changeSchema}
- />,
- <RefreshLabel
- onClick={() => this.onDatabaseChange({ id: this.props.dbId },
true)}
- tooltipContent={t('Force refresh schema list')}
- />,
+ return this.renderSelectRow(
+ <Select
+ name="select-schema"
+ placeholder={t('Select a schema (%s)',
this.state.schemaOptions.length)}
+ options={this.state.schemaOptions}
+ value={this.props.schema}
+ valueRenderer={o => (
+ <div>
+ <span className="text-muted">{t('Schema:')}</span> {o.label}
+ </div>
)}
- </div>
+ isLoading={this.state.schemaLoading}
+ autosize={false}
+ onChange={this.changeSchema}
+ />,
+ <RefreshLabel
+ onClick={() => this.onDatabaseChange({ id: this.props.dbId }, true)}
+ tooltipContent={t('Force refresh schema list')}
+ />,
);
}
renderTable() {
@@ -290,20 +284,16 @@ export default class TableSelector extends
React.PureComponent {
value={this.state.tableName}
loadOptions={this.getTableNamesBySubStr}
/>);
- return (
- <div className="m-t-5">
- {this.renderSelectRow(
- select,
- <RefreshLabel
- onClick={() => this.changeSchema({ value: this.props.schema },
true)}
- tooltipContent={t('Force refresh table list')}
- />)}
- </div>);
+ return this.renderSelectRow(
+ select,
+ <RefreshLabel
+ onClick={() => this.changeSchema({ value: this.props.schema }, true)}
+ tooltipContent={t('Force refresh table list')}
+ />);
}
renderSeeTableLabel() {
return (
- <div>
- <hr />
+ <div className="section">
<ControlLabel>
{t('See table schema')}{' '}
<small>
@@ -319,18 +309,11 @@ export default class TableSelector extends
React.PureComponent {
render() {
return (
<div className="TableSelector">
- {this.props.horizontal ?
- <div>
- <Col md={4}>{this.renderDatabaseSelect()}</Col>
- <Col md={4}>{this.renderSchema()}</Col>
- <Col md={4}>{this.renderTable()}</Col>
- </div> :
- <div>
- <div>{this.renderDatabaseSelect()}</div>
- <div className="m-t-5">{this.renderSchema()}</div>
- {this.props.sqlLabMode && this.renderSeeTableLabel()}
- <div className="m-t-5">{this.renderTable()}</div>
- </div>}
+ {this.renderDatabaseSelect()}
+ {this.renderSchema()}
+ <div className="divider" />
+ {this.props.sqlLabMode && this.renderSeeTableLabel()}
+ {this.renderTable()}
</div>
);
}