Skip to content

Commit

Permalink
Get query button working in explorev2 (#1581)
Browse files Browse the repository at this point in the history
* Get query buttonw working in explorev2

 - Create new endpoint for updating explore viz
 - Send over new form_data when query button is pressed

* Added endpoint test

* Changes based on comments

* Added docstring for endpoint, and query spec

* Remove white space around docstring
  • Loading branch information
vera-liu authored Nov 16, 2016
1 parent ed3d44d commit 83d08b8
Show file tree
Hide file tree
Showing 11 changed files with 224 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default function QueryAndSaveBtns({ canAdd, onQuery }) {

return (
<div className="btn-group query-and-save">
<button type="button" className="btn btn-primary btn-sm" onClick={onQuery}>
<button id="query_button" type="button" className="btn btn-primary btn-sm" onClick={onQuery}>
<i className="fa fa-bolt"></i> Query
</button>
<button
Expand Down
62 changes: 49 additions & 13 deletions superset/assets/javascripts/explorev2/actions/exploreActions.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,17 @@
/* eslint camelcase: 0 */
const $ = window.$ = require('jquery');
export const SET_DATASOURCE = 'SET_DATASOURCE';
export const SET_FIELD_OPTIONS = 'SET_FIELD_OPTIONS';
export const TOGGLE_SEARCHBOX = 'TOGGLE_SEARCHBOX';
export const SET_FILTER_COLUMN_OPTS = 'SET_FILTER_COLUMN_OPTS';
export const ADD_FILTER = 'ADD_FILTER';
export const SET_FILTER = 'SET_FILTER';
export const REMOVE_FILTER = 'REMOVE_FILTER';
export const CHANGE_FILTER_FIELD = 'CHANGE_FILTER_FIELD';
export const CHANGE_FILTER_OP = 'CHANGE_FILTER_OP';
export const CHANGE_FILTER_VALUE = 'CHANGE_FILTER_VALUE';
export const CLEAR_ALL_OPTS = 'CLEAR_ALL_OPTS';
export const SET_DATASOURCE_TYPE = 'SET_DATASOURCE_TYPE';
export const SET_FIELD_VALUE = 'SET_FIELD_VALUE';

export const SET_FIELD_OPTIONS = 'SET_FIELD_OPTIONS';
export function setFieldOptions(options) {
return { type: SET_FIELD_OPTIONS, options };
}

export const CLEAR_ALL_OPTS = 'CLEAR_ALL_OPTS';
export function clearAllOpts() {
return { type: CLEAR_ALL_OPTS };
}

export const SET_DATASOURCE_TYPE = 'SET_DATASOURCE_TYPE';
export function setDatasourceType(datasourceType) {
return { type: SET_DATASOURCE_TYPE, datasourceType };
}
Expand Down Expand Up @@ -62,26 +53,71 @@ export function fetchFieldOptions(datasourceId, datasourceType) {
}
};
}

export const ADD_FILTER = 'ADD_FILTER';
export function addFilter(filter) {
return { type: ADD_FILTER, filter };
}

export const REMOVE_FILTER = 'REMOVE_FILTER';
export function removeFilter(filter) {
return { type: REMOVE_FILTER, filter };
}

export const CHANGE_FILTER_FIELD = 'CHANGE_FILTER_FIELD';
export function changeFilterField(filter, field) {
return { type: CHANGE_FILTER_FIELD, filter, field };
}

export const CHANGE_FILTER_OP = 'CHANGE_FILTER_OP';
export function changeFilterOp(filter, op) {
return { type: CHANGE_FILTER_OP, filter, op };
}

export const CHANGE_FILTER_VALUE = 'CHANGE_FILTER_VALUE';
export function changeFilterValue(filter, value) {
return { type: CHANGE_FILTER_VALUE, filter, value };
}

export const SET_FIELD_VALUE = 'SET_FIELD_VALUE';
export function setFieldValue(key, value) {
return { type: SET_FIELD_VALUE, key, value };
}

export const UPDATE_CHART = 'UPDATE_CHART';
export function updateChart(viz) {
return { type: UPDATE_CHART, viz };
}

export const CHART_UPDATE_STARTED = 'CHART_UPDATE_STARTED';
export function chartUpdateStarted() {
return { type: CHART_UPDATE_STARTED };
}

export const CHART_UPDATE_FAILED = 'CHART_UPDATE_FAILED ';
export function chartUpdateFailed() {
return { type: CHART_UPDATE_FAILED };
}

export function updateExplore(datasource_type, datasource_id, form_data) {
return function (dispatch) {
dispatch(chartUpdateStarted);
const updateUrl =
`/superset/update_explore/${datasource_type}/${datasource_id}/`;

$.ajax({
type: 'POST',
url: updateUrl,
data: {
data: JSON.stringify(form_data),
},
success: (data) => {
dispatch(updateChart(JSON.parse(data)));
},
error(error) {
dispatch(chartUpdateFailed(error));
},
});
};
}

41 changes: 26 additions & 15 deletions superset/assets/javascripts/explorev2/components/ChartContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const propTypes = {
standalone_endpoint: PropTypes.string.isRequired,
query: PropTypes.string.isRequired,
column_formats: PropTypes.object,
data: PropTypes.any,
isChartLoading: PropTypes.bool,
};

class ChartContainer extends React.Component {
Expand All @@ -29,30 +31,34 @@ class ChartContainer extends React.Component {
}

componentWillMount() {
this.setState({ mockSlice: this.getMockedSliceObject() });
this.setState({ mockSlice: this.getMockedSliceObject(this.props) });
}

componentDidMount() {
this.renderVis();
}

componentWillReceiveProps(nextProps) {
this.setState({ mockSlice: this.getMockedSliceObject(nextProps) });
}

componentDidUpdate() {
this.renderVis();
}

getMockedSliceObject() {
getMockedSliceObject(props) {
return {
viewSqlQuery: this.props.query,
viewSqlQuery: props.query,

data: {
csv_endpoint: this.props.csv_endpoint,
json_endpoint: this.props.json_endpoint,
standalone_endpoint: this.props.standalone_endpoint,
csv_endpoint: props.csv_endpoint,
json_endpoint: props.json_endpoint,
standalone_endpoint: props.standalone_endpoint,
},

containerId: this.props.containerId,
containerId: props.containerId,

jsonEndpoint: () => this.props.json_endpoint,
jsonEndpoint: () => props.json_endpoint,

container: {
html: (data) => {
Expand All @@ -66,7 +72,7 @@ class ChartContainer extends React.Component {
// should call callback to adjust height of chart
$(this.state.selector).css(dim, size);
},
height: () => parseInt(this.props.height, 10) - 100,
height: () => parseInt(props.height, 10) - 100,

show: () => { this.render(); },

Expand All @@ -78,7 +84,7 @@ class ChartContainer extends React.Component {

width: () => this.chartContainerRef.getBoundingClientRect().width,

height: () => parseInt(this.props.height, 10) - 100,
height: () => parseInt(props.height, 10) - 100,

selector: this.state.selector,

Expand Down Expand Up @@ -128,6 +134,7 @@ class ChartContainer extends React.Component {
};
}


renderVis() {
visMap[this.props.viz_type](this.state.mockSlice).render();
}
Expand All @@ -152,11 +159,13 @@ class ChartContainer extends React.Component {
</div>
}
>
<div
id={this.props.containerId}
ref={(ref) => { this.chartContainerRef = ref; }}
className={this.props.viz_type}
/>
{!this.props.isChartLoading &&
<div
id={this.props.containerId}
ref={(ref) => { this.chartContainerRef = ref; }}
className={this.props.viz_type}
/>
}
</Panel>
</div>
);
Expand All @@ -176,6 +185,8 @@ function mapStateToProps(state) {
standalone_endpoint: state.viz.standalone_endpoint,
query: state.viz.query,
column_formats: state.viz.column_formats,
data: state.viz.data,
isChartLoading: state.isChartLoading,
};
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,68 @@
/* eslint camelcase: 0 */
import React from 'react';
import { bindActionCreators } from 'redux';
import * as actions from '../actions/exploreActions';
import { connect } from 'react-redux';
import ChartContainer from './ChartContainer';
import ControlPanelsContainer from './ControlPanelsContainer';
import QueryAndSaveBtns from '../../explore/components/QueryAndSaveBtns';
const $ = require('jquery');

export default class ExploreViewContainer extends React.Component {
const propTypes = {
form_data: React.PropTypes.object.isRequired,
actions: React.PropTypes.object.isRequired,
slice_id: React.PropTypes.string.isRequired,
slice_name: React.PropTypes.string.isRequired,
datasource_id: React.PropTypes.number.isRequired,
datasource_type: React.PropTypes.string.isRequired,
};


class ExploreViewContainer extends React.Component {
constructor(props) {
super(props);
this.state = {
height: this.getHeight(),
};
}

onQuery() {
const data = {};
const form_data = this.props.form_data;
Object.keys(form_data).forEach((field) => {
// filter out null fields
if (form_data[field] !== null) {
data[field] = form_data[field];
}
});
// V2 tag temporarily for updating url
// Todo: remove after launch
data.V2 = true;
data.datasource_id = this.props.datasource_id;
data.datasource_type = this.props.datasource_type;
this.queryFormData(data);

const params = $.param(data, true);
this.updateUrl(params);
}

getHeight() {
const navHeight = 90;
return `${window.innerHeight - navHeight}px`;
}

updateUrl(params) {
const baseUrl =
`/superset/explore/${this.props.datasource_type}/${this.props.datasource_id}/`;
const newEndpoint = `${baseUrl}?${params}`;
history.pushState({}, document.title, newEndpoint);
}

queryFormData(data) {
this.props.actions.updateExplore(
this.props.datasource_type, this.props.datasource_id, data);
}

render() {
return (
<div
Expand All @@ -29,10 +76,13 @@ export default class ExploreViewContainer extends React.Component {
<div className="col-sm-4">
<QueryAndSaveBtns
canAdd="True"
onQuery={() => {}}
onQuery={this.onQuery.bind(this)}
/>
<br /><br />
<ControlPanelsContainer />
<ControlPanelsContainer
actions={this.props.actions}
form_data={this.props.form_data}
/>
</div>
<div className="col-sm-8">
<ChartContainer
Expand All @@ -44,3 +94,25 @@ export default class ExploreViewContainer extends React.Component {
);
}
}

ExploreViewContainer.propTypes = propTypes;

function mapStateToProps(state) {
return {
datasource_id: state.datasource_id,
datasource_type: state.datasource_type,
form_data: state.viz.form_data,
slice_id: state.viz.form_data.slice_id,
slice_name: state.viz.form_data.slice_name,
};
}

function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(actions, dispatch),
};
}

export { ControlPanelsContainer };

export default connect(mapStateToProps, mapDispatchToProps)(ExploreViewContainer);
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import Select, { Creatable } from 'react-select';
const propTypes = {
name: PropTypes.string.isRequired,
choices: PropTypes.array,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array]).isRequired,
label: PropTypes.string,
description: PropTypes.string,
onChange: PropTypes.func,
Expand Down
1 change: 1 addition & 0 deletions superset/assets/javascripts/explorev2/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const bootstrappedState = Object.assign(initialState, {
datasource_type: bootstrapData.datasource_type,
viz: bootstrapData.viz,
});

const store = createStore(exploreReducer, bootstrappedState,
compose(applyMiddleware(thunk))
);
Expand Down
23 changes: 23 additions & 0 deletions superset/assets/javascripts/explorev2/reducers/exploreReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,29 @@ export const exploreReducer = function (state, action) {
{ viz: Object.assign({}, state.viz, { form_data: newFormData }) }
);
},
[actions.UPDATE_CHART]() {
const vizUpdates = {
column_formats: action.viz.column_formats,
json_endpoint: action.viz.json_endpoint,
csv_endpoint: action.viz.csv_endpoint,
standalone_endpoint: action.viz.standalone_endpoint,
query: action.viz.query,
data: action.viz.data,
};
return Object.assign(
{},
state,
{
viz: Object.assign({}, state.viz, vizUpdates),
isChartLoading: false,
});
},
[actions.CHART_UPDATE_STARTED]() {
return Object.assign({}, state, { isChartLoading: true });
},
[actions.CHART_UPDATE_FAILED]() {
return Object.assign({}, state, { isChartLoading: false });
},
};
if (action.type in actionHandlers) {
return actionHandlers[action.type]();
Expand Down
2 changes: 1 addition & 1 deletion superset/assets/javascripts/explorev2/stores/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -604,7 +604,7 @@ export const visTypes = {
label: 'Heatmap',
controlPanelSections: [
{
label: null,
label: 'Axis & Metrics',
fieldSetRows: [
['all_columns_x'],
['all_columns_y'],
Expand Down
Loading

0 comments on commit 83d08b8

Please sign in to comment.