Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SQL Lab - A multi-tab SQL editor #514

Merged
merged 19 commits into from
Aug 30, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ dist
caravel.egg-info/
app.db
*.bak
.idea
*.sqllite

# Node.js, webpack artifacts
*.entry.js
Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ recursive-include caravel/static *
recursive-exclude caravel/static/assets/node_modules *
recursive-include caravel/static/assets/node_modules/font-awesome *
recursive-exclude caravel/static/docs *
recursive-exclude caravel/static/spec *
recursive-exclude tests *
recursive-include caravel/data *
recursive-include caravel/migrations *
2 changes: 1 addition & 1 deletion caravel/assets/.eslintignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
node_modules/*
vendor/*
javascripts/dist/*
dist/*
stylesheets/*
spec/*
19 changes: 19 additions & 0 deletions caravel/assets/javascripts/SqlLab/TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

# TODO
* Figure out how to organize the left panel, integrate Search
* collapse sql beyond 10 lines
* Security per-database (dropdown)
* Get a to work

## Cosmetic
* Result set font is too big
* lmiit/timer/buttons wrap
* table label is transparent
* SqlEditor buttons
* use react-bootstrap-prompt for query title input
* Make tabs look great

# PROJECT
* Write Runbook
* Confirm backups
* merge chef branch
116 changes: 116 additions & 0 deletions caravel/assets/javascripts/SqlLab/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
export const RESET_STATE = 'RESET_STATE';
export const ADD_QUERY_EDITOR = 'ADD_QUERY_EDITOR';
export const REMOVE_QUERY_EDITOR = 'REMOVE_QUERY_EDITOR';
export const ADD_TABLE = 'ADD_TABLE';
export const REMOVE_TABLE = 'REMOVE_TABLE';
export const START_QUERY = 'START_QUERY';
export const STOP_QUERY = 'STOP_QUERY';
export const END_QUERY = 'END_QUERY';
export const REMOVE_QUERY = 'REMOVE_QUERY';
export const EXPAND_TABLE = 'EXPAND_TABLE';
export const COLLAPSE_TABLE = 'COLLAPSE_TABLE';
export const QUERY_SUCCESS = 'QUERY_SUCCESS';
export const QUERY_FAILED = 'QUERY_FAILED';
export const QUERY_EDITOR_SETDB = 'QUERY_EDITOR_SETDB';
export const QUERY_EDITOR_SET_SCHEMA = 'QUERY_EDITOR_SET_SCHEMA';
export const QUERY_EDITOR_SET_TITLE = 'QUERY_EDITOR_SET_TITLE';
export const QUERY_EDITOR_SET_AUTORUN = 'QUERY_EDITOR_SET_AUTORUN';
export const QUERY_EDITOR_SET_SQL = 'QUERY_EDITOR_SET_SQL';
export const SET_WORKSPACE_DB = 'SET_WORKSPACE_DB';
export const ADD_WORKSPACE_QUERY = 'ADD_WORKSPACE_QUERY';
export const REMOVE_WORKSPACE_QUERY = 'REMOVE_WORKSPACE_QUERY';
export const SET_ACTIVE_QUERY_EDITOR = 'SET_ACTIVE_QUERY_EDITOR';
export const ADD_ALERT = 'ADD_ALERT';
export const REMOVE_ALERT = 'REMOVE_ALERT';
export const REFRESH_QUERIES = 'REFRESH_QUERIES';

export function resetState() {
return { type: RESET_STATE };
}

export function addQueryEditor(queryEditor) {
return { type: ADD_QUERY_EDITOR, queryEditor };
}

export function addAlert(alert) {
return { type: ADD_ALERT, alert };
}

export function removeAlert(alert) {
return { type: REMOVE_ALERT, alert };
}

export function setActiveQueryEditor(queryEditor) {
return { type: SET_ACTIVE_QUERY_EDITOR, queryEditor };
}

export function removeQueryEditor(queryEditor) {
return { type: REMOVE_QUERY_EDITOR, queryEditor };
}

export function removeQuery(query) {
return { type: REMOVE_QUERY, query };
}

export function queryEditorSetDb(queryEditor, dbId) {
return { type: QUERY_EDITOR_SETDB, queryEditor, dbId };
}

export function queryEditorSetSchema(queryEditor, schema) {
return { type: QUERY_EDITOR_SET_SCHEMA, queryEditor, schema };
}

export function queryEditorSetAutorun(queryEditor, autorun) {
return { type: QUERY_EDITOR_SET_AUTORUN, queryEditor, autorun };
}

export function queryEditorSetTitle(queryEditor, title) {
return { type: QUERY_EDITOR_SET_TITLE, queryEditor, title };
}

export function queryEditorSetSql(queryEditor, sql) {
return { type: QUERY_EDITOR_SET_SQL, queryEditor, sql };
}

export function addTable(table) {
return { type: ADD_TABLE, table };
}

export function expandTable(table) {
return { type: EXPAND_TABLE, table };
}

export function collapseTable(table) {
return { type: COLLAPSE_TABLE, table };
}

export function removeTable(table) {
return { type: REMOVE_TABLE, table };
}

export function startQuery(query) {
return { type: START_QUERY, query };
}

export function stopQuery(query) {
return { type: STOP_QUERY, query };
}

export function querySuccess(query, results) {
return { type: QUERY_SUCCESS, query, results };
}

export function queryFailed(query, msg) {
return { type: QUERY_FAILED, query, msg };
}

export function addWorkspaceQuery(query) {
return { type: ADD_WORKSPACE_QUERY, query };
}

export function removeWorkspaceQuery(query) {
return { type: REMOVE_WORKSPACE_QUERY, query };
}
export function refreshQueries(alteredQueries) {
return { type: REFRESH_QUERIES, alteredQueries };
}
6 changes: 6 additions & 0 deletions caravel/assets/javascripts/SqlLab/common.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const STATE_BSSTYLE_MAP = {
failed: 'danger',
pending: 'info',
running: 'warning',
success: 'success',
};
41 changes: 41 additions & 0 deletions caravel/assets/javascripts/SqlLab/components/Alerts.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
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) {
this.props.actions.removeAlert(alert);
}
render() {
const alerts = this.props.alerts.map((alert) =>
<Alert
bsStyle={alert.bsStyle}
style={{ width: '500px', textAlign: 'midddle', margin: '10px auto' }}
>
{alert.msg}
<i
className="fa fa-close pull-right"
onClick={this.removeAlert.bind(this, alert)}
style={{ cursor: 'pointer' }}
/>
</Alert>
);
return (
<div>{alerts}</div>
);
}
}

Alerts.propTypes = {
alerts: React.PropTypes.array,
actions: React.PropTypes.object,
};

function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Actions, dispatch),
};
}
export default connect(null, mapDispatchToProps)(Alerts);
48 changes: 48 additions & 0 deletions caravel/assets/javascripts/SqlLab/components/ButtonWithTooltip.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import { Button, OverlayTrigger, Tooltip } from 'react-bootstrap';

const ButtonWithTooltip = (props) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer a named function here:

function ButtonWithTooltip(props) {
  ...
}

let tooltip = (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this can be const since we aren't mutating it.

<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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should make the props that do not have defaults required.

tooltip: React.PropTypes.string.isRequired,

};

export default ButtonWithTooltip;
62 changes: 62 additions & 0 deletions caravel/assets/javascripts/SqlLab/components/LeftPane.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React from 'react';
import { Alert, Button } from 'react-bootstrap';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as Actions from '../actions';
import QueryLink from './QueryLink';

import 'react-select/dist/react-select.css';

const LeftPane = (props) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer named functions/function declarations https://github.com/airbnb/javascript#functions--declarations

let queryElements;
if (props.workspaceQueries.length > 0) {
queryElements = props.workspaceQueries.map((q) => <QueryLink query={q} />);
} else {
queryElements = (
<Alert bsStyle="info">
Use the save button on the SQL editor to save a query
into this section for future reference.
</Alert>
);
}
return (
<div>
<div className="panel panel-default LeftPane">
<div className="panel-heading">
<div className="panel-title">
Saved Queries
</div>
</div>
<div className="panel-body">
{queryElements}
</div>
</div>
<br /><br />
<Button onClick={props.actions.resetState.bind(this)} bsStyle="danger">
Reset State
</Button>
</div>
);
};

LeftPane.propTypes = {
workspaceQueries: React.PropTypes.array,
actions: React.PropTypes.object,
Copy link
Contributor

@ascott ascott Aug 11, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be required: actions: React.PropTypes.object.isRequired,

};

LeftPane.defaultProps = {
workspaceQueries: [],
};

function mapStateToProps(state) {
return {
workspaceQueries: state.workspaceQueries,
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Actions, dispatch),
};
}

export default connect(mapStateToProps, mapDispatchToProps)(LeftPane);
54 changes: 54 additions & 0 deletions caravel/assets/javascripts/SqlLab/components/Link.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import { OverlayTrigger, Tooltip } from 'react-bootstrap';


class Link extends React.Component {
render() {
let tooltip = (
<Tooltip id="tooltip">
{this.props.tooltip}
</Tooltip>
);
const link = (
<a
href={this.props.href}
onClick={this.props.onClick}
style={this.props.style}
className={'Link ' + this.props.className}
>
{this.props.children}
</a>
);
if (this.props.tooltip) {
return (
<OverlayTrigger
overlay={tooltip}
placement={this.props.placement}
delayShow={300}
delayHide={150}
>
{link}
</OverlayTrigger>
);
}
return link;
}
}
Link.propTypes = {
children: React.PropTypes.object,
className: React.PropTypes.string,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

required?

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: () => {},
};

export default Link;
Loading