allow user update slice name in dashboard view (#3467)

- if current user is allowed to edit dashboard, we will allow this user to edit slice name.
- show different tooltip given allowed/not-allowed to update slice name.
- user will click slice name and update.
- after user submit edit, if he doesn't have right to alter slice, server-side will return error message to client-side. Slice name will not be changed or saved.
- will show notification after save slice name.
This commit is contained in:
Grace Guo 2017-09-25 11:37:12 -07:00 committed by Maxime Beauchemin
parent f3146ef6f9
commit 5718d6bbaf
6 changed files with 78 additions and 10 deletions

View File

@ -6,7 +6,8 @@ import { t } from '../locales';
const propTypes = {
title: PropTypes.string,
canEdit: PropTypes.bool,
onSaveTitle: PropTypes.func.isRequired,
onSaveTitle: PropTypes.func,
noPermitTooltip: PropTypes.string,
};
const defaultProps = {
title: t('Title'),
@ -26,6 +27,14 @@ class EditableTitle extends React.PureComponent {
this.handleChange = this.handleChange.bind(this);
this.handleKeyPress = this.handleKeyPress.bind(this);
}
componentWillReceiveProps(nextProps) {
if (nextProps.title !== this.state.title) {
this.setState({
lastTitle: this.state.title,
title: nextProps.title,
});
}
}
handleClick() {
if (!this.props.canEdit) {
return;
@ -72,7 +81,8 @@ class EditableTitle extends React.PureComponent {
<span className="editable-title">
<TooltipWrapper
label="title"
tooltip={this.props.canEdit ? t('click to edit title') : t('You don\'t have the rights to alter this title.')}
tooltip={this.props.canEdit ? t('click to edit title') :
this.props.noPermitTooltip || t('You don\'t have the rights to alter this title.')}
>
<input
required

View File

@ -1,9 +1,11 @@
/* global notify */
import React from 'react';
import PropTypes from 'prop-types';
import { Responsive, WidthProvider } from 'react-grid-layout';
import $ from 'jquery';
import SliceCell from './SliceCell';
import { getExploreUrl } from '../../explore/exploreUtils';
require('react-grid-layout/css/styles.css');
require('react-resizable/css/styles.css');
@ -72,6 +74,42 @@ class GridLayout extends React.Component {
this.props.dashboard.onChange();
}
updateSliceName(sliceId, sliceName) {
const index = this.state.slices.map(slice => (slice.slice_id)).indexOf(sliceId);
if (index === -1) {
return;
}
// update slice_name first
const oldSlices = this.state.slices;
const currentSlice = this.state.slices[index];
const updated = Object.assign({},
this.state.slices[index], { slice_name: sliceName });
const updatedSlices = this.state.slices.slice();
updatedSlices[index] = updated;
this.setState({ slices: updatedSlices });
const sliceParams = {};
sliceParams.slice_id = currentSlice.slice_id;
sliceParams.action = 'overwrite';
sliceParams.slice_name = sliceName;
const saveUrl = getExploreUrl(currentSlice.form_data, 'base', false, null, sliceParams);
$.ajax({
url: saveUrl,
type: 'GET',
success: () => {
notify.success('This slice name was saved successfully.');
},
error: () => {
// if server-side reject the overwrite action,
// revert to old state
this.setState({ slices: oldSlices });
notify.error('You don\'t have the rights to alter this slice');
},
});
}
serialize() {
return this.state.layout.map(reactPos => ({
slice_id: reactPos.i,
@ -107,6 +145,8 @@ class GridLayout extends React.Component {
slice={slice}
removeSlice={this.removeSlice.bind(this, slice.slice_id)}
expandedSlices={this.props.dashboard.metadata.expanded_slices}
updateSliceName={this.props.dashboard.dash_edit_perm ?
this.updateSliceName.bind(this) : null}
/>
</div>
))}

View File

@ -30,6 +30,7 @@ class Header extends React.PureComponent {
title={dashboard.dashboard_title}
canEdit={dashboard.dash_save_perm}
onSaveTitle={this.handleSaveTitle}
noPermitTooltip={'You don\'t have the rights to alter this dashboard.'}
/>
<span is class="favstar" class_name="Dashboard" obj_id={dashboard.id} />
</h1>

View File

@ -4,22 +4,35 @@ import PropTypes from 'prop-types';
import { t } from '../../locales';
import { getExploreUrl } from '../../explore/exploreUtils';
import EditableTitle from '../../components/EditableTitle';
const propTypes = {
slice: PropTypes.object.isRequired,
removeSlice: PropTypes.func.isRequired,
updateSliceName: PropTypes.func,
expandedSlices: PropTypes.object,
};
function SliceCell({ expandedSlices, removeSlice, slice }) {
const SliceCell = ({ expandedSlices, removeSlice, slice, updateSliceName }) => {
const onSaveTitle = (newTitle) => {
if (updateSliceName) {
updateSliceName(slice.slice_id, newTitle);
}
};
return (
<div className="slice-cell" id={`${slice.slice_id}-cell`}>
<div className="chart-header">
<div className="row">
<div className="col-md-12 header">
<span>{slice.slice_name}</span>
<div className="row chart-header">
<div className="col-md-12">
<div className="header">
<EditableTitle
title={slice.slice_name}
canEdit={!!updateSliceName}
onSaveTitle={onSaveTitle}
noPermitTooltip={'You don\'t have the rights to alter this dashboard.'}
/>
</div>
<div className="col-md-12 chart-controls">
<div className="chart-controls">
<div id={'controls_' + slice.slice_id} className="pull-right">
<a title={t('Move chart')} data-toggle="tooltip">
<i className="fa fa-arrows drag" />
@ -97,7 +110,7 @@ function SliceCell({ expandedSlices, removeSlice, slice }) {
</div>
</div>
);
}
};
SliceCell.propTypes = propTypes;

View File

@ -16,7 +16,6 @@ div.widget .chart-controls {
position: absolute;
z-index: 100;
right: 0;
left: 0;
top: 5px;
padding: 5px 5px;
opacity: 0.75;
@ -117,6 +116,7 @@ div.widget .chart-controls {
.chart-header .header {
font-size: 16px;
margin: 0 -10px;
}
.ace_gutter {
z-index: 0;

View File

@ -1069,6 +1069,10 @@ class Superset(BaseSupersetView):
# handle save or overwrite
action = request.args.get('action')
if action == 'overwrite' and not slice_overwrite_perm:
return json_error_response("You don't have the rights to alter this slice", status=400)
if action in ('saveas', 'overwrite'):
return self.save_or_overwrite_slice(
request.args,