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

Bogdan/queries endpoint #1452

Closed
wants to merge 9 commits into from
Closed
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
16 changes: 16 additions & 0 deletions caravel/assets/javascripts/SqlLab/TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

# 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
* SqlEditor buttons
* use react-bootstrap-prompt for query title input
* Make tabs look great

# PROJECT
* Write Runbook
* Confirm backups
* merge chef branch
112 changes: 112 additions & 0 deletions caravel/assets/javascripts/SqlLab/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
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 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 };
}
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);
46 changes: 46 additions & 0 deletions caravel/assets/javascripts/SqlLab/components/ButtonWithTooltip.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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}
disabled={props.disabled}
className={props.className}
>
{props.children}
</Button>
</OverlayTrigger>
);
};

ButtonWithTooltip.defaultProps = {
onClick: () => {},
disabled: false,
placement: 'top',
bsStyle: 'default',
};

ButtonWithTooltip.propTypes = {
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;
79 changes: 79 additions & 0 deletions caravel/assets/javascripts/SqlLab/components/LeftPane.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React from 'react';
import { Alert, Button, Label } 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) => {
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 className="panel panel-default LeftPane">
<div className="panel-heading">
<h6 className="m-r-10">
<i className="fa fa-flask" />
SQL Lab <Label bsStyle="danger">ALPHA</Label>
</h6>
</div>
<div className="panel-body">
<div>
<h6>
<span className="fa-stack">
<i className="fa fa-database fa-stack-lg"></i>
<i className="fa fa-search fa-stack-1x"></i>
</span> Saved Queries
</h6>
<div>
{queryElements}
</div>
<hr />
<Button onClick={props.actions.resetState.bind(this)}>
Reset State
</Button>
<Button
onClick={props.actions.addAlert.bind(this, {
msg: 'This info alert is a demo alert',
bsStyle: 'info',
})}
>
Add Alert
</Button>
</div>
</div>
</div>
);
};

LeftPane.propTypes = {
workspaceQueries: React.PropTypes.array,
actions: React.PropTypes.object,
};

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

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

export default connect(mapStateToProps, mapDispatchToProps)(LeftPane);
52 changes: 52 additions & 0 deletions caravel/assets/javascripts/SqlLab/components/Link.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
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}
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 = {
className: React.PropTypes.string,
href: React.PropTypes.string,
onClick: React.PropTypes.func,
tooltip: React.PropTypes.string,
placement: React.PropTypes.string,
children: React.PropTypes.object,
};
Link.defaultProps = {
disabled: false,
href: '#',
tooltip: null,
placement: 'top',
onClick: () => {},
};

export default Link;
Loading