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/query status polling #1453

Closed
wants to merge 7 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
4 changes: 4 additions & 0 deletions bogdan.todo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
1. [] implement the polling of the query results
2. [] implement the retrieving of the CTA results
3. [] implement parsing of the query to retrieve the table names

24 changes: 24 additions & 0 deletions caravel/assets/javascripts/SqlLab/TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Design
* Query Log, search, filter on active tab only
* Where to make the limit clear?

# TODO
* collapse sql beyond 10 lines
* add [Visualize] icon to modal
* Security per-database
* Overwrite workspace query
* Async
* Refactor timer in to its own thing


## Cosmetic
* use icons for datatypes
* SqlEditor buttons
* use react-bootstrap-prompt for query title input
* make input:text more self-evident
* Tab cosmetic in theme

# PROJECT
* Write Runbook
* Confirm backups
* merge chef branch
102 changes: 102 additions & 0 deletions caravel/assets/javascripts/SqlLab/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
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 function resetState() {
return { type: RESET_STATE };
}

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

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 };
}
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;
72 changes: 72 additions & 0 deletions caravel/assets/javascripts/SqlLab/components/LeftPane.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
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';

// CSS
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>
</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;
50 changes: 50 additions & 0 deletions caravel/assets/javascripts/SqlLab/components/QueryHistory.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
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 QueryHistory = (props) => {
const activeQeId = props.tabHistory[props.tabHistory.length - 1];
const queries = props.queries.filter((q) => (q.sqlEditorId === activeQeId));
if (queries.length > 0) {
return (
<QueryTable
columns={['state', 'started', 'duration', 'rows', 'sql', 'actions']}
queries={queries}
/>
);
}
return (
<Alert bsStyle="info">
No query history yet...
</Alert>
);
};

QueryHistory.defaultProps = {
queries: [],
};

QueryHistory.propTypes = {
queries: React.PropTypes.array,
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);
Loading