mirror of
https://github.com/apache/superset.git
synced 2024-09-17 11:09:47 -04:00
Added Alert for ControlPanel and ChartContainer (#1626)
* Added Alert for ControlPanel and ChartContainer Done: - Add alert for Control Panel when fetch_datasource_metadata failes - Add alert for Chart Container when update_explore query fails * Changed color to warning-yellow * Solve linter issue * Fixed indent and delete error_redirect
This commit is contained in:
parent
0acf26b37c
commit
a8480f5492
@ -24,8 +24,8 @@ export function fetchSucceeded() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const FETCH_FAILED = 'FETCH_FAILED';
|
export const FETCH_FAILED = 'FETCH_FAILED';
|
||||||
export function fetchFailed() {
|
export function fetchFailed(error) {
|
||||||
return { type: FETCH_FAILED };
|
return { type: FETCH_FAILED, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchFieldOptions(datasourceId, datasourceType) {
|
export function fetchFieldOptions(datasourceId, datasourceType) {
|
||||||
@ -35,18 +35,19 @@ export function fetchFieldOptions(datasourceId, datasourceType) {
|
|||||||
if (datasourceId) {
|
if (datasourceId) {
|
||||||
const params = [`datasource_id=${datasourceId}`, `datasource_type=${datasourceType}`];
|
const params = [`datasource_id=${datasourceId}`, `datasource_type=${datasourceType}`];
|
||||||
const url = '/superset/fetch_datasource_metadata?' + params.join('&');
|
const url = '/superset/fetch_datasource_metadata?' + params.join('&');
|
||||||
|
$.ajax({
|
||||||
$.get(url, (data, status) => {
|
type: 'GET',
|
||||||
if (status === 'success') {
|
url,
|
||||||
// populate options for select type fields
|
success: (data) => {
|
||||||
dispatch(setFieldOptions(data.field_options));
|
dispatch(setFieldOptions(data.field_options));
|
||||||
dispatch(fetchSucceeded());
|
dispatch(fetchSucceeded());
|
||||||
} else if (status === 'error') {
|
},
|
||||||
dispatch(fetchFailed());
|
error(error) {
|
||||||
}
|
dispatch(fetchFailed(error.responseJSON.error));
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// in what case don't we have a datasource id?
|
dispatch(fetchFailed('Please select a datasource'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -119,8 +120,8 @@ export function chartUpdateStarted() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const CHART_UPDATE_FAILED = 'CHART_UPDATE_FAILED ';
|
export const CHART_UPDATE_FAILED = 'CHART_UPDATE_FAILED ';
|
||||||
export function chartUpdateFailed() {
|
export function chartUpdateFailed(error) {
|
||||||
return { type: CHART_UPDATE_FAILED };
|
return { type: CHART_UPDATE_FAILED, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateExplore(datasource_type, datasource_id, form_data) {
|
export function updateExplore(datasource_type, datasource_id, form_data) {
|
||||||
@ -139,9 +140,18 @@ export function updateExplore(datasource_type, datasource_id, form_data) {
|
|||||||
dispatch(updateChart(JSON.parse(data)));
|
dispatch(updateChart(JSON.parse(data)));
|
||||||
},
|
},
|
||||||
error(error) {
|
error(error) {
|
||||||
dispatch(chartUpdateFailed(error));
|
dispatch(chartUpdateFailed(error.responseJSON.error));
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const REMOVE_CONTROL_PANEL_ALERT = 'REMOVE_CONTROL_PANEL_ALERT';
|
||||||
|
export function removeControlPanelAlert() {
|
||||||
|
return { type: REMOVE_CONTROL_PANEL_ALERT };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const REMOVE_CHART_ALERT = 'REMOVE_CHART_ALERT';
|
||||||
|
export function removeChartAlert() {
|
||||||
|
return { type: REMOVE_CHART_ALERT };
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import React, { PropTypes } from 'react';
|
import React, { PropTypes } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Panel } from 'react-bootstrap';
|
import { Panel, Alert } from 'react-bootstrap';
|
||||||
import visMap from '../../../visualizations/main';
|
import visMap from '../../../visualizations/main';
|
||||||
import { d3format } from '../../modules/utils';
|
import { d3format } from '../../modules/utils';
|
||||||
import ExploreActionButtons from '../../explore/components/ExploreActionButtons';
|
import ExploreActionButtons from '../../explore/components/ExploreActionButtons';
|
||||||
@ -24,6 +24,7 @@ const propTypes = {
|
|||||||
data: PropTypes.any,
|
data: PropTypes.any,
|
||||||
isChartLoading: PropTypes.bool,
|
isChartLoading: PropTypes.bool,
|
||||||
isStarred: PropTypes.bool.isRequired,
|
isStarred: PropTypes.bool.isRequired,
|
||||||
|
alert: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ChartContainer extends React.Component {
|
class ChartContainer extends React.Component {
|
||||||
@ -139,6 +140,9 @@ class ChartContainer extends React.Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
removeAlert() {
|
||||||
|
this.props.actions.removeChartAlert();
|
||||||
|
}
|
||||||
|
|
||||||
renderVis() {
|
renderVis() {
|
||||||
visMap[this.props.viz_type](this.state.mockSlice).render();
|
visMap[this.props.viz_type](this.state.mockSlice).render();
|
||||||
@ -183,6 +187,16 @@ class ChartContainer extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{this.props.alert &&
|
||||||
|
<Alert bsStyle="warning">
|
||||||
|
{this.props.alert}
|
||||||
|
<i
|
||||||
|
className="fa fa-close pull-right"
|
||||||
|
onClick={this.removeAlert.bind(this)}
|
||||||
|
style={{ cursor: 'pointer' }}
|
||||||
|
/>
|
||||||
|
</Alert>
|
||||||
|
}
|
||||||
{!this.props.isChartLoading &&
|
{!this.props.isChartLoading &&
|
||||||
<div
|
<div
|
||||||
id={this.props.containerId}
|
id={this.props.containerId}
|
||||||
@ -213,6 +227,7 @@ function mapStateToProps(state) {
|
|||||||
data: state.viz.data,
|
data: state.viz.data,
|
||||||
isChartLoading: state.isChartLoading,
|
isChartLoading: state.isChartLoading,
|
||||||
isStarred: state.isStarred,
|
isStarred: state.isStarred,
|
||||||
|
alert: state.chartAlert,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import React, { PropTypes } from 'react';
|
|||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import * as actions from '../actions/exploreActions';
|
import * as actions from '../actions/exploreActions';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Panel } from 'react-bootstrap';
|
import { Panel, Alert } from 'react-bootstrap';
|
||||||
import { visTypes, commonControlPanelSections } from '../stores/store';
|
import { visTypes, commonControlPanelSections } from '../stores/store';
|
||||||
import ControlPanelSection from './ControlPanelSection';
|
import ControlPanelSection from './ControlPanelSection';
|
||||||
import FieldSetRow from './FieldSetRow';
|
import FieldSetRow from './FieldSetRow';
|
||||||
@ -15,6 +15,7 @@ const propTypes = {
|
|||||||
isDatasourceMetaLoading: PropTypes.bool.isRequired,
|
isDatasourceMetaLoading: PropTypes.bool.isRequired,
|
||||||
form_data: PropTypes.object.isRequired,
|
form_data: PropTypes.object.isRequired,
|
||||||
y_axis_zero: PropTypes.any,
|
y_axis_zero: PropTypes.any,
|
||||||
|
alert: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
class ControlPanelsContainer extends React.Component {
|
class ControlPanelsContainer extends React.Component {
|
||||||
@ -53,10 +54,23 @@ class ControlPanelsContainer extends React.Component {
|
|||||||
const viz = visTypes[this.props.form_data.viz_type];
|
const viz = visTypes[this.props.form_data.viz_type];
|
||||||
return viz.fieldOverrides;
|
return viz.fieldOverrides;
|
||||||
}
|
}
|
||||||
|
removeAlert() {
|
||||||
|
this.props.actions.removeControlPanelAlert();
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Panel>
|
<Panel>
|
||||||
|
{this.props.alert &&
|
||||||
|
<Alert bsStyle="warning">
|
||||||
|
{this.props.alert}
|
||||||
|
<i
|
||||||
|
className="fa fa-close pull-right"
|
||||||
|
onClick={this.removeAlert.bind(this)}
|
||||||
|
style={{ cursor: 'pointer' }}
|
||||||
|
/>
|
||||||
|
</Alert>
|
||||||
|
}
|
||||||
{!this.props.isDatasourceMetaLoading &&
|
{!this.props.isDatasourceMetaLoading &&
|
||||||
<div className="scrollbar-container">
|
<div className="scrollbar-container">
|
||||||
<div className="scrollbar-content">
|
<div className="scrollbar-content">
|
||||||
@ -91,6 +105,7 @@ ControlPanelsContainer.propTypes = propTypes;
|
|||||||
|
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
return {
|
return {
|
||||||
|
alert: state.controlPanelAlert,
|
||||||
isDatasourceMetaLoading: state.isDatasourceMetaLoading,
|
isDatasourceMetaLoading: state.isDatasourceMetaLoading,
|
||||||
fields: state.fields,
|
fields: state.fields,
|
||||||
datasource_type: state.datasource_type,
|
datasource_type: state.datasource_type,
|
||||||
|
@ -41,6 +41,9 @@ class ExploreViewContainer extends React.Component {
|
|||||||
|
|
||||||
const params = $.param(data, true);
|
const params = $.param(data, true);
|
||||||
this.updateUrl(params);
|
this.updateUrl(params);
|
||||||
|
// remove alerts when query
|
||||||
|
this.props.actions.removeControlPanelAlert();
|
||||||
|
this.props.actions.removeChartAlert();
|
||||||
}
|
}
|
||||||
|
|
||||||
getHeight() {
|
getHeight() {
|
||||||
@ -85,6 +88,7 @@ class ExploreViewContainer extends React.Component {
|
|||||||
<ChartContainer
|
<ChartContainer
|
||||||
actions={this.props.actions}
|
actions={this.props.actions}
|
||||||
height={this.state.height}
|
height={this.state.height}
|
||||||
|
actions={this.props.actions}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,9 +18,15 @@ export const exploreReducer = function (state, action) {
|
|||||||
|
|
||||||
[actions.FETCH_FAILED]() {
|
[actions.FETCH_FAILED]() {
|
||||||
// todo(alanna) handle failure/error state
|
// todo(alanna) handle failure/error state
|
||||||
return Object.assign({}, state, { isDatasourceMetaLoading: false });
|
return Object.assign({}, state,
|
||||||
|
{
|
||||||
|
isDatasourceMetaLoading: false,
|
||||||
|
controlPanelAlert: action.error,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[actions.REMOVE_CONTROL_PANEL_ALERT]() {
|
||||||
|
return Object.assign({}, state, { controlPanelAlert: null });
|
||||||
},
|
},
|
||||||
|
|
||||||
[actions.SET_FIELD_OPTIONS]() {
|
[actions.SET_FIELD_OPTIONS]() {
|
||||||
const newState = Object.assign({}, state);
|
const newState = Object.assign({}, state);
|
||||||
const optionsByFieldName = action.options;
|
const optionsByFieldName = action.options;
|
||||||
@ -88,7 +94,10 @@ export const exploreReducer = function (state, action) {
|
|||||||
return Object.assign({}, state, { isChartLoading: true });
|
return Object.assign({}, state, { isChartLoading: true });
|
||||||
},
|
},
|
||||||
[actions.CHART_UPDATE_FAILED]() {
|
[actions.CHART_UPDATE_FAILED]() {
|
||||||
return Object.assign({}, state, { isChartLoading: false });
|
return Object.assign({}, state, { isChartLoading: false, chartAlert: action.error });
|
||||||
|
},
|
||||||
|
[actions.REMOVE_CHART_ALERT]() {
|
||||||
|
return Object.assign({}, state, { chartAlert: null });
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
if (action.type in actionHandlers) {
|
if (action.type in actionHandlers) {
|
||||||
|
@ -1294,16 +1294,20 @@ class Superset(BaseSupersetView):
|
|||||||
def update_explore(self, datasource_type, datasource_id):
|
def update_explore(self, datasource_type, datasource_id):
|
||||||
"""Send back new viz on POST request for updating update explore view"""
|
"""Send back new viz on POST request for updating update explore view"""
|
||||||
form_data = json.loads(request.form.get('data'))
|
form_data = json.loads(request.form.get('data'))
|
||||||
error_redirect = '/slicemodelview/list/'
|
|
||||||
try:
|
try:
|
||||||
viz_obj = self.get_viz(
|
viz_obj = self.get_viz(
|
||||||
datasource_type=datasource_type,
|
datasource_type=datasource_type,
|
||||||
datasource_id=datasource_id,
|
datasource_id=datasource_id,
|
||||||
args=form_data)
|
args=form_data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
flash('{}'.format(e), "alert")
|
logging.exception(e)
|
||||||
return redirect(error_redirect)
|
return json_error_response('{}'.format(e))
|
||||||
return viz_obj.get_json()
|
try:
|
||||||
|
viz_json = viz_obj.get_json()
|
||||||
|
except Exception as e:
|
||||||
|
logging.exception(e)
|
||||||
|
return json_error_response(utils.error_msg_from_exception(e))
|
||||||
|
return viz_json
|
||||||
|
|
||||||
@has_access_api
|
@has_access_api
|
||||||
@expose("/explore_json/<datasource_type>/<datasource_id>/")
|
@expose("/explore_json/<datasource_type>/<datasource_id>/")
|
||||||
|
Loading…
Reference in New Issue
Block a user