diff --git a/superset/assets/javascripts/explorev2/actions/exploreActions.js b/superset/assets/javascripts/explorev2/actions/exploreActions.js index c03e25a8e08..d944b839c38 100644 --- a/superset/assets/javascripts/explorev2/actions/exploreActions.js +++ b/superset/assets/javascripts/explorev2/actions/exploreActions.js @@ -1,6 +1,5 @@ /* eslint camelcase: 0 */ const $ = window.$ = require('jquery'); - export const SET_FIELD_OPTIONS = 'SET_FIELD_OPTIONS'; export function setFieldOptions(options) { return { type: SET_FIELD_OPTIONS, options }; @@ -75,8 +74,8 @@ export function changeFilterValue(filter, value) { } export const SET_FIELD_VALUE = 'SET_FIELD_VALUE'; -export function setFieldValue(key, value) { - return { type: SET_FIELD_VALUE, key, value }; +export function setFieldValue(key, value, label) { + return { type: SET_FIELD_VALUE, key, value, label }; } export const UPDATE_CHART = 'UPDATE_CHART'; diff --git a/superset/assets/javascripts/explorev2/components/ControlPanelsContainer.jsx b/superset/assets/javascripts/explorev2/components/ControlPanelsContainer.jsx index c637bae99cc..8452e377c73 100644 --- a/superset/assets/javascripts/explorev2/components/ControlPanelsContainer.jsx +++ b/superset/assets/javascripts/explorev2/components/ControlPanelsContainer.jsx @@ -9,7 +9,6 @@ import ControlPanelSection from './ControlPanelSection'; import FieldSetRow from './FieldSetRow'; const propTypes = { - datasource_id: PropTypes.number.isRequired, datasource_type: PropTypes.string.isRequired, actions: PropTypes.object.isRequired, fields: PropTypes.object.isRequired, @@ -20,14 +19,24 @@ const propTypes = { class ControlPanelsContainer extends React.Component { componentWillMount() { - const { datasource_id, datasource_type } = this.props; + const datasource_id = this.props.form_data.datasource; + const datasource_type = this.props.datasource_type; if (datasource_id) { this.props.actions.fetchFieldOptions(datasource_id, datasource_type); } } - onChange(name, value) { - this.props.actions.setFieldValue(name, value); + componentWillReceiveProps(nextProps) { + if (nextProps.form_data.datasource !== this.props.form_data.datasource) { + if (nextProps.form_data.datasource) { + this.props.actions.fetchFieldOptions( + nextProps.form_data.datasource, nextProps.datasource_type); + } + } + } + + onChange(name, value, label) { + this.props.actions.setFieldValue(name, value, label); } sectionsToRender() { @@ -82,7 +91,6 @@ function mapStateToProps(state) { return { isDatasourceMetaLoading: state.isDatasourceMetaLoading, fields: state.fields, - datasource_id: state.datasource_id, datasource_type: state.datasource_type, form_data: state.viz.form_data, }; diff --git a/superset/assets/javascripts/explorev2/components/ExploreViewContainer.jsx b/superset/assets/javascripts/explorev2/components/ExploreViewContainer.jsx index 6ac5d6e6a0e..9535ad4565d 100644 --- a/superset/assets/javascripts/explorev2/components/ExploreViewContainer.jsx +++ b/superset/assets/javascripts/explorev2/components/ExploreViewContainer.jsx @@ -11,9 +11,6 @@ const $ = require('jquery'); 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, }; @@ -31,14 +28,14 @@ class ExploreViewContainer extends React.Component { const form_data = this.props.form_data; Object.keys(form_data).forEach((field) => { // filter out null fields - if (form_data[field] !== null) { + if (form_data[field] !== null && field !== 'datasource') { 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_id = this.props.form_data.datasource; data.datasource_type = this.props.datasource_type; this.queryFormData(data); @@ -53,14 +50,14 @@ class ExploreViewContainer extends React.Component { updateUrl(params) { const baseUrl = - `/superset/explore/${this.props.datasource_type}/${this.props.datasource_id}/`; + `/superset/explore/${this.props.datasource_type}/${this.props.form_data.datasource}/`; const newEndpoint = `${baseUrl}?${params}`; history.pushState({}, document.title, newEndpoint); } queryFormData(data) { this.props.actions.updateExplore( - this.props.datasource_type, this.props.datasource_id, data); + this.props.datasource_type, this.props.form_data.datasource, data); } render() { @@ -99,11 +96,8 @@ 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, }; } diff --git a/superset/assets/javascripts/explorev2/components/SelectField.jsx b/superset/assets/javascripts/explorev2/components/SelectField.jsx index f582be59a2d..b574470d2b0 100644 --- a/superset/assets/javascripts/explorev2/components/SelectField.jsx +++ b/superset/assets/javascripts/explorev2/components/SelectField.jsx @@ -31,7 +31,11 @@ export default class SelectField extends React.Component { if (this.props.multi) { optionValue = opt ? opt.map((o) => o.value) : null; } - this.props.onChange(this.props.name, optionValue); + if (this.props.name === 'datasource' && optionValue !== null) { + this.props.onChange(this.props.name, optionValue, opt.label); + } else { + this.props.onChange(this.props.name, optionValue); + } } render() { const options = this.props.choices.map((c) => ({ value: c[0], label: c[1] })); diff --git a/superset/assets/javascripts/explorev2/index.jsx b/superset/assets/javascripts/explorev2/index.jsx index 3ed5b65b275..2b7fc145837 100644 --- a/superset/assets/javascripts/explorev2/index.jsx +++ b/superset/assets/javascripts/explorev2/index.jsx @@ -12,13 +12,14 @@ const bootstrapData = JSON.parse(exploreViewContainer.getAttribute('data-bootstr import { exploreReducer } from './reducers/exploreReducer'; -const bootstrappedState = Object.assign(initialState, { +const bootstrappedState = Object.assign(initialState(bootstrapData.viz.form_data.viz_type), { can_download: bootstrapData.can_download, datasources: bootstrapData.datasources, - datasource_id: parseInt(bootstrapData.datasource_id, 10), datasource_type: bootstrapData.datasource_type, viz: bootstrapData.viz, }); +bootstrappedState.viz.form_data.datasource = parseInt(bootstrapData.datasource_id, 10); +bootstrappedState.viz.form_data.datasource_name = bootstrapData.datasource_name; const store = createStore(exploreReducer, bootstrappedState, compose(applyMiddleware(thunk)) diff --git a/superset/assets/javascripts/explorev2/reducers/exploreReducer.js b/superset/assets/javascripts/explorev2/reducers/exploreReducer.js index 3a98a9e5e79..2bee4daba07 100644 --- a/superset/assets/javascripts/explorev2/reducers/exploreReducer.js +++ b/superset/assets/javascripts/explorev2/reducers/exploreReducer.js @@ -1,3 +1,4 @@ +import { defaultFormData } from '../stores/store'; import * as actions from '../actions/exploreActions'; import { addToArr, removeFromArr, alterInArr } from '../../../utils/reducerUtils'; @@ -47,9 +48,15 @@ export const exploreReducer = function (state, action) { return alterInArr(state, 'filters', action.filter, { value: action.value }); }, [actions.SET_FIELD_VALUE]() { - const newFormData = Object.assign({}, state.viz.form_data); + const newFormData = action.key === 'datasource' ? + defaultFormData(state.viz.form_data.viz_type) : Object.assign({}, state.viz.form_data); + if (action.key === 'datasource') { + newFormData.datasource_name = action.label; + newFormData.slice_id = state.viz.form_data.slice_id; + newFormData.slice_name = state.viz.form_data.slice_name; + newFormData.viz_type = state.viz.form_data.viz_type; + } newFormData[action.key] = action.value ? action.value : (!state.viz.form_data[action.key]); - return Object.assign( {}, state, diff --git a/superset/assets/javascripts/explorev2/stores/store.js b/superset/assets/javascripts/explorev2/stores/store.js index ead6bcade88..1b413f9c4ac 100644 --- a/superset/assets/javascripts/explorev2/stores/store.js +++ b/superset/assets/javascripts/explorev2/stores/store.js @@ -1628,34 +1628,47 @@ export const fields = { }, }; -export function defaultFormData() { +export function defaultFormData(vizType = 'table') { const data = { slice_name: null, slice_id: null, + datasource_name: null, }; - Object.keys(fields).forEach((k) => { data[k] = fields[k].default; }); + const { datasourceAndVizType, sqlClause } = commonControlPanelSections; + const viz = visTypes[vizType]; + const sectionsToRender = [datasourceAndVizType].concat(viz.controlPanelSections, sqlClause); + sectionsToRender.forEach((section) => { + section.fieldSetRows.forEach((fieldSetRow) => { + fieldSetRow.forEach((k) => { + data[k] = fields[k].default; + }); + }); + }); return data; } -export const defaultViz = { - cached_key: null, - cached_timeout: null, - cached_dttm: null, - column_formats: null, - csv_endpoint: null, - is_cached: false, - data: [], - form_data: defaultFormData(), - json_endpoint: null, - query: null, - standalone_endpoint: null, -}; +export function defaultViz(vizType) { + return { + cached_key: null, + cached_timeout: null, + cached_dttm: null, + column_formats: null, + csv_endpoint: null, + is_cached: false, + data: [], + form_data: defaultFormData(vizType), + json_endpoint: null, + query: null, + standalone_endpoint: null, + }; +} -export const initialState = { - isDatasourceMetaLoading: false, - datasources: null, - datasource_id: null, - datasource_type: null, - fields, - viz: defaultViz, -}; +export function initialState(vizType = 'table') { + return { + isDatasourceMetaLoading: false, + datasources: null, + datasource_type: null, + fields, + viz: defaultViz(vizType), + }; +} diff --git a/superset/assets/spec/javascripts/explorev2/actions_spec.js b/superset/assets/spec/javascripts/explorev2/actions_spec.js index c674fdf5199..c779c3a3345 100644 --- a/superset/assets/spec/javascripts/explorev2/actions_spec.js +++ b/superset/assets/spec/javascripts/explorev2/actions_spec.js @@ -6,11 +6,12 @@ import { exploreReducer } from '../../../javascripts/explorev2/reducers/exploreR describe('reducers', () => { it('sets correct field value given a key and value', () => { - const newState = exploreReducer(initialState, actions.setFieldValue('x_axis_label', 'x')); + const newState = exploreReducer( + initialState('dist_bar'), actions.setFieldValue('x_axis_label', 'x')); expect(newState.viz.form_data.x_axis_label).to.equal('x'); }); it('toggles a boolean field value given only a key', () => { - const newState = exploreReducer(initialState, actions.setFieldValue('show_legend')); + const newState = exploreReducer(initialState('dist_bar'), actions.setFieldValue('show_legend')); expect(newState.viz.form_data.show_legend).to.equal(false); }); }); diff --git a/superset/views.py b/superset/views.py index 1251384d93f..42ad66f9e42 100755 --- a/superset/views.py +++ b/superset/views.py @@ -1391,6 +1391,7 @@ class Superset(BaseSupersetView): # TODO: separate endpoint for fetching datasources "datasources": [(d.id, d.full_name) for d in datasources], "datasource_id": datasource_id, + "datasource_name": viz_obj.datasource.name, "datasource_type": datasource_type, "user_id": g.user.get_id() if g.user else None, "viz": json.loads(viz_obj.get_json())