Skip to content

Commit

Permalink
[sqllab] show partition metadata for Presto (#1342)
Browse files Browse the repository at this point in the history
  • Loading branch information
mistercrunch committed Oct 19, 2016
1 parent 2edce5b commit c255e89
Show file tree
Hide file tree
Showing 15 changed files with 390 additions and 87 deletions.
6 changes: 3 additions & 3 deletions caravel/assets/javascripts/SqlLab/actions.js
Expand Up @@ -2,7 +2,7 @@ export const RESET_STATE = 'RESET_STATE';
export const ADD_QUERY_EDITOR = 'ADD_QUERY_EDITOR';
export const CLONE_QUERY_TO_NEW_TAB = 'CLONE_QUERY_TO_NEW_TAB';
export const REMOVE_QUERY_EDITOR = 'REMOVE_QUERY_EDITOR';
export const ADD_TABLE = 'ADD_TABLE';
export const MERGE_TABLE = 'MERGE_TABLE';
export const REMOVE_TABLE = 'REMOVE_TABLE';
export const START_QUERY = 'START_QUERY';
export const STOP_QUERY = 'STOP_QUERY';
Expand Down Expand Up @@ -86,8 +86,8 @@ export function queryEditorSetSql(queryEditor, sql) {
return { type: QUERY_EDITOR_SET_SQL, queryEditor, sql };
}

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

export function expandTable(table) {
Expand Down
2 changes: 1 addition & 1 deletion caravel/assets/javascripts/SqlLab/components/SouthPane.jsx
Expand Up @@ -55,7 +55,7 @@ class SouthPane extends React.Component {
return (
<div className="SouthPane">
<Tabs bsStyle="tabs" id={shortid.generate()}>
<Tab title="Results" eventKey={1} id={shortid.generate()}>
<Tab title="Results" eventKey={1}>
<div style={{ overflow: 'auto' }}>
{results}
</div>
Expand Down
4 changes: 2 additions & 2 deletions caravel/assets/javascripts/SqlLab/components/SqlEditor.jsx
Expand Up @@ -28,7 +28,7 @@ import shortid from 'shortid';
import SouthPane from './SouthPane';
import Timer from './Timer';

import SqlEditorTopToolbar from './SqlEditorTopToolbar';
import SqlEditorLeftBar from './SqlEditorLeftBar';

class SqlEditor extends React.Component {
constructor(props) {
Expand Down Expand Up @@ -252,7 +252,7 @@ class SqlEditor extends React.Component {
<div className="SqlEditor" style={{ minHeight: this.sqlEditorHeight() }}>
<Row>
<Col md={3}>
<SqlEditorTopToolbar queryEditor={this.props.queryEditor} />
<SqlEditorLeftBar queryEditor={this.props.queryEditor} />
</Col>
<Col md={9}>
<AceEditor
Expand Down
Expand Up @@ -4,14 +4,13 @@ import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as Actions from '../actions';
import shortid from 'shortid';
import Select from 'react-select';
import { Label, Button } from 'react-bootstrap';
import TableElement from './TableElement';
import DatabaseSelect from './DatabaseSelect';


class SqlEditorTopToolbar extends React.Component {
class SqlEditorLeftBar extends React.Component {
constructor(props) {
super(props);
this.state = {
Expand Down Expand Up @@ -79,12 +78,11 @@ class SqlEditorTopToolbar extends React.Component {
changeTable(tableOpt) {
const tableName = tableOpt.value;
const qe = this.props.queryEditor;
const url = `/caravel/table/${qe.dbId}/${tableName}/${qe.schema}/`;
let url = `/caravel/table/${qe.dbId}/${tableName}/${qe.schema}/`;

this.setState({ tableLoading: true });
$.get(url, (data) => {
this.props.actions.addTable({
id: shortid.generate(),
this.props.actions.mergeTable({
dbId: this.props.queryEditor.dbId,
queryEditorId: this.props.queryEditor.id,
name: data.name,
Expand All @@ -102,6 +100,18 @@ class SqlEditorTopToolbar extends React.Component {
});
this.setState({ tableLoading: false });
});

url = `/caravel/extra_table_metadata/${qe.dbId}/${tableName}/${qe.schema}/`;
$.get(url, (data) => {
const table = {
dbId: this.props.queryEditor.dbId,
queryEditorId: this.props.queryEditor.id,
schema: qe.schema,
name: tableName,
};
Object.assign(table, data);
this.props.actions.mergeTable(table);
});
}
render() {
let networkAlert = null;
Expand Down Expand Up @@ -158,14 +168,14 @@ class SqlEditorTopToolbar extends React.Component {
}
}

SqlEditorTopToolbar.propTypes = {
SqlEditorLeftBar.propTypes = {
queryEditor: React.PropTypes.object,
tables: React.PropTypes.array,
actions: React.PropTypes.object,
networkOn: React.PropTypes.bool,
};

SqlEditorTopToolbar.defaultProps = {
SqlEditorLeftBar.defaultProps = {
tables: [],
};

Expand All @@ -182,4 +192,4 @@ function mapDispatchToProps(dispatch) {
};
}

export default connect(mapStateToProps, mapDispatchToProps)(SqlEditorTopToolbar);
export default connect(mapStateToProps, mapDispatchToProps)(SqlEditorLeftBar);
Expand Up @@ -116,7 +116,6 @@ class TabbedSqlEditors extends React.Component {
key={qe.id}
title={tabTitle}
eventKey={qe.id}
id={`a11y-query-editor-${qe.id}`}
>
<div className="panel panel-default">
<div className="panel-body">
Expand Down
120 changes: 87 additions & 33 deletions caravel/assets/javascripts/SqlLab/components/TableElement.jsx
@@ -1,11 +1,23 @@
import React from 'react';
import { ButtonGroup } from 'react-bootstrap';
import { ButtonGroup, Well } from 'react-bootstrap';
import Link from './Link';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as Actions from '../actions';
import shortid from 'shortid';
import ModalTrigger from '../../components/ModalTrigger.jsx';
import ModalTrigger from '../../components/ModalTrigger';
import CopyToClipboard from '../../components/CopyToClipboard';

const propTypes = {
table: React.PropTypes.object,
queryEditor: React.PropTypes.object,
actions: React.PropTypes.object,
};

const defaultProps = {
table: null,
actions: {},
};

class TableElement extends React.Component {
setSelectStar() {
Expand Down Expand Up @@ -40,40 +52,85 @@ class TableElement extends React.Component {

collapseTable(e) {
e.preventDefault();
this.props.actions.collapseTable.bind(this, this.props.table)();
this.props.actions.collapseTable(this.props.table);
}

expandTable(e) {
e.preventDefault();
this.props.actions.expandTable.bind(this, this.props.table)();
this.props.actions.expandTable(this.props.table);
}

removeTable() {
this.props.actions.removeTable(this.props.table);
}

render() {
const table = this.props.table;
let metadata = null;
let buttonToggle;
if (this.props.table.expanded) {

let header;
if (table.partitions) {
let partitionQuery;
let partitionClipBoard;
if (table.partitions.partitionQuery) {
partitionQuery = table.partitions.partitionQuery;
const tt = 'Copy partition query to clipboard';
partitionClipBoard = (
<CopyToClipboard
text={partitionQuery}
shouldShowText={false}
tooltipText={tt}
copyNode={<i className="fa fa-clipboard" />}
/>
);
}
let latest = [];
for (const k in table.partitions.latest) {
latest.push(`${k}=${table.partitions.latest[k]}`);
}
latest = latest.join('/');
header = (
<Well bsSize="small">
<div>
<small>
latest partition: {latest}
</small> {partitionClipBoard}
</div>
</Well>
);
}
if (table.expanded) {
buttonToggle = (
<a
href="#"
onClick={(e) => { this.collapseTable(e); }}
>
<strong>{this.props.table.name}</strong>
<strong>{table.name}</strong>
<small className="m-l-5"><i className="fa fa-minus" /></small>
</a>
);
metadata = (
<div>
{this.props.table.columns.map((col) => (
<div className="clearfix" key={shortid.generate()}>
<div className="pull-left m-l-10">
{col.name}
</div>
<div className="pull-right text-muted">
<small> {col.type}</small>
</div>
</div>
))}
<hr />
{header}
<div className="table-columns">
{table.columns.map((col) => {
let name = col.name;
if (col.indexed) {
name = <strong>{col.name}</strong>;
}
return (
<div className="clearfix table-column" key={shortid.generate()}>
<div className="pull-left m-l-10">
{name}
</div>
<div className="pull-right text-muted">
<small> {col.type}</small>
</div>
</div>);
})}
<hr />
</div>
</div>
);
} else {
Expand All @@ -82,34 +139,34 @@ class TableElement extends React.Component {
href="#"
onClick={(e) => { this.expandTable(e); }}
>
{this.props.table.name}
{table.name}
<small className="m-l-5"><i className="fa fa-plus" /></small>
</a>
);
}
let keyLink;
if (this.props.table.indexes && this.props.table.indexes.length > 0) {
if (table.indexes && table.indexes.length > 0) {
keyLink = (
<ModalTrigger
modalTitle={
<div>
Keys for table <strong>{this.props.table.name}</strong>
Keys for table <strong>{table.name}</strong>
</div>
}
modalBody={
<pre>{JSON.stringify(this.props.table.indexes, null, 4)}</pre>
<pre>{JSON.stringify(table.indexes, null, 4)}</pre>
}
triggerNode={
<Link
className="fa fa-key pull-left m-l-2"
tooltip={`View indexes (${this.props.table.indexes.length})`}
tooltip={`View indexes (${table.indexes.length})`}
/>
}
/>
);
}
return (
<div>
<div className="TableElement">
<div className="clearfix">
<div className="pull-left">
{buttonToggle}
Expand All @@ -131,30 +188,27 @@ class TableElement extends React.Component {
/>
<Link
className="fa fa-trash pull-left m-l-2"
onClick={this.props.actions.removeTable.bind(this, this.props.table)}
onClick={this.removeTable.bind(this)}
tooltip="Remove from workspace"
href="#"
/>
</ButtonGroup>
</div>
</div>
{metadata}
<div>
{metadata}
</div>
</div>
);
}
}
TableElement.propTypes = {
table: React.PropTypes.object,
queryEditor: React.PropTypes.object,
actions: React.PropTypes.object,
};
TableElement.defaultProps = {
table: null,
};
TableElement.propTypes = propTypes;
TableElement.defaultProps = defaultProps;

function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(Actions, dispatch),
};
}
export default connect(null, mapDispatchToProps)(TableElement);
export { TableElement };
6 changes: 6 additions & 0 deletions caravel/assets/javascripts/SqlLab/main.css
Expand Up @@ -232,3 +232,9 @@ div.tablePopover:hover {
.SouthPane .tab-content {
padding-top: 10px;
}

.TableElement .well {
margin-top: 5px;
margin-bottom: 5px;
padding: 5px 10px;
}
19 changes: 17 additions & 2 deletions caravel/assets/javascripts/SqlLab/reducers.js
Expand Up @@ -72,8 +72,23 @@ export const sqlLabReducer = function (state, action) {
[actions.RESET_STATE]() {
return Object.assign({}, initialState);
},
[actions.ADD_TABLE]() {
return addToArr(state, 'tables', action.table);
[actions.MERGE_TABLE]() {
const at = Object.assign({}, action.table);
let existingTable;
state.tables.forEach((t) => {
if (
t.dbId === at.dbId &&
t.queryEditorId === at.queryEditorId &&
t.schema === at.schema &&
t.name === at.name) {
existingTable = t;
}
});
if (existingTable) {
return alterInArr(state, 'tables', existingTable, at);
}
at.id = shortid.generate();
return addToArr(state, 'tables', at);
},
[actions.EXPAND_TABLE]() {
return alterInArr(state, 'tables', action.table, { expanded: true });
Expand Down
6 changes: 4 additions & 2 deletions caravel/assets/javascripts/components/CopyToClipboard.jsx
Expand Up @@ -76,9 +76,11 @@ export default class CopyToClipboard extends React.Component {
return (
<span>
{this.props.shouldShowText &&
<span>{this.props.text}</span>
<span>
{this.props.text}
&nbsp;&nbsp;&nbsp;&nbsp;
</span>
}
&nbsp;&nbsp;&nbsp;&nbsp;
<OverlayTrigger placement="top" overlay={this.renderTooltip()} trigger={['hover']}>
<Button
bsStyle="link"
Expand Down
2 changes: 1 addition & 1 deletion caravel/assets/javascripts/components/ModalTrigger.jsx
Expand Up @@ -4,7 +4,7 @@ import cx from 'classnames';

const propTypes = {
triggerNode: PropTypes.node.isRequired,
modalTitle: PropTypes.string.isRequired,
modalTitle: PropTypes.node.isRequired,
modalBody: PropTypes.node.isRequired,
beforeOpen: PropTypes.func,
isButton: PropTypes.bool,
Expand Down

0 comments on commit c255e89

Please sign in to comment.