mirror of
https://github.com/apache/superset.git
synced 2026-04-22 01:24:43 +00:00
[sqllab] some frontend tests (#1400)
* [sqllab] some frontend tests * linting * Addressing comments * Addressing unaddressed comments * Touchups
This commit is contained in:
committed by
GitHub
parent
7c5933732b
commit
940659bc14
@@ -1,8 +1,5 @@
|
||||
import React from 'react';
|
||||
import { Alert } from 'react-bootstrap';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as Actions from '../actions';
|
||||
|
||||
class Alerts extends React.Component {
|
||||
removeAlert(alert) {
|
||||
@@ -11,6 +8,7 @@ class Alerts extends React.Component {
|
||||
render() {
|
||||
const alerts = this.props.alerts.map((alert) =>
|
||||
<Alert
|
||||
key={alert.id}
|
||||
bsStyle={alert.bsStyle}
|
||||
style={{ width: '500px', textAlign: 'midddle', margin: '10px auto' }}
|
||||
>
|
||||
@@ -33,9 +31,4 @@ Alerts.propTypes = {
|
||||
actions: React.PropTypes.object,
|
||||
};
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
export default connect(null, mapDispatchToProps)(Alerts);
|
||||
export default Alerts;
|
||||
|
||||
@@ -48,7 +48,7 @@ class App extends React.Component {
|
||||
}
|
||||
return (
|
||||
<div className="App SqlLab">
|
||||
<Alerts alerts={this.props.alerts} />
|
||||
<Alerts alerts={this.props.alerts} actions={this.props.actions} />
|
||||
<DataPreviewModal />
|
||||
<div className="container-fluid">
|
||||
{content}
|
||||
@@ -60,6 +60,7 @@ class App extends React.Component {
|
||||
|
||||
App.propTypes = {
|
||||
alerts: React.PropTypes.array,
|
||||
actions: React.PropTypes.object,
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
@@ -73,4 +74,5 @@ function mapDispatchToProps(dispatch) {
|
||||
};
|
||||
}
|
||||
|
||||
export { App };
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import React from 'react';
|
||||
import { Button, OverlayTrigger, Tooltip } from 'react-bootstrap';
|
||||
|
||||
const ButtonWithTooltip = (props) => {
|
||||
let tooltip = (
|
||||
<Tooltip id="tooltip">
|
||||
{props.tooltip}
|
||||
</Tooltip>
|
||||
);
|
||||
return (
|
||||
<OverlayTrigger
|
||||
overlay={tooltip}
|
||||
delayShow={300}
|
||||
placement={props.placement}
|
||||
delayHide={150}
|
||||
>
|
||||
<Button
|
||||
onClick={props.onClick}
|
||||
bsStyle={props.bsStyle}
|
||||
bsSize={props.bsSize}
|
||||
disabled={props.disabled}
|
||||
className={props.className}
|
||||
>
|
||||
{props.children}
|
||||
</Button>
|
||||
</OverlayTrigger>
|
||||
);
|
||||
};
|
||||
|
||||
ButtonWithTooltip.defaultProps = {
|
||||
onClick: () => {},
|
||||
disabled: false,
|
||||
placement: 'top',
|
||||
bsStyle: 'default',
|
||||
};
|
||||
|
||||
ButtonWithTooltip.propTypes = {
|
||||
bsSize: React.PropTypes.string,
|
||||
bsStyle: React.PropTypes.string,
|
||||
children: React.PropTypes.element,
|
||||
className: React.PropTypes.string,
|
||||
disabled: React.PropTypes.bool,
|
||||
onClick: React.PropTypes.func,
|
||||
placement: React.PropTypes.string,
|
||||
tooltip: React.PropTypes.string,
|
||||
};
|
||||
|
||||
export default ButtonWithTooltip;
|
||||
@@ -3,11 +3,11 @@ import CopyToClipboard from '../../components/CopyToClipboard';
|
||||
import { getShortUrl } from '../../../utils/common';
|
||||
|
||||
const propTypes = {
|
||||
qe: React.PropTypes.object,
|
||||
queryEditor: React.PropTypes.object,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
qe: null,
|
||||
queryEditor: null,
|
||||
};
|
||||
|
||||
export default class CopyQueryTabUrl extends React.Component {
|
||||
@@ -20,7 +20,7 @@ export default class CopyQueryTabUrl extends React.Component {
|
||||
|
||||
componentWillMount() {
|
||||
const params = [];
|
||||
const qe = this.props.qe;
|
||||
const qe = this.props.queryEditor;
|
||||
if (qe.dbId) params.push('dbid=' + qe.dbId);
|
||||
if (qe.title) params.push('title=' + encodeURIComponent(qe.title));
|
||||
if (qe.schema) params.push('schema=' + encodeURIComponent(qe.schema));
|
||||
|
||||
@@ -32,7 +32,7 @@ class DataPreviewModal extends React.Component {
|
||||
</Modal.Title>
|
||||
</Modal.Header>
|
||||
<Modal.Body>
|
||||
<ResultSet query={query} visualize={false} csv={false} />
|
||||
<ResultSet query={query} visualize={false} csv={false} actions={this.props.actions} />
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
const $ = window.$ = require('jquery');
|
||||
import React from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import Select from 'react-select';
|
||||
import { connect } from 'react-redux';
|
||||
import * as Actions from '../actions';
|
||||
|
||||
class DatabaseSelect extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -53,15 +50,4 @@ DatabaseSelect.propTypes = {
|
||||
valueRenderer: React.PropTypes.func,
|
||||
};
|
||||
|
||||
DatabaseSelect.defaultProps = {
|
||||
onChange: () => {},
|
||||
databaseId: null,
|
||||
};
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(DatabaseSelect);
|
||||
export default DatabaseSelect;
|
||||
|
||||
@@ -1,6 +1,24 @@
|
||||
import React from 'react';
|
||||
import { OverlayTrigger, Tooltip } from 'react-bootstrap';
|
||||
|
||||
const propTypes = {
|
||||
children: React.PropTypes.node,
|
||||
className: React.PropTypes.string,
|
||||
href: React.PropTypes.string,
|
||||
onClick: React.PropTypes.func,
|
||||
placement: React.PropTypes.string,
|
||||
style: React.PropTypes.object,
|
||||
tooltip: React.PropTypes.string,
|
||||
};
|
||||
const defaultProps = {
|
||||
className: '',
|
||||
href: '#',
|
||||
onClick: () => {},
|
||||
placement: 'top',
|
||||
style: {},
|
||||
tooltip: null,
|
||||
};
|
||||
|
||||
|
||||
class Link extends React.Component {
|
||||
render() {
|
||||
@@ -34,21 +52,7 @@ class Link extends React.Component {
|
||||
return link;
|
||||
}
|
||||
}
|
||||
Link.propTypes = {
|
||||
children: React.PropTypes.object,
|
||||
className: React.PropTypes.string,
|
||||
href: React.PropTypes.string,
|
||||
onClick: React.PropTypes.func,
|
||||
placement: React.PropTypes.string,
|
||||
style: React.PropTypes.object,
|
||||
tooltip: React.PropTypes.string,
|
||||
};
|
||||
Link.defaultProps = {
|
||||
disabled: false,
|
||||
href: '#',
|
||||
tooltip: null,
|
||||
placement: 'top',
|
||||
onClick: () => {},
|
||||
};
|
||||
Link.propTypes = propTypes;
|
||||
Link.defaultProps = defaultProps;
|
||||
|
||||
export default Link;
|
||||
|
||||
@@ -30,14 +30,10 @@ class QueryAutoRefresh extends React.Component {
|
||||
if (Object.keys(data).length > 0) {
|
||||
this.props.actions.refreshQueries(data);
|
||||
}
|
||||
if (!this.props.networkOn) {
|
||||
this.props.actions.setNetworkStatus(true);
|
||||
}
|
||||
this.props.actions.setNetworkStatus(true);
|
||||
})
|
||||
.fail(() => {
|
||||
if (this.props.networkOn) {
|
||||
this.props.actions.setNetworkStatus(false);
|
||||
}
|
||||
this.props.actions.setNetworkStatus(false);
|
||||
});
|
||||
}
|
||||
render() {
|
||||
@@ -47,7 +43,6 @@ class QueryAutoRefresh extends React.Component {
|
||||
QueryAutoRefresh.propTypes = {
|
||||
actions: React.PropTypes.object,
|
||||
queriesLastUpdate: React.PropTypes.number,
|
||||
networkOn: React.PropTypes.bool,
|
||||
};
|
||||
QueryAutoRefresh.defaultProps = {
|
||||
// queries: null,
|
||||
@@ -56,7 +51,6 @@ QueryAutoRefresh.defaultProps = {
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
queriesLastUpdate: state.queriesLastUpdate,
|
||||
networkOn: state.networkOn,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,28 +1,23 @@
|
||||
import React from 'react';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as Actions from '../actions';
|
||||
|
||||
import QueryTable from './QueryTable';
|
||||
import { Alert } from 'react-bootstrap';
|
||||
|
||||
const propTypes = {
|
||||
queries: React.PropTypes.array.isRequired,
|
||||
actions: React.PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const QueryHistory = (props) => {
|
||||
const activeQeId = props.tabHistory[props.tabHistory.length - 1];
|
||||
const queriesArray = [];
|
||||
for (const id in props.queries) {
|
||||
if (props.queries[id].sqlEditorId === activeQeId) {
|
||||
queriesArray.push(props.queries[id]);
|
||||
}
|
||||
}
|
||||
if (queriesArray.length > 0) {
|
||||
if (props.queries.length > 0) {
|
||||
return (
|
||||
<QueryTable
|
||||
columns={[
|
||||
'state', 'started', 'duration', 'progress',
|
||||
'rows', 'sql', 'output', 'actions',
|
||||
]}
|
||||
queries={queriesArray}
|
||||
queries={props.queries}
|
||||
actions={props.actions}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -32,27 +27,6 @@ const QueryHistory = (props) => {
|
||||
</Alert>
|
||||
);
|
||||
};
|
||||
QueryHistory.propTypes = propTypes;
|
||||
|
||||
QueryHistory.defaultProps = {
|
||||
queries: {},
|
||||
};
|
||||
|
||||
QueryHistory.propTypes = {
|
||||
queries: React.PropTypes.object,
|
||||
tabHistory: React.PropTypes.array,
|
||||
actions: React.PropTypes.object,
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
queries: state.queries,
|
||||
tabHistory: state.tabHistory,
|
||||
};
|
||||
}
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(QueryHistory);
|
||||
export default QueryHistory;
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
import React from 'react';
|
||||
import Link from './Link';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as Actions from '../actions';
|
||||
import shortid from 'shortid';
|
||||
|
||||
class QueryLink extends React.Component {
|
||||
popTab() {
|
||||
const qe = {
|
||||
id: shortid.generate(),
|
||||
title: this.props.query.title,
|
||||
dbId: this.props.query.dbId,
|
||||
autorun: false,
|
||||
sql: this.props.query.sql,
|
||||
};
|
||||
this.props.actions.addQueryEditor(qe);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div className="clearfix">
|
||||
<div className="pull-left">
|
||||
<a
|
||||
href="#"
|
||||
tooltip="Pop this query in a new tab"
|
||||
onClick={this.popTab.bind(this)}
|
||||
>
|
||||
{this.props.query.title}
|
||||
</a>
|
||||
</div>
|
||||
<div className="pull-right">
|
||||
<Link
|
||||
onClick={this.props.actions.removeWorkspaceQuery.bind(this, this.props.query)}
|
||||
tooltip="Remove query from workspace"
|
||||
href="#"
|
||||
>
|
||||
×
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
QueryLink.propTypes = {
|
||||
query: React.PropTypes.object,
|
||||
actions: React.PropTypes.object,
|
||||
};
|
||||
|
||||
QueryLink.defaultProps = {
|
||||
};
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
export default connect(null, mapDispatchToProps)(QueryLink);
|
||||
|
||||
@@ -7,6 +7,10 @@ import QueryTable from './QueryTable';
|
||||
import DatabaseSelect from './DatabaseSelect';
|
||||
import { STATUS_OPTIONS } from '../common';
|
||||
|
||||
const propTypes = {
|
||||
actions: React.PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
class QuerySearch extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -132,11 +136,11 @@ class QuerySearch extends React.Component {
|
||||
onUserClicked={this.onUserClicked.bind(this)}
|
||||
onDbClicked={this.onDbClicked.bind(this)}
|
||||
queries={this.state.queriesArray}
|
||||
actions={this.props.actions}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QuerySearch.propTypes = propTypes;
|
||||
export default QuerySearch;
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as Actions from '../actions';
|
||||
|
||||
import moment from 'moment';
|
||||
import { Table } from 'reactable';
|
||||
import { Label, ProgressBar } from 'react-bootstrap';
|
||||
@@ -67,6 +63,9 @@ class QueryTable extends React.Component {
|
||||
clearQueryResults(query) {
|
||||
this.props.actions.clearQueryResults(query);
|
||||
}
|
||||
removeQuery(query) {
|
||||
this.props.actions.removeQuery(query);
|
||||
}
|
||||
|
||||
render() {
|
||||
const data = this.props.queries.map((query) => {
|
||||
@@ -111,7 +110,7 @@ class QueryTable extends React.Component {
|
||||
modalTitle={'Data preview'}
|
||||
beforeOpen={this.openAsyncResults.bind(this, query)}
|
||||
onExit={this.clearQueryResults.bind(this, query)}
|
||||
modalBody={<ResultSet showSql query={query} />}
|
||||
modalBody={<ResultSet showSql query={query} actions={this.props.actions} />}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
@@ -163,7 +162,7 @@ class QueryTable extends React.Component {
|
||||
<Link
|
||||
className="fa fa-trash m-r-3"
|
||||
tooltip="Remove query from log"
|
||||
onClick={this.props.actions.removeQuery.bind(this, query)}
|
||||
onClick={this.removeQuery.bind(this, query)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -198,13 +197,4 @@ class QueryTable extends React.Component {
|
||||
QueryTable.propTypes = propTypes;
|
||||
QueryTable.defaultProps = defaultProps;
|
||||
|
||||
function mapStateToProps() {
|
||||
return {};
|
||||
}
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
export { QueryTable };
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(QueryTable);
|
||||
export default QueryTable;
|
||||
|
||||
@@ -3,10 +3,6 @@ import { Alert, Button, ButtonGroup, ProgressBar } from 'react-bootstrap';
|
||||
import { Table } from 'reactable';
|
||||
import shortid from 'shortid';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as Actions from '../actions';
|
||||
|
||||
import VisualizeModal from './VisualizeModal';
|
||||
import HighlightedSql from './HighlightedSql';
|
||||
|
||||
@@ -116,7 +112,7 @@ class ResultSet extends React.Component {
|
||||
if (this.props.showSql) {
|
||||
sql = <HighlightedSql sql={query.sql} />;
|
||||
}
|
||||
if (['running', 'pending', 'fetching'].includes(query.state)) {
|
||||
if (['running', 'pending', 'fetching'].indexOf(query.state) > -1) {
|
||||
let progressBar;
|
||||
if (query.progress > 0 && query.state === 'running') {
|
||||
progressBar = (
|
||||
@@ -191,12 +187,4 @@ class ResultSet extends React.Component {
|
||||
ResultSet.propTypes = propTypes;
|
||||
ResultSet.defaultProps = defaultProps;
|
||||
|
||||
function mapStateToProps() {
|
||||
return {};
|
||||
}
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ResultSet);
|
||||
export default ResultSet;
|
||||
|
||||
@@ -3,16 +3,21 @@ import QueryHistory from './QueryHistory';
|
||||
import ResultSet from './ResultSet';
|
||||
import React from 'react';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as Actions from '../actions';
|
||||
import shortid from 'shortid';
|
||||
|
||||
const propTypes = {
|
||||
queries: React.PropTypes.array.isRequired,
|
||||
actions: React.PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const SouthPane = function (props) {
|
||||
let results = <div />;
|
||||
const latestQuery = props.latestQuery;
|
||||
let latestQuery;
|
||||
if (props.queries.length > 0) {
|
||||
latestQuery = props.queries[props.queries.length - 1];
|
||||
}
|
||||
let results;
|
||||
if (latestQuery) {
|
||||
results = <ResultSet showControls search query={latestQuery} />;
|
||||
results = <ResultSet showControls search query={latestQuery} actions={props.actions} />;
|
||||
} else {
|
||||
results = <Alert bsStyle="info">Run a query to display results here</Alert>;
|
||||
}
|
||||
@@ -25,24 +30,12 @@ const SouthPane = function (props) {
|
||||
</div>
|
||||
</Tab>
|
||||
<Tab title="Query History" eventKey={2}>
|
||||
<QueryHistory />
|
||||
<QueryHistory queries={props.queries} actions={props.actions} />
|
||||
</Tab>
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
SouthPane.propTypes = propTypes;
|
||||
|
||||
SouthPane.propTypes = {
|
||||
latestQuery: React.PropTypes.object,
|
||||
actions: React.PropTypes.object,
|
||||
};
|
||||
|
||||
SouthPane.defaultProps = {
|
||||
};
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
export default connect(null, mapDispatchToProps)(SouthPane);
|
||||
export default SouthPane;
|
||||
|
||||
@@ -18,16 +18,29 @@ import 'brace/mode/sql';
|
||||
import 'brace/theme/github';
|
||||
import 'brace/ext/language_tools';
|
||||
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import * as Actions from '../actions';
|
||||
|
||||
import shortid from 'shortid';
|
||||
import SouthPane from './SouthPane';
|
||||
import Timer from './Timer';
|
||||
|
||||
import SqlEditorLeftBar from './SqlEditorLeftBar';
|
||||
|
||||
const propTypes = {
|
||||
actions: React.PropTypes.object.isRequired,
|
||||
database: React.PropTypes.object,
|
||||
latestQuery: React.PropTypes.object,
|
||||
networkOn: React.PropTypes.bool,
|
||||
tables: React.PropTypes.array.isRequired,
|
||||
queries: React.PropTypes.array.isRequired,
|
||||
queryEditor: React.PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
networkOn: true,
|
||||
database: null,
|
||||
latestQuery: null,
|
||||
};
|
||||
|
||||
|
||||
class SqlEditor extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -72,15 +85,6 @@ class SqlEditor extends React.Component {
|
||||
this.setState({ sql: text });
|
||||
this.props.actions.queryEditorSetSql(this.props.queryEditor, text);
|
||||
}
|
||||
addWorkspaceQuery() {
|
||||
this.props.actions.addWorkspaceQuery({
|
||||
id: shortid.generate(),
|
||||
sql: this.state.sql,
|
||||
dbId: this.props.queryEditor.dbId,
|
||||
schema: this.props.queryEditor.schema,
|
||||
title: this.props.queryEditor.title,
|
||||
});
|
||||
}
|
||||
ctasChange() {}
|
||||
visualize() {}
|
||||
ctasChanged(event) {
|
||||
@@ -130,7 +134,9 @@ class SqlEditor extends React.Component {
|
||||
{runButtons}
|
||||
</ButtonGroup>
|
||||
);
|
||||
if (this.props.latestQuery && ['running', 'pending'].includes(this.props.latestQuery.state)) {
|
||||
if (
|
||||
this.props.latestQuery &&
|
||||
['running', 'pending'].indexOf(this.props.latestQuery.state) > -1) {
|
||||
runButtons = (
|
||||
<ButtonGroup bsSize="small" className="inline m-r-5 pull-left">
|
||||
<Button
|
||||
@@ -202,7 +208,12 @@ class SqlEditor extends React.Component {
|
||||
<div className="SqlEditor" style={{ minHeight: this.sqlEditorHeight() }}>
|
||||
<Row>
|
||||
<Col md={3}>
|
||||
<SqlEditorLeftBar queryEditor={this.props.queryEditor} />
|
||||
<SqlEditorLeftBar
|
||||
queryEditor={this.props.queryEditor}
|
||||
tables={this.props.tables}
|
||||
networkOn={this.props.networkOn}
|
||||
actions={this.props.actions}
|
||||
/>
|
||||
</Col>
|
||||
<Col md={9}>
|
||||
<AceEditor
|
||||
@@ -220,32 +231,17 @@ class SqlEditor extends React.Component {
|
||||
/>
|
||||
{editorBottomBar}
|
||||
<br />
|
||||
<SouthPane latestQuery={this.props.latestQuery} sqlEditor={this} />
|
||||
<SouthPane
|
||||
queries={this.props.queries}
|
||||
actions={this.props.actions}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
SqlEditor.defaultProps = defaultProps;
|
||||
SqlEditor.propTypes = propTypes;
|
||||
|
||||
SqlEditor.propTypes = {
|
||||
actions: React.PropTypes.object,
|
||||
database: React.PropTypes.object,
|
||||
latestQuery: React.PropTypes.object,
|
||||
queryEditor: React.PropTypes.object,
|
||||
};
|
||||
|
||||
SqlEditor.defaultProps = {
|
||||
};
|
||||
|
||||
function mapStateToProps() {
|
||||
return {};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SqlEditor);
|
||||
export default SqlEditor;
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
const $ = window.$ = require('jquery');
|
||||
import React from 'react';
|
||||
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import * as Actions from '../actions';
|
||||
import Select from 'react-select';
|
||||
import { Label, Button } from 'react-bootstrap';
|
||||
import TableElement from './TableElement';
|
||||
import DatabaseSelect from './DatabaseSelect';
|
||||
|
||||
const propTypes = {
|
||||
queryEditor: React.PropTypes.object.isRequired,
|
||||
tables: React.PropTypes.array,
|
||||
actions: React.PropTypes.object,
|
||||
networkOn: React.PropTypes.bool,
|
||||
};
|
||||
|
||||
const defaultProps = {
|
||||
tables: [],
|
||||
networkOn: true,
|
||||
actions: {},
|
||||
};
|
||||
|
||||
class SqlEditorLeftBar extends React.Component {
|
||||
constructor(props) {
|
||||
@@ -115,7 +124,6 @@ class SqlEditorLeftBar extends React.Component {
|
||||
if (!this.props.networkOn) {
|
||||
networkAlert = <p><Label bsStyle="danger">OFFLINE</Label></p>;
|
||||
}
|
||||
const tables = this.props.tables.filter((t) => (t.queryEditorId === this.props.queryEditor.id));
|
||||
const shouldShowReset = window.location.search === '?reset=1';
|
||||
return (
|
||||
<div className="clearfix sql-toolbar">
|
||||
@@ -124,6 +132,7 @@ class SqlEditorLeftBar extends React.Component {
|
||||
<DatabaseSelect
|
||||
onChange={this.onChange.bind(this)}
|
||||
databaseId={this.props.queryEditor.dbId}
|
||||
actions={this.props.actions}
|
||||
valueRenderer={(o) => (
|
||||
<div>
|
||||
<span className="text-muted">Database:</span> {o.label}
|
||||
@@ -161,8 +170,13 @@ class SqlEditorLeftBar extends React.Component {
|
||||
</div>
|
||||
<hr />
|
||||
<div className="m-t-5">
|
||||
{tables.map((table) => (
|
||||
<TableElement table={table} queryEditor={this.props.queryEditor} key={table.id} />
|
||||
{this.props.tables.map((table) => (
|
||||
<TableElement
|
||||
table={table}
|
||||
queryEditor={this.props.queryEditor}
|
||||
key={table.id}
|
||||
actions={this.props.actions}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{shouldShowReset &&
|
||||
@@ -174,29 +188,7 @@ class SqlEditorLeftBar extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
SqlEditorLeftBar.propTypes = propTypes;
|
||||
SqlEditorLeftBar.defaultProps = defaultProps;
|
||||
|
||||
SqlEditorLeftBar.propTypes = {
|
||||
queryEditor: React.PropTypes.object,
|
||||
tables: React.PropTypes.array,
|
||||
actions: React.PropTypes.object,
|
||||
networkOn: React.PropTypes.bool,
|
||||
};
|
||||
|
||||
SqlEditorLeftBar.defaultProps = {
|
||||
tables: [],
|
||||
};
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
tables: state.tables,
|
||||
networkOn: state.networkOn,
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SqlEditorLeftBar);
|
||||
export default SqlEditorLeftBar;
|
||||
|
||||
@@ -4,20 +4,21 @@ import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as Actions from '../actions';
|
||||
import SqlEditor from './SqlEditor';
|
||||
import shortid from 'shortid';
|
||||
import { getParamFromQuery } from '../../../utils/common';
|
||||
import CopyQueryTabUrl from './CopyQueryTabUrl';
|
||||
|
||||
const propTypes = {
|
||||
actions: React.PropTypes.object,
|
||||
databases: React.PropTypes.object,
|
||||
queries: React.PropTypes.object,
|
||||
actions: React.PropTypes.object.isRequired,
|
||||
databases: React.PropTypes.object.isRequired,
|
||||
queries: React.PropTypes.object.isRequired,
|
||||
queryEditors: React.PropTypes.array,
|
||||
tabHistory: React.PropTypes.array,
|
||||
tabHistory: React.PropTypes.array.isRequired,
|
||||
tables: React.PropTypes.array.isRequired,
|
||||
networkOn: React.PropTypes.bool,
|
||||
};
|
||||
const defaultProps = {
|
||||
tabHistory: [],
|
||||
queryEditors: [],
|
||||
networkOn: true,
|
||||
};
|
||||
|
||||
let queryCount = 1;
|
||||
@@ -39,7 +40,6 @@ class TabbedSqlEditors extends React.Component {
|
||||
if (this.state.query) {
|
||||
queryCount++;
|
||||
const queryEditorProps = {
|
||||
id: shortid.generate(),
|
||||
title: getParamFromQuery(this.state.query, 'title'),
|
||||
dbId: parseInt(getParamFromQuery(this.state.query, 'dbid'), 10),
|
||||
schema: getParamFromQuery(this.state.query, 'schema'),
|
||||
@@ -72,7 +72,6 @@ class TabbedSqlEditors extends React.Component {
|
||||
queryCount++;
|
||||
const activeQueryEditor = this.activeQueryEditor();
|
||||
const qe = {
|
||||
id: shortid.generate(),
|
||||
title: `Untitled Query ${queryCount}`,
|
||||
dbId: (activeQueryEditor) ? activeQueryEditor.dbId : null,
|
||||
schema: (activeQueryEditor) ? activeQueryEditor.schema : null,
|
||||
@@ -88,10 +87,26 @@ class TabbedSqlEditors extends React.Component {
|
||||
this.props.actions.setActiveQueryEditor({ id: key });
|
||||
}
|
||||
}
|
||||
removeQueryEditor(qe) {
|
||||
this.props.actions.removeQueryEditor(qe);
|
||||
}
|
||||
render() {
|
||||
const editors = this.props.queryEditors.map((qe, i) => {
|
||||
let latestQuery = this.props.queries[qe.latestQueryId];
|
||||
const database = this.props.databases[qe.dbId];
|
||||
const isSelected = (qe.id === this.activeQueryEditor().id);
|
||||
const queriesArray = [];
|
||||
for (const id in this.props.queries) {
|
||||
if (this.props.queries[id].sqlEditorId === qe.id) {
|
||||
queriesArray.push(this.props.queries[id]);
|
||||
}
|
||||
}
|
||||
let latestQuery;
|
||||
if (qe.latestQueryId) {
|
||||
latestQuery = this.props.queries[qe.latestQueryId];
|
||||
}
|
||||
let database;
|
||||
if (qe.dbId) {
|
||||
database = this.props.databases[qe.dbId];
|
||||
}
|
||||
const state = (latestQuery) ? latestQuery.state : '';
|
||||
const tabTitle = (
|
||||
<div>
|
||||
@@ -101,14 +116,14 @@ class TabbedSqlEditors extends React.Component {
|
||||
id={'ddbtn-tab-' + i}
|
||||
title=""
|
||||
>
|
||||
<MenuItem eventKey="1" onClick={this.props.actions.removeQueryEditor.bind(this, qe)}>
|
||||
<MenuItem eventKey="1" onClick={this.removeQueryEditor.bind(this, qe)}>
|
||||
<i className="fa fa-close" /> close tab
|
||||
</MenuItem>
|
||||
<MenuItem eventKey="2" onClick={this.renameTab.bind(this, qe)}>
|
||||
<i className="fa fa-i-cursor" /> rename tab
|
||||
</MenuItem>
|
||||
<MenuItem eventKey="3">
|
||||
<i className="fa fa-clipboard" /> <CopyQueryTabUrl qe={qe} />
|
||||
<i className="fa fa-clipboard" /> <CopyQueryTabUrl queryEditor={qe} />
|
||||
</MenuItem>
|
||||
</DropdownButton>
|
||||
</div>
|
||||
@@ -121,11 +136,17 @@ class TabbedSqlEditors extends React.Component {
|
||||
>
|
||||
<div className="panel panel-default">
|
||||
<div className="panel-body">
|
||||
<SqlEditor
|
||||
queryEditor={qe}
|
||||
latestQuery={latestQuery}
|
||||
database={database}
|
||||
/>
|
||||
{isSelected &&
|
||||
<SqlEditor
|
||||
tables={this.props.tables.filter((t) => (t.queryEditorId === qe.id))}
|
||||
queryEditor={qe}
|
||||
queries={queriesArray}
|
||||
latestQuery={latestQuery}
|
||||
database={database}
|
||||
actions={this.props.actions}
|
||||
networkOn={this.props.networkOn}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</Tab>);
|
||||
@@ -138,7 +159,13 @@ class TabbedSqlEditors extends React.Component {
|
||||
id="a11y-query-editor-tabs"
|
||||
>
|
||||
{editors}
|
||||
<Tab title={<div><i className="fa fa-plus-circle" /> </div>} eventKey="add_tab" />
|
||||
<Tab
|
||||
title={
|
||||
<div>
|
||||
<i className="fa fa-plus-circle" />
|
||||
</div>}
|
||||
eventKey="add_tab"
|
||||
/>
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
@@ -152,6 +179,8 @@ function mapStateToProps(state) {
|
||||
queryEditors: state.queryEditors,
|
||||
queries: state.queries,
|
||||
tabHistory: state.tabHistory,
|
||||
networkOn: state.networkOn,
|
||||
tables: state.tables,
|
||||
};
|
||||
}
|
||||
function mapDispatchToProps(dispatch) {
|
||||
@@ -160,4 +189,5 @@ function mapDispatchToProps(dispatch) {
|
||||
};
|
||||
}
|
||||
|
||||
export { TabbedSqlEditors };
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TabbedSqlEditors);
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as Actions from '../actions';
|
||||
|
||||
import { ButtonGroup, Well } from 'react-bootstrap';
|
||||
import shortid from 'shortid';
|
||||
@@ -187,7 +184,7 @@ class TableElement extends React.Component {
|
||||
<Link
|
||||
className="fa fa-trash pull-left m-l-2"
|
||||
onClick={this.removeTable.bind(this)}
|
||||
tooltip="Remove from workspace"
|
||||
tooltip="Remove from panel"
|
||||
href="#"
|
||||
/>
|
||||
</ButtonGroup>
|
||||
@@ -203,10 +200,4 @@ class TableElement extends React.Component {
|
||||
TableElement.propTypes = propTypes;
|
||||
TableElement.defaultProps = defaultProps;
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
export default connect(null, mapDispatchToProps)(TableElement);
|
||||
export { TableElement };
|
||||
export default TableElement;
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import React from 'react';
|
||||
import { BootstrapTable, TableHeaderColumn } from 'react-bootstrap-table';
|
||||
|
||||
const TableMetadata = function (props) {
|
||||
return (
|
||||
<BootstrapTable
|
||||
condensed
|
||||
data={props.table.columns}
|
||||
>
|
||||
<TableHeaderColumn dataField="id" isKey hidden>
|
||||
id
|
||||
</TableHeaderColumn>
|
||||
<TableHeaderColumn dataField="name">Name</TableHeaderColumn>
|
||||
<TableHeaderColumn dataField="type">Type</TableHeaderColumn>
|
||||
</BootstrapTable>
|
||||
);
|
||||
};
|
||||
|
||||
TableMetadata.propTypes = {
|
||||
table: React.PropTypes.object,
|
||||
};
|
||||
|
||||
export default TableMetadata;
|
||||
@@ -1,10 +1,6 @@
|
||||
import React from 'react';
|
||||
import { Alert, Button, Col, Modal } from 'react-bootstrap';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import * as Actions from '../actions';
|
||||
|
||||
import Select from 'react-select';
|
||||
import { Table } from 'reactable';
|
||||
import shortid from 'shortid';
|
||||
@@ -16,6 +12,17 @@ const CHART_TYPES = [
|
||||
{ value: 'bar', label: 'Time Series - Bar Chart', requiresTime: true },
|
||||
];
|
||||
|
||||
const propTypes = {
|
||||
onHide: React.PropTypes.func,
|
||||
query: React.PropTypes.object,
|
||||
show: React.PropTypes.bool,
|
||||
};
|
||||
const defaultProps = {
|
||||
show: false,
|
||||
query: {},
|
||||
onHide: () => {},
|
||||
};
|
||||
|
||||
class VisualizeModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@@ -34,7 +41,10 @@ class VisualizeModal extends React.Component {
|
||||
this.validate();
|
||||
}
|
||||
setStateFromProps() {
|
||||
if (!this.props.query || !this.props.query.results.columns) {
|
||||
if (
|
||||
!this.props.query ||
|
||||
!this.props.query.results ||
|
||||
!this.props.query.results.columns) {
|
||||
return;
|
||||
}
|
||||
const columns = {};
|
||||
@@ -204,22 +214,7 @@ class VisualizeModal extends React.Component {
|
||||
return modal;
|
||||
}
|
||||
}
|
||||
VisualizeModal.propTypes = {
|
||||
query: React.PropTypes.object,
|
||||
show: React.PropTypes.bool,
|
||||
onHide: React.PropTypes.func,
|
||||
};
|
||||
VisualizeModal.defaultProps = {
|
||||
show: false,
|
||||
onHide: () => {},
|
||||
};
|
||||
VisualizeModal.propTypes = propTypes;
|
||||
VisualizeModal.defaultProps = defaultProps;
|
||||
|
||||
function mapStateToProps() {
|
||||
return {};
|
||||
}
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators(Actions, dispatch),
|
||||
};
|
||||
}
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(VisualizeModal);
|
||||
export default VisualizeModal;
|
||||
|
||||
Reference in New Issue
Block a user