[SQL Lab] moving the db/schema/table select to the left (#1038)

This commit is contained in:
Maxime Beauchemin 2016-08-30 11:08:41 -07:00 committed by GitHub
parent fc1e63761c
commit 561828c2f8
10 changed files with 98 additions and 152 deletions

View File

@ -5,8 +5,6 @@ import { bindActionCreators } from 'redux';
import * as Actions from '../actions'; import * as Actions from '../actions';
import QueryLink from './QueryLink'; import QueryLink from './QueryLink';
import 'react-select/dist/react-select.css';
const LeftPane = (props) => { const LeftPane = (props) => {
let queryElements; let queryElements;
if (props.workspaceQueries.length > 0) { if (props.workspaceQueries.length > 0) {

View File

@ -5,9 +5,6 @@ import { bindActionCreators } from 'redux';
import * as Actions from '../actions'; import * as Actions from '../actions';
import shortid from 'shortid'; import shortid from 'shortid';
// CSS
import 'react-select/dist/react-select.css';
class QueryLink extends React.Component { class QueryLink extends React.Component {
popTab() { popTab() {
const qe = { const qe = {

View File

@ -1,4 +1,4 @@
import { Alert, Panel, Tab, Tabs } from 'react-bootstrap'; import { Alert, Tab, Tabs } from 'react-bootstrap';
import QueryHistory from './QueryHistory'; import QueryHistory from './QueryHistory';
import ResultSet from './ResultSet'; import ResultSet from './ResultSet';
import React from 'react'; import React from 'react';
@ -21,16 +21,12 @@ const SouthPane = function (props) {
return ( return (
<Tabs bsStyle="tabs"> <Tabs bsStyle="tabs">
<Tab title="Results" eventKey={1}> <Tab title="Results" eventKey={1}>
<Panel> <div style={{ overflow: 'auto' }}>
<div style={{ overflow: 'auto' }}> {results}
{results} </div>
</div>
</Panel>
</Tab> </Tab>
<Tab title="Query History" eventKey={2}> <Tab title="Query History" eventKey={2}>
<Panel> <QueryHistory />
<QueryHistory />
</Panel>
</Tab> </Tab>
</Tabs> </Tabs>
); );

View File

@ -4,6 +4,7 @@ import React from 'react';
import { import {
Button, Button,
ButtonGroup, ButtonGroup,
Col,
FormGroup, FormGroup,
InputGroup, InputGroup,
Form, Form,
@ -12,6 +13,7 @@ import {
Label, Label,
MenuItem, MenuItem,
OverlayTrigger, OverlayTrigger,
Row,
Tooltip, Tooltip,
} from 'react-bootstrap'; } from 'react-bootstrap';
@ -29,10 +31,7 @@ import ButtonWithTooltip from './ButtonWithTooltip';
import SouthPane from './SouthPane'; import SouthPane from './SouthPane';
import Timer from './Timer'; import Timer from './Timer';
import SqlEditorTopToolbar from './SqlEditorTopToolbar'; import SqlEditorLeft from './SqlEditorLeft';
// CSS
import 'react-select/dist/react-select.css';
class SqlEditor extends React.Component { class SqlEditor extends React.Component {
constructor(props) { constructor(props) {
@ -246,23 +245,29 @@ class SqlEditor extends React.Component {
<div className="SqlEditor"> <div className="SqlEditor">
<div> <div>
<div> <div>
<SqlEditorTopToolbar queryEditor={this.props.queryEditor} /> <Row>
<AceEditor <Col md={3}>
mode="sql" <SqlEditorLeft queryEditor={this.props.queryEditor} />
name={this.props.queryEditor.id} </Col>
theme="github" <Col md={9}>
minLines={5} <AceEditor
maxLines={30} mode="sql"
onChange={this.textChange.bind(this)} name={this.props.queryEditor.id}
height="200px" theme="github"
width="100%" minLines={5}
editorProps={{ $blockScrolling: true }} maxLines={30}
enableBasicAutocompletion onChange={this.textChange.bind(this)}
value={this.props.queryEditor.sql} height="200px"
/> width="100%"
{editorBottomBar} editorProps={{ $blockScrolling: true }}
<br /> enableBasicAutocompletion
<SouthPane latestQuery={this.props.latestQuery} sqlEditor={this} /> value={this.props.queryEditor.sql}
/>
{editorBottomBar}
<br />
<SouthPane latestQuery={this.props.latestQuery} sqlEditor={this} />
</Col>
</Row>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,16 +1,13 @@
const $ = window.$ = require('jquery'); const $ = window.$ = require('jquery');
import React from 'react'; import React from 'react';
import { Label, OverlayTrigger, Popover } from 'react-bootstrap';
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import * as Actions from '../actions'; import * as Actions from '../actions';
import shortid from 'shortid'; import shortid from 'shortid';
import Select from 'react-select'; import Select from 'react-select';
import Link from './Link'; import TableElement from './TableElement';
// CSS
import 'react-select/dist/react-select.css';
class SqlEditorTopToolbar extends React.Component { class SqlEditorTopToolbar extends React.Component {
constructor(props) { constructor(props) {
@ -123,7 +120,6 @@ class SqlEditorTopToolbar extends React.Component {
schema: qe.schema, schema: qe.schema,
columns: data.columns, columns: data.columns,
expanded: true, expanded: true,
showPopup: true,
}); });
}) })
.fail(() => { .fail(() => {
@ -135,76 +131,9 @@ class SqlEditorTopToolbar extends React.Component {
} }
render() { render() {
const tables = this.props.tables.filter((t) => (t.queryEditorId === this.props.queryEditor.id)); const tables = this.props.tables.filter((t) => (t.queryEditorId === this.props.queryEditor.id));
const tablesEls = tables.map((table) => {
let cols = [];
if (table.columns) {
cols = table.columns.map((col) => (
<div className="clearfix">
<div className="pull-left m-r-10">{col.name}</div>
<div className="pull-right text-muted"> {col.type}</div>
</div>
));
}
const popoverId = 'tblPopover_' + table.name;
const popoverTop = (
<div className="clearfix">
<div className="pull-left">
<Link
className="fa fa-pencil"
onClick={this.selectStar.bind(this, table)}
tooltip="Overwrite text in editor with a query on this table"
placement="left"
href="#"
/>
<Link
className="fa fa-plus-circle"
onClick={this.popTab.bind(this, table)}
tooltip="Run query in a new tab"
placement="left"
href="#"
/>
</div>
<div className="pull-right">
<Link
className="fa fa-close"
onClick={this.closePopover.bind(this, popoverId)}
href="#"
/>
</div>
</div>
);
const popover = (
<Popover
id={popoverId}
className="tablePopover"
title={popoverTop}
>
{cols}
</Popover>
);
return (
<Label className="m-r-5 table-label" style={{ fontSize: '100%' }}>
<OverlayTrigger
trigger="click"
placement="bottom"
overlay={popover}
ref={popoverId}
>
<span className="m-r-5" style={{ cursor: 'pointer' }}>
{table.name}
</span>
</OverlayTrigger>
<i
className="fa fa-close"
style={{ cursor: 'pointer' }}
onClick={this.props.actions.removeTable.bind(this, table)}
/>
</Label>
);
});
return ( return (
<div className="clearfix sql-toolbar"> <div className="clearfix sql-toolbar">
<div className="pull-left m-r-5"> <div>
<Select <Select
name="select-db" name="select-db"
placeholder="[Database]" placeholder="[Database]"
@ -215,7 +144,7 @@ class SqlEditorTopToolbar extends React.Component {
onChange={this.changeDb.bind(this)} onChange={this.changeDb.bind(this)}
/> />
</div> </div>
<div className="pull-left m-r-5"> <div className="m-t-5">
<Select <Select
name="select-schema" name="select-schema"
placeholder="[Schema]" placeholder="[Schema]"
@ -226,7 +155,7 @@ class SqlEditorTopToolbar extends React.Component {
onChange={this.changeSchema.bind(this)} onChange={this.changeSchema.bind(this)}
/> />
</div> </div>
<div className="pull-left m-r-5"> <div className="m-t-5">
<Select <Select
name="select-table" name="select-table"
ref="selectTable" ref="selectTable"
@ -238,8 +167,9 @@ class SqlEditorTopToolbar extends React.Component {
options={this.state.tableOptions} options={this.state.tableOptions}
/> />
</div> </div>
<div className="pull-left m-r-5"> <hr />
{tablesEls} <div className="m-t-5">
{tables.map((table) => <TableElement table={table} />)}
</div> </div>
</div> </div>
); );

View File

@ -6,10 +6,7 @@ import { bindActionCreators } from 'redux';
import * as Actions from '../actions'; import * as Actions from '../actions';
import shortid from 'shortid'; import shortid from 'shortid';
// CSS class TableElement extends React.Component {
import 'react-select/dist/react-select.css';
class TableWorkspaceElement extends React.Component {
selectStar() { selectStar() {
let cols = ''; let cols = '';
this.props.table.columns.forEach((col, i) => { this.props.table.columns.forEach((col, i) => {
@ -31,35 +28,37 @@ class TableWorkspaceElement extends React.Component {
render() { render() {
let metadata = null; let metadata = null;
let buttonToggle; let buttonToggle;
if (!this.props.table.expanded) { if (this.props.table.expanded) {
buttonToggle = (
<Link
href="#"
onClick={this.props.actions.expandTable.bind(this, this.props.table)}
placement="right"
tooltip="Collapse the table's structure information"
>
<i className="fa fa-minus" /> {this.props.table.name}
</Link>
);
metadata = this.props.table.columns.map((col) =>
<div className="clearfix">
<span className="pull-left">{col.name}</span>
<span className="pull-right">{col.type}</span>
</div>
);
metadata = (
<div style={{ 'margin-bottom': '5px' }}>{metadata}</div>
);
} else {
buttonToggle = ( buttonToggle = (
<Link <Link
href="#" href="#"
onClick={this.props.actions.collapseTable.bind(this, this.props.table)} onClick={this.props.actions.collapseTable.bind(this, this.props.table)}
placement="right" placement="right"
tooltip="Collapse the table's structure information"
>
{this.props.table.name} <i className="fa fa-caret-up" />
</Link>
);
metadata = (
<div>
{this.props.table.columns.map((col) => (
<div className="clearfix">
<span className="pull-left m-l-5">{col.name}</span>
<span className="pull-right">{col.type}</span>
</div>
))}
<hr />
</div>
);
} else {
buttonToggle = (
<Link
href="#"
onClick={this.props.actions.expandTable.bind(this, this.props.table)}
placement="right"
tooltip="Expand the table's structure information" tooltip="Expand the table's structure information"
> >
<i className="fa fa-plus" /> {this.props.table.name} {this.props.table.name} <i className="fa fa-caret-down" />
</Link> </Link>
); );
} }
@ -68,13 +67,19 @@ class TableWorkspaceElement extends React.Component {
{buttonToggle} {buttonToggle}
<ButtonGroup className="ws-el-controls pull-right"> <ButtonGroup className="ws-el-controls pull-right">
<Link <Link
className="fa fa-play" className="fa fa-pencil m-l-2"
onClick={this.selectStar.bind(this)} onClick={this.selectStar.bind(this)}
tooltip="Run query in a new tab" tooltip="Run query in a new tab"
href="#" href="#"
/> />
<Link <Link
className="fa fa-trash" className="fa fa-plus-circle m-l-2"
onClick={this.selectStar.bind(this)}
tooltip="Run query in a new tab"
href="#"
/>
<Link
className="fa fa-trash m-l-2"
onClick={this.props.actions.removeTable.bind(this, this.props.table)} onClick={this.props.actions.removeTable.bind(this, this.props.table)}
tooltip="Remove from workspace" tooltip="Remove from workspace"
href="#" href="#"
@ -85,11 +90,11 @@ class TableWorkspaceElement extends React.Component {
); );
} }
} }
TableWorkspaceElement.propTypes = { TableElement.propTypes = {
table: React.PropTypes.object, table: React.PropTypes.object,
actions: React.PropTypes.object, actions: React.PropTypes.object,
}; };
TableWorkspaceElement.defaultProps = { TableElement.defaultProps = {
table: null, table: null,
}; };
@ -98,5 +103,4 @@ function mapDispatchToProps(dispatch) {
actions: bindActionCreators(Actions, dispatch), actions: bindActionCreators(Actions, dispatch),
}; };
} }
export default connect(null, mapDispatchToProps)(TableWorkspaceElement); export default connect(null, mapDispatchToProps)(TableElement);

View File

@ -6,7 +6,6 @@ import React from 'react';
import { render } from 'react-dom'; import { render } from 'react-dom';
import * as Actions from './actions'; import * as Actions from './actions';
import LeftPane from './components/LeftPane';
import TabbedSqlEditors from './components/TabbedSqlEditors'; import TabbedSqlEditors from './components/TabbedSqlEditors';
import QueryAutoRefresh from './components/QueryAutoRefresh'; import QueryAutoRefresh from './components/QueryAutoRefresh';
import Alerts from './components/Alerts'; import Alerts from './components/Alerts';
@ -37,12 +36,9 @@ const App = function (props) {
<QueryAutoRefresh /> <QueryAutoRefresh />
<Alerts alerts={props.alerts} /> <Alerts alerts={props.alerts} />
<div className="row"> <div className="row">
<div className="col-md-9"> <div className="col-md-12">
<TabbedSqlEditors /> <TabbedSqlEditors />
</div> </div>
<div className="col-md-3">
<LeftPane />
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -72,9 +72,18 @@ div.Workspace {
.m-l-1 { .m-l-1 {
margin-left: 1px; margin-left: 1px;
} }
.m-l-2 {
margin-left: 2px;
}
.m-r-10 { .m-r-10 {
margin-right: 10px; margin-right: 10px;
} }
.m-l-10 {
margin-left: 10px;
}
.m-l-5 {
margin-left: 5px;
}
.m-b-10 { .m-b-10 {
margin-bottom: 10px; margin-bottom: 10px;
} }
@ -132,7 +141,9 @@ div.Workspace {
max-height: 600px; max-height: 600px;
box-shadow: rgba(0, 0, 0, 0.8) 5px 5px 25px box-shadow: rgba(0, 0, 0, 0.8) 5px 5px 25px
} }
.SqlLab {
font-size: 12px;
}
.SqlLab pre { .SqlLab pre {
padding: 0px !important; padding: 0px !important;
margin: 0px; margin: 0px;
@ -217,7 +228,7 @@ div.tablePopover:hover {
.ace_editor { .ace_editor {
border: 1px solid #ccc; border: 1px solid #ccc;
margin: 10px 0; margin: 0px 0px 10px 0px;
} }
.Select-menu-outer { .Select-menu-outer {
@ -227,3 +238,11 @@ div.tablePopover:hover {
.ace_content { .ace_content {
background-color: #f4f4f4; background-color: #f4f4f4;
} }
.ws-el > .ws-el-controls {
opacity: 0;
transition: visibility 0s, opacity 0.3s linear;
}
.ws-el:hover > .ws-el-controls {
opacity: 1;
transition: visibility 0s, opacity 0.3s linear;
}

View File

@ -1 +1,2 @@
require('../stylesheets/less/index.less'); require('../stylesheets/less/index.less');
require('../stylesheets/react-select/select.less');

View File

@ -22,7 +22,7 @@
@select-input-border-radius: 4px; @select-input-border-radius: 4px;
@select-input-border-focus: @select-primary-color; @select-input-border-focus: @select-primary-color;
@select-input-border-width: 1px; @select-input-border-width: 1px;
@select-input-height: 36px; @select-input-height: 30px;
@select-input-internal-height: (@select-input-height - (@select-input-border-width * 2)); @select-input-internal-height: (@select-input-height - (@select-input-border-width * 2));
@select-input-placeholder: #aaa; @select-input-placeholder: #aaa;
@select-text-color: #333; @select-text-color: #333;