From 83d08b8b8f7c73cbf4de25cadeab93dd3fdfc2fc Mon Sep 17 00:00:00 2001 From: vera-liu Date: Wed, 16 Nov 2016 13:21:53 -0800 Subject: [PATCH] Get query button working in explorev2 (#1581) * 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 --- .../explore/components/QueryAndSaveBtns.jsx | 2 +- .../explorev2/actions/exploreActions.js | 62 +++++++++++---- .../explorev2/components/ChartContainer.jsx | 41 ++++++---- .../components/ExploreViewContainer.jsx | 78 ++++++++++++++++++- .../explorev2/components/SelectField.jsx | 2 +- .../assets/javascripts/explorev2/index.jsx | 1 + .../explorev2/reducers/exploreReducer.js | 23 ++++++ .../javascripts/explorev2/stores/store.js | 2 +- .../components/QueryAndSaveBtns_spec.jsx | 9 ++- superset/views.py | 21 ++++- tests/core_tests.py | 19 +++++ 11 files changed, 224 insertions(+), 36 deletions(-) diff --git a/superset/assets/javascripts/explore/components/QueryAndSaveBtns.jsx b/superset/assets/javascripts/explore/components/QueryAndSaveBtns.jsx index 1a5213934..d6e25a052 100644 --- a/superset/assets/javascripts/explore/components/QueryAndSaveBtns.jsx +++ b/superset/assets/javascripts/explore/components/QueryAndSaveBtns.jsx @@ -13,7 +13,7 @@ export default function QueryAndSaveBtns({ canAdd, onQuery }) { return (
-
} > -
{ this.chartContainerRef = ref; }} - className={this.props.viz_type} - /> + {!this.props.isChartLoading && +
{ this.chartContainerRef = ref; }} + className={this.props.viz_type} + /> + }
); @@ -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, }; } diff --git a/superset/assets/javascripts/explorev2/components/ExploreViewContainer.jsx b/superset/assets/javascripts/explorev2/components/ExploreViewContainer.jsx index 253b5beb3..6ac5d6e6a 100644 --- a/superset/assets/javascripts/explorev2/components/ExploreViewContainer.jsx +++ b/superset/assets/javascripts/explorev2/components/ExploreViewContainer.jsx @@ -1,9 +1,24 @@ +/* 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 = { @@ -11,11 +26,43 @@ export default class ExploreViewContainer extends React.Component { }; } + 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 (
{}} + onQuery={this.onQuery.bind(this)} />

- +
{ const defaultProps = { canAdd: 'True', - onQuery: () => {}, + onQuery: sinon.spy(), }; // It must render @@ -32,5 +33,11 @@ describe('QueryAndSaveButtons', () => { expect(wrapper.find('button').contains(' Query')).to.eql(true); expect(wrapper.find('button').contains(' Save as')).to.eql(true); }); + + it('calls onQuery when query button is clicked', () => { + const queryButton = wrapper.find('#query_button'); + queryButton.simulate('click'); + expect(defaultProps.onQuery.called).to.eql(true); + }); }); }); diff --git a/superset/views.py b/superset/views.py index 841c968b4..486008d6e 100755 --- a/superset/views.py +++ b/superset/views.py @@ -1244,7 +1244,8 @@ class Superset(BaseSupersetView): viz_type = args.get('viz_type', 'table') datasource = SourceRegistry.get_datasource( datasource_type, datasource_id, db.session) - viz_obj = viz.viz_types[viz_type](datasource, request.args) + viz_obj = viz.viz_types[viz_type]( + datasource, request.args if request.args else args) return viz_obj @has_access @@ -1253,6 +1254,24 @@ class Superset(BaseSupersetView): viz_obj = self.get_viz(slice_id) return redirect(viz_obj.get_url(**request.args)) + @log_this + @has_access_api + @expose( + "/update_explore///", methods=['POST']) + def update_explore(self, datasource_type, datasource_id): + """Send back new viz on POST request for updating update explore view""" + form_data = json.loads(request.form.get('data')) + error_redirect = '/slicemodelview/list/' + try: + viz_obj = self.get_viz( + datasource_type=datasource_type, + datasource_id=datasource_id, + args=form_data) + except Exception as e: + flash('{}'.format(e), "alert") + return redirect(error_redirect) + return viz_obj.get_json() + @has_access_api @expose("/explore_json///") def explore_json(self, datasource_type, datasource_id): diff --git a/tests/core_tests.py b/tests/core_tests.py index 70e8d6459..5b3e23348 100644 --- a/tests/core_tests.py +++ b/tests/core_tests.py @@ -97,6 +97,25 @@ class CoreTests(SupersetTestCase): assert_admin_view_menus_in('Alpha', self.assertNotIn) assert_admin_view_menus_in('Gamma', self.assertNotIn) + def test_update_explore(self): + self.login(username='admin') + tbl_id = self.table_ids.get('energy_usage') + data = json.dumps({ + 'viz_type': 'sankey', + 'groupby': ['source', 'target'], + 'metrics': ['sum__value'], + 'row_limit': 5000, + 'flt_col_0': 'source', + 'datasource_name': 'energy_usage', + 'datasource_id': tbl_id, + 'datasource_type': 'table', + 'previous_viz_type': 'sankey' + }) + response = self.client.post('/superset/update_explore/table/{}/'.format(tbl_id), + data=dict(data=data)) + assert response.status_code == 200 + self.logout() + def test_save_slice(self): self.login(username='admin') slice_id = self.get_slice("Energy Sankey", db.session).id