Allow user update slice title in visualize flow (#3466)

* 1. after user make sql query and visualize, allow user click title to update slice title, and create a new slice at the same time.
2. don't save new title if it is empty. Will still show old title.

* change saveSlice call response and update explore view
This commit is contained in:
Grace Guo 2017-09-25 11:38:29 -07:00 committed by Maxime Beauchemin
parent 5718d6bbaf
commit 3949d39478
8 changed files with 58 additions and 10 deletions

View File

@ -53,6 +53,14 @@ class EditableTitle extends React.PureComponent {
isEditing: false,
});
if (!this.state.title.length) {
this.setState({
title: this.state.lastTitle,
});
return;
}
if (this.state.lastTitle !== this.state.title) {
this.setState({
lastTitle: this.state.title,

View File

@ -150,3 +150,8 @@ export const RENDER_TRIGGERED = 'RENDER_TRIGGERED';
export function renderTriggered() {
return { type: RENDER_TRIGGERED };
}
export const CREATE_NEW_SLICE = 'CREATE_NEW_SLICE';
export function createNewSlice(can_add, can_download, can_overwrite, slice, form_data) {
return { type: CREATE_NEW_SLICE, can_add, can_download, can_overwrite, slice, form_data };
}

View File

@ -153,15 +153,22 @@ class ChartContainer extends React.PureComponent {
this.props.actions.runQuery(this.props.formData, true, this.props.timeout);
}
updateChartTitle(newTitle) {
updateChartTitleOrSaveSlice(newTitle) {
const isNewSlice = !this.props.slice;
const params = {
slice_name: newTitle,
action: 'overwrite',
action: isNewSlice ? 'saveas' : 'overwrite',
};
const saveUrl = getExploreUrl(this.props.formData, 'base', false, null, params);
this.props.actions.saveSlice(saveUrl)
.then(() => {
this.props.actions.updateChartTitle(newTitle);
.then((data) => {
if (isNewSlice) {
this.props.actions.createNewSlice(
data.can_add, data.can_download, data.can_overwrite,
data.slice, data.form_data);
} else {
this.props.actions.updateChartTitle(newTitle);
}
});
}
@ -263,8 +270,8 @@ class ChartContainer extends React.PureComponent {
>
<EditableTitle
title={this.renderChartTitle()}
canEdit={this.props.can_overwrite}
onSaveTitle={this.updateChartTitle.bind(this)}
canEdit={!this.props.slice || this.props.can_overwrite}
onSaveTitle={this.updateChartTitleOrSaveSlice.bind(this)}
/>
{this.props.slice &&

View File

@ -108,7 +108,7 @@ class SaveModal extends React.Component {
this.props.actions.saveSlice(saveUrl)
.then((data) => {
// Go to new slice url or dashboard url
window.location = data;
window.location = data.slice.slice_url;
});
this.props.onHide();
}
@ -185,6 +185,7 @@ class SaveModal extends React.Component {
{t('Add slice to existing dashboard')}
</Radio>
<Select
className="save-modal-selector"
options={this.props.dashboards}
onChange={this.onChange.bind(this, 'saveToDashboardId')}
autoSize={false}

View File

@ -104,3 +104,6 @@
right: 0;
top: 12px;
}
.save-modal-selector {
margin: 10px 0;
}

View File

@ -72,6 +72,15 @@ export default function exploreReducer(state = {}, action) {
[actions.RENDER_TRIGGERED]() {
return Object.assign({}, state, { triggerRender: false });
},
[actions.CREATE_NEW_SLICE]() {
return Object.assign({}, state, {
slice: action.slice,
controls: getControlsState(state, action.form_data),
can_add: action.can_add,
can_download: action.can_download,
can_overwrite: action.can_overwrite,
});
},
};
if (action.type in actionHandlers) {
return actionHandlers[action.type]();

View File

@ -81,5 +81,12 @@ describe('EditableTitle', () => {
// no change
expect(callback.callCount).to.equal(0);
});
it('should not save empty title', () => {
editableWrapper.setState({ title: '' });
editableWrapper.find('input').simulate('blur');
expect(editableWrapper.find('input').props().type).to.equal('button');
expect(editableWrapper.find('input').props().value).to.equal('my title');
expect(callback.callCount).to.equal(0);
});
});
});

View File

@ -1067,6 +1067,8 @@ class Superset(BaseSupersetView):
slice_overwrite_perm = is_owner(slc, g.user)
slice_download_perm = self.can_access('can_download', 'SliceModelView')
form_data['datasource'] = str(datasource_id) + '__' + datasource_type
# handle save or overwrite
action = request.args.get('action')
@ -1078,10 +1080,10 @@ class Superset(BaseSupersetView):
request.args,
slc, slice_add_perm,
slice_overwrite_perm,
slice_download_perm,
datasource_id,
datasource_type)
form_data['datasource'] = str(datasource_id) + '__' + datasource_type
standalone = request.args.get("standalone") == "true"
bootstrap_data = {
"can_add": slice_add_perm,
@ -1137,7 +1139,7 @@ class Superset(BaseSupersetView):
return json_success(payload)
def save_or_overwrite_slice(
self, args, slc, slice_add_perm, slice_overwrite_perm,
self, args, slc, slice_add_perm, slice_overwrite_perm, slice_download_perm,
datasource_id, datasource_type):
"""Save or overwrite a slice"""
slice_name = args.get('slice_name')
@ -1192,7 +1194,13 @@ class Superset(BaseSupersetView):
if request.args.get('goto_dash') == 'true':
return dash.url
else:
return slc.slice_url
return json_success(json.dumps({
"can_add": slice_add_perm,
"can_download": slice_download_perm,
"can_overwrite": is_owner(slc, g.user),
'form_data': form_data,
'slice': slc.data,
}))
def save_slice(self, slc):
session = db.session()