mirror of https://github.com/apache/superset.git
remove extra call to get_viz in explorev2 (#1812)
* Not working errors * Remove update_explore endpoint, only update explore endpoints in reducer on query * Change scroll to auto and make container reponse to height: * Remove update_explore endpoint * Remove can_update_explore perm
This commit is contained in:
parent
699602d1c5
commit
9f7486f402
|
@ -98,41 +98,24 @@ export function setFieldValue(datasource_type, key, value, label) {
|
||||||
return { type: SET_FIELD_VALUE, datasource_type, key, value, label };
|
return { type: SET_FIELD_VALUE, datasource_type, key, value, label };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UPDATE_CHART = 'UPDATE_CHART';
|
|
||||||
export function updateChart(viz) {
|
|
||||||
return { type: UPDATE_CHART, viz };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CHART_UPDATE_STARTED = 'CHART_UPDATE_STARTED';
|
export const CHART_UPDATE_STARTED = 'CHART_UPDATE_STARTED';
|
||||||
export function chartUpdateStarted() {
|
export function chartUpdateStarted() {
|
||||||
return { type: CHART_UPDATE_STARTED };
|
return { type: CHART_UPDATE_STARTED };
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CHART_UPDATE_FAILED = 'CHART_UPDATE_FAILED ';
|
export const CHART_UPDATE_SUCCEEDED = 'CHART_UPDATE_SUCCEEDED';
|
||||||
|
export function chartUpdateSucceeded(query) {
|
||||||
|
return { type: CHART_UPDATE_SUCCEEDED, query };
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CHART_UPDATE_FAILED = 'CHART_UPDATE_FAILED';
|
||||||
export function chartUpdateFailed(error) {
|
export function chartUpdateFailed(error) {
|
||||||
return { type: CHART_UPDATE_FAILED, error };
|
return { type: CHART_UPDATE_FAILED, error };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateExplore(datasource_type, datasource_id, form_data) {
|
export const UPDATE_EXPLORE_ENDPOINTS = 'UPDATE_EXPLORE_ENDPOINTS';
|
||||||
return function (dispatch) {
|
export function updateExploreEndpoints(jsonUrl, csvUrl, standaloneUrl) {
|
||||||
dispatch(chartUpdateStarted());
|
return { type: UPDATE_EXPLORE_ENDPOINTS, jsonUrl, csvUrl, standaloneUrl };
|
||||||
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.responseJSON.error));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const REMOVE_CONTROL_PANEL_ALERT = 'REMOVE_CONTROL_PANEL_ALERT';
|
export const REMOVE_CONTROL_PANEL_ALERT = 'REMOVE_CONTROL_PANEL_ALERT';
|
||||||
|
|
|
@ -26,13 +26,13 @@ const propTypes = {
|
||||||
json_endpoint: PropTypes.string.isRequired,
|
json_endpoint: PropTypes.string.isRequired,
|
||||||
csv_endpoint: PropTypes.string.isRequired,
|
csv_endpoint: PropTypes.string.isRequired,
|
||||||
standalone_endpoint: PropTypes.string.isRequired,
|
standalone_endpoint: PropTypes.string.isRequired,
|
||||||
query: PropTypes.string.isRequired,
|
query: PropTypes.string,
|
||||||
column_formats: PropTypes.object,
|
column_formats: PropTypes.object,
|
||||||
data: PropTypes.any,
|
data: PropTypes.any,
|
||||||
chartStatus: PropTypes.bool,
|
chartStatus: PropTypes.string,
|
||||||
isStarred: PropTypes.bool.isRequired,
|
isStarred: PropTypes.bool.isRequired,
|
||||||
chartUpdateStartTime: PropTypes.string.isRequired,
|
chartUpdateStartTime: PropTypes.number.isRequired,
|
||||||
chartUpdateEndTime: PropTypes.string.isRequired,
|
chartUpdateEndTime: PropTypes.number,
|
||||||
alert: PropTypes.string,
|
alert: PropTypes.string,
|
||||||
table_name: PropTypes.string,
|
table_name: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
@ -55,8 +55,16 @@ class ChartContainer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps) {
|
componentWillReceiveProps(nextProps) {
|
||||||
|
if (nextProps.chartStatus !== this.props.chartStatus
|
||||||
|
|| nextProps.height !== this.props.height) {
|
||||||
this.setState({ mockSlice: this.getMockedSliceObject(nextProps) });
|
this.setState({ mockSlice: this.getMockedSliceObject(nextProps) });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate(nextProps) {
|
||||||
|
return (nextProps.chartStatus !== this.props.chartStatus
|
||||||
|
|| nextProps.height !== this.props.height);
|
||||||
|
}
|
||||||
|
|
||||||
componentDidUpdate() {
|
componentDidUpdate() {
|
||||||
this.renderVis();
|
this.renderVis();
|
||||||
|
@ -114,8 +122,10 @@ class ChartContainer extends React.Component {
|
||||||
{}
|
{}
|
||||||
),
|
),
|
||||||
|
|
||||||
done: () => {
|
done: (payload) => {
|
||||||
// finished rendering callback
|
// finished rendering callback
|
||||||
|
// Todo: end timer and chartLoading set to success
|
||||||
|
props.actions.chartUpdateSucceeded(payload.query);
|
||||||
},
|
},
|
||||||
|
|
||||||
clearError: () => {
|
clearError: () => {
|
||||||
|
@ -166,16 +176,19 @@ class ChartContainer extends React.Component {
|
||||||
</Alert>
|
</Alert>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (this.props.chartStatus === 'loading') {
|
const loading = this.props.chartStatus === 'loading';
|
||||||
return (<img alt="loading" width="25" src="/static/assets/images/loading.gif" />);
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
|
<div>
|
||||||
|
{loading &&
|
||||||
|
<img alt="loading" width="25" src="/static/assets/images/loading.gif" />
|
||||||
|
}
|
||||||
<div
|
<div
|
||||||
id={this.props.containerId}
|
id={this.props.containerId}
|
||||||
ref={(ref) => { this.chartContainerRef = ref; }}
|
ref={(ref) => { this.chartContainerRef = ref; }}
|
||||||
className={this.props.viz_type}
|
className={this.props.viz_type}
|
||||||
style={{ overflowX: 'scroll' }}
|
style={{ overflowX: 'auto' }}
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +232,7 @@ class ChartContainer extends React.Component {
|
||||||
endTime={this.props.chartUpdateEndTime}
|
endTime={this.props.chartUpdateEndTime}
|
||||||
isRunning={this.props.chartStatus === 'loading'}
|
isRunning={this.props.chartStatus === 'loading'}
|
||||||
state={CHART_STATUS_MAP[this.props.chartStatus]}
|
state={CHART_STATUS_MAP[this.props.chartStatus]}
|
||||||
style={{ 'font-size': '10px', 'margin-right': '5px' }}
|
style={{ fontSize: '10px', marginRight: '5px' }}
|
||||||
/>
|
/>
|
||||||
<ExploreActionButtons
|
<ExploreActionButtons
|
||||||
slice={this.state.mockSlice}
|
slice={this.state.mockSlice}
|
||||||
|
|
|
@ -8,9 +8,7 @@ import ControlPanelsContainer from './ControlPanelsContainer';
|
||||||
import SaveModal from './SaveModal';
|
import SaveModal from './SaveModal';
|
||||||
import QueryAndSaveBtns from '../../explore/components/QueryAndSaveBtns';
|
import QueryAndSaveBtns from '../../explore/components/QueryAndSaveBtns';
|
||||||
import { autoQueryFields } from '../stores/fields';
|
import { autoQueryFields } from '../stores/fields';
|
||||||
import { getParamObject } from '../exploreUtils';
|
import { getExploreUrl } from '../exploreUtils';
|
||||||
|
|
||||||
const $ = require('jquery');
|
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
form_data: React.PropTypes.object.isRequired,
|
form_data: React.PropTypes.object.isRequired,
|
||||||
|
@ -48,11 +46,12 @@ class ExploreViewContainer extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onQuery(form_data) {
|
onQuery(form_data) {
|
||||||
const data = getParamObject(form_data, this.props.datasource_type);
|
this.props.actions.chartUpdateStarted();
|
||||||
this.queryFormData(data);
|
history.pushState(
|
||||||
|
{},
|
||||||
const params = $.param(data, true);
|
document.title,
|
||||||
this.updateUrl(params);
|
getExploreUrl(form_data, this.props.datasource_type)
|
||||||
|
);
|
||||||
// remove alerts when query
|
// remove alerts when query
|
||||||
this.props.actions.removeControlPanelAlert();
|
this.props.actions.removeControlPanelAlert();
|
||||||
this.props.actions.removeChartAlert();
|
this.props.actions.removeChartAlert();
|
||||||
|
@ -63,17 +62,6 @@ class ExploreViewContainer extends React.Component {
|
||||||
return `${window.innerHeight - navHeight}px`;
|
return `${window.innerHeight - navHeight}px`;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateUrl(params) {
|
|
||||||
const baseUrl =
|
|
||||||
`/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.form_data.datasource, data);
|
|
||||||
}
|
|
||||||
handleResize() {
|
handleResize() {
|
||||||
this.setState({ height: this.getHeight() });
|
this.setState({ height: this.getHeight() });
|
||||||
}
|
}
|
||||||
|
@ -119,7 +107,6 @@ 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>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/* eslint camelcase: 0 */
|
/* eslint camelcase: 0 */
|
||||||
|
const $ = require('jquery');
|
||||||
function formatFilters(filters) {
|
function formatFilters(filters) {
|
||||||
// outputs an object of url params of filters
|
// outputs an object of url params of filters
|
||||||
// prefix can be 'flt' or 'having'
|
// prefix can be 'flt' or 'having'
|
||||||
|
@ -22,7 +23,7 @@ export function getParamObject(form_data, datasource_type, saveNewSlice) {
|
||||||
};
|
};
|
||||||
Object.keys(form_data).forEach((field) => {
|
Object.keys(form_data).forEach((field) => {
|
||||||
// filter out null fields
|
// filter out null fields
|
||||||
if (form_data[field] !== null && field !== 'datasource'
|
if (form_data[field] !== null && field !== 'datasource' && field !== 'filters'
|
||||||
&& !(saveNewSlice && field === 'slice_name')) {
|
&& !(saveNewSlice && field === 'slice_name')) {
|
||||||
data[field] = form_data[field];
|
data[field] = form_data[field];
|
||||||
}
|
}
|
||||||
|
@ -31,3 +32,21 @@ export function getParamObject(form_data, datasource_type, saveNewSlice) {
|
||||||
Object.assign(data, filterParams);
|
Object.assign(data, filterParams);
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getExploreUrl(form_data, datasource_type, endpoint = 'base') {
|
||||||
|
const data = getParamObject(form_data, datasource_type);
|
||||||
|
const params = `${datasource_type}/` +
|
||||||
|
`${form_data.datasource}/?${$.param(data, true)}`;
|
||||||
|
switch (endpoint) {
|
||||||
|
case 'base':
|
||||||
|
return `/superset/explore/${params}`;
|
||||||
|
case 'json':
|
||||||
|
return `/superset/explore_json/${params}`;
|
||||||
|
case 'csv':
|
||||||
|
return `/superset/explore/${params}&csv=true`;
|
||||||
|
case 'standalone':
|
||||||
|
return `/superset/explore/${params}&standalone=true`;
|
||||||
|
default:
|
||||||
|
return `/superset/explore/${params}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
|
/* eslint camelcase: 0 */
|
||||||
import { defaultFormData } from '../stores/store';
|
import { defaultFormData } from '../stores/store';
|
||||||
import * as actions from '../actions/exploreActions';
|
import * as actions from '../actions/exploreActions';
|
||||||
import { addToArr, removeFromArr, alterInArr } from '../../../utils/reducerUtils';
|
import { addToArr, removeFromArr, alterInArr } from '../../../utils/reducerUtils';
|
||||||
import { now } from '../../modules/dates';
|
import { now } from '../../modules/dates';
|
||||||
|
import { getExploreUrl } from '../exploreUtils';
|
||||||
|
|
||||||
export const exploreReducer = function (state, action) {
|
export const exploreReducer = function (state, action) {
|
||||||
const actionHandlers = {
|
const actionHandlers = {
|
||||||
|
@ -105,29 +107,35 @@ export const exploreReducer = function (state, action) {
|
||||||
{ viz: Object.assign({}, state.viz, { form_data: newFormData }) }
|
{ viz: Object.assign({}, state.viz, { form_data: newFormData }) }
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[actions.UPDATE_CHART]() {
|
[actions.CHART_UPDATE_SUCCEEDED]() {
|
||||||
const vizUpdates = {
|
const vizUpdates = {
|
||||||
column_formats: action.viz.column_formats,
|
query: action.query,
|
||||||
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,
|
|
||||||
};
|
};
|
||||||
const chartUpdateEndTime = now();
|
|
||||||
return Object.assign(
|
return Object.assign(
|
||||||
{},
|
{},
|
||||||
state,
|
state,
|
||||||
{
|
{
|
||||||
viz: Object.assign({}, state.viz, vizUpdates),
|
|
||||||
chartStatus: 'success',
|
chartStatus: 'success',
|
||||||
chartUpdateEndTime,
|
viz: Object.assign({}, state.viz, vizUpdates),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[actions.CHART_UPDATE_STARTED]() {
|
[actions.CHART_UPDATE_STARTED]() {
|
||||||
const chartUpdateStartTime = now();
|
const chartUpdateStartTime = now();
|
||||||
|
const form_data = Object.assign({}, state.viz.form_data);
|
||||||
|
const datasource_type = state.datasource_type;
|
||||||
|
const vizUpdates = {
|
||||||
|
json_endpoint: getExploreUrl(form_data, datasource_type, 'json'),
|
||||||
|
csv_endpoint: getExploreUrl(form_data, datasource_type, 'csv'),
|
||||||
|
standalone_endpoint:
|
||||||
|
getExploreUrl(form_data, datasource_type, 'standalone'),
|
||||||
|
};
|
||||||
return Object.assign({}, state,
|
return Object.assign({}, state,
|
||||||
{ chartStatus: 'loading', chartUpdateEndTime: null, chartUpdateStartTime });
|
{
|
||||||
|
chartStatus: 'loading',
|
||||||
|
chartUpdateEndTime: null,
|
||||||
|
chartUpdateStartTime,
|
||||||
|
viz: Object.assign({}, state.viz, vizUpdates),
|
||||||
|
});
|
||||||
},
|
},
|
||||||
[actions.CHART_UPDATE_FAILED]() {
|
[actions.CHART_UPDATE_FAILED]() {
|
||||||
const chartUpdateEndTime = now();
|
const chartUpdateEndTime = now();
|
||||||
|
|
|
@ -1364,28 +1364,6 @@ class Superset(BaseSupersetView):
|
||||||
viz_obj = self.get_viz(slice_id)
|
viz_obj = self.get_viz(slice_id)
|
||||||
return redirect(viz_obj.get_url(**request.args))
|
return redirect(viz_obj.get_url(**request.args))
|
||||||
|
|
||||||
@log_this
|
|
||||||
@has_access_api
|
|
||||||
@expose(
|
|
||||||
"/update_explore/<datasource_type>/<datasource_id>/", 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'))
|
|
||||||
try:
|
|
||||||
viz_obj = self.get_viz(
|
|
||||||
datasource_type=datasource_type,
|
|
||||||
datasource_id=datasource_id,
|
|
||||||
args=form_data)
|
|
||||||
except Exception as e:
|
|
||||||
logging.exception(e)
|
|
||||||
return json_error_response('{}'.format(e))
|
|
||||||
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>/")
|
||||||
def explore_json(self, datasource_type, datasource_id):
|
def explore_json(self, datasource_type, datasource_id):
|
||||||
|
|
|
@ -265,7 +265,6 @@ class SupersetTestCase(unittest.TestCase):
|
||||||
self.assertIn(('can_fave_slices', 'Superset'), gamma_perm_set)
|
self.assertIn(('can_fave_slices', 'Superset'), gamma_perm_set)
|
||||||
self.assertIn(('can_save_dash', 'Superset'), gamma_perm_set)
|
self.assertIn(('can_save_dash', 'Superset'), gamma_perm_set)
|
||||||
self.assertIn(('can_slice', 'Superset'), gamma_perm_set)
|
self.assertIn(('can_slice', 'Superset'), gamma_perm_set)
|
||||||
self.assertIn(('can_update_explore', 'Superset'), gamma_perm_set)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -95,25 +95,6 @@ class CoreTests(SupersetTestCase):
|
||||||
assert_admin_view_menus_in('Alpha', self.assertNotIn)
|
assert_admin_view_menus_in('Alpha', self.assertNotIn)
|
||||||
assert_admin_view_menus_in('Gamma', 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):
|
def test_save_slice(self):
|
||||||
self.login(username='admin')
|
self.login(username='admin')
|
||||||
slice_name = "Energy Sankey"
|
slice_name = "Energy Sankey"
|
||||||
|
|
Loading…
Reference in New Issue