{this.renderTooltip()}
diff --git a/superset/assets/src/explore/components/Control.jsx b/superset/assets/src/explore/components/Control.jsx
index 31942e9f28..b8babc709b 100644
--- a/superset/assets/src/explore/components/Control.jsx
+++ b/superset/assets/src/explore/components/Control.jsx
@@ -37,7 +37,6 @@ const propTypes = {
description: PropTypes.string,
tooltipOnClick: PropTypes.func,
places: PropTypes.number,
- validators: PropTypes.array,
validationErrors: PropTypes.array,
renderTrigger: PropTypes.bool,
rightNode: PropTypes.node,
@@ -54,7 +53,6 @@ const propTypes = {
const defaultProps = {
renderTrigger: false,
- validators: [],
hidden: false,
validationErrors: [],
};
@@ -63,45 +61,14 @@ export default class Control extends React.PureComponent {
constructor(props) {
super(props);
this.state = { hovered: false };
- this.validate = this.validate.bind(this);
this.onChange = this.onChange.bind(this);
}
- componentDidMount() {
- this.validateAndSetValue(this.props.value, []);
- }
onChange(value, errors) {
- this.validateAndSetValue(value, errors);
+ this.props.actions.setControlValue(this.props.name, value, errors);
}
setHover(hovered) {
this.setState({ hovered });
}
- validateAndSetValue(value, errors) {
- let validationErrors = this.props.validationErrors;
- let currentErrors = this.validate(value);
- if (errors && errors.length > 0) {
- currentErrors = validationErrors.concat(errors);
- }
- if (validationErrors.length + currentErrors.length > 0) {
- validationErrors = currentErrors;
- }
-
- if (value !== this.props.value || validationErrors !== this.props.validationErrors) {
- this.props.actions.setControlValue(this.props.name, value, validationErrors);
- }
- }
- validate(value) {
- const validators = this.props.validators;
- const validationErrors = [];
- if (validators && validators.length > 0) {
- validators.forEach((f) => {
- const v = f(value);
- if (v) {
- validationErrors.push(v);
- }
- });
- }
- return validationErrors;
- }
render() {
const ControlType = controlMap[this.props.type];
const divStyle = this.props.hidden ? { display: 'none' } : null;
diff --git a/superset/assets/src/explore/components/ExploreViewContainer.jsx b/superset/assets/src/explore/components/ExploreViewContainer.jsx
index 91777e45e2..68d8fe1adc 100644
--- a/superset/assets/src/explore/components/ExploreViewContainer.jsx
+++ b/superset/assets/src/explore/components/ExploreViewContainer.jsx
@@ -21,6 +21,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
+import { t } from '@superset-ui/translation';
import ExploreChartPanel from './ExploreChartPanel';
import ControlPanelsContainer from './ControlPanelsContainer';
@@ -100,6 +101,12 @@ class ExploreViewContainer extends React.Component {
document.addEventListener('keydown', this.handleKeydown);
this.addHistory({ isReplace: true });
this.props.actions.logEvent(LOG_ACTIONS_MOUNT_EXPLORER);
+
+ // Trigger the chart if there are no errors
+ const { chart } = this.props;
+ if (!this.hasErrors()) {
+ this.props.actions.triggerQuery(true, this.props.chart.id);
+ }
}
componentWillReceiveProps(nextProps) {
@@ -272,12 +279,13 @@ class ExploreViewContainer extends React.Component {
renderErrorMessage() {
// Returns an error message as a node if any errors are in the store
const errors = [];
+ const ctrls = this.props.controls;
for (const controlName in this.props.controls) {
const control = this.props.controls[controlName];
if (control.validationErrors && control.validationErrors.length > 0) {
errors.push(
- {`[ ${control.label} ] `}
+ {t('Control labeled ')}{` "${control.label}" `}
{control.validationErrors.join('. ')}
,
);
diff --git a/superset/assets/src/explore/reducers/exploreReducer.js b/superset/assets/src/explore/reducers/exploreReducer.js
index 3823888812..6f6a1a9e6b 100644
--- a/superset/assets/src/explore/reducers/exploreReducer.js
+++ b/superset/assets/src/explore/reducers/exploreReducer.js
@@ -17,7 +17,8 @@
* under the License.
*/
/* eslint camelcase: 0 */
-import { getControlsState, getFormDataFromControls } from '../store';
+import { validateControl, getControlsState, getFormDataFromControls } from '../store';
+import controls from '../controls';
import * as actions from '../actions/exploreActions';
export default function exploreReducer(state = {}, action) {
@@ -75,24 +76,28 @@ export default function exploreReducer(state = {}, action) {
};
},
[actions.SET_FIELD_VALUE]() {
- const controls = Object.assign({}, state.controls);
- const control = Object.assign({}, controls[action.controlName]);
- control.value = action.value;
- control.validationErrors = action.validationErrors;
- controls[action.controlName] = control;
- const changes = {
- controls,
+ // These errors are reported from the Control components
+ let errors = action.validationErrors || [];
+ let control = {
+ ...controls[action.controlName],
+ value: action.value,
};
- if (control.renderTrigger) {
- changes.triggerRender = true;
- } else {
- changes.triggerRender = false;
- }
- const newState = {
+ control = validateControl(control);
+
+ // These errors are based on control config `validators`
+ errors = errors.concat(control.validationErrors || []);
+ const hasErrors = errors && errors.length > 0;
+ return {
...state,
- ...changes,
+ triggerRender: control.renderTrigger && !hasErrors,
+ controls: {
+ ...state.controls,
+ [action.controlName]: {
+ ...control,
+ validationErrors: errors,
+ },
+ },
};
- return newState;
},
[actions.SET_EXPLORE_CONTROLS]() {
return {
diff --git a/superset/assets/src/explore/reducers/getInitialState.js b/superset/assets/src/explore/reducers/getInitialState.js
index 48c85c7579..98b979914a 100644
--- a/superset/assets/src/explore/reducers/getInitialState.js
+++ b/superset/assets/src/explore/reducers/getInitialState.js
@@ -52,14 +52,14 @@ export default function getInitialState(bootstrapData) {
[chartKey]: {
id: chartKey,
chartAlert: null,
- chartStatus: 'loading',
+ chartStatus: null,
chartUpdateEndTime: null,
chartUpdateStartTime: 0,
latestQueryFormData: getFormDataFromControls(controls),
sliceFormData,
queryController: null,
queryResponse: null,
- triggerQuery: true,
+ triggerQuery: false,
lastRendered: 0,
},
},
diff --git a/superset/assets/src/explore/store.js b/superset/assets/src/explore/store.js
index be2be7b32a..df456c29eb 100644
--- a/superset/assets/src/explore/store.js
+++ b/superset/assets/src/explore/store.js
@@ -29,6 +29,24 @@ export function getFormDataFromControls(controlsState) {
return formData;
}
+export function validateControl(control) {
+ const validators = control.validators;
+ const validationErrors = [];
+ if (validators && validators.length > 0) {
+ validators.forEach((f) => {
+ const v = f(control.value);
+ if (v) {
+ validationErrors.push(v);
+ }
+ });
+ }
+ if (validationErrors.length > 0) {
+ return { ...control, validationErrors };
+ }
+ return control;
+}
+
+
export function getControlNames(vizType, datasourceType) {
const controlNames = [];
sectionsToRender(vizType, datasourceType).forEach(
@@ -109,7 +127,7 @@ export function getControlsState(state, form_data) {
) {
control.value = formData[k];
}
- controlsState[k] = control;
+ controlsState[k] = validateControl(control);
});
if (viz.onInit) {
return viz.onInit(controlsState);