diff --git a/superset/assets/javascripts/components/EditableTitle.jsx b/superset/assets/javascripts/components/EditableTitle.jsx index 26f474420d0ae..9ea64a34912b9 100644 --- a/superset/assets/javascripts/components/EditableTitle.jsx +++ b/superset/assets/javascripts/components/EditableTitle.jsx @@ -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 { (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} /> ))} diff --git a/superset/assets/javascripts/dashboard/components/Header.jsx b/superset/assets/javascripts/dashboard/components/Header.jsx index 740b102f1df9d..a1ab0e8e551d2 100644 --- a/superset/assets/javascripts/dashboard/components/Header.jsx +++ b/superset/assets/javascripts/dashboard/components/Header.jsx @@ -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.'} /> diff --git a/superset/assets/javascripts/dashboard/components/SliceCell.jsx b/superset/assets/javascripts/dashboard/components/SliceCell.jsx index 3cd1334dc0db6..2fbdff31ba030 100644 --- a/superset/assets/javascripts/dashboard/components/SliceCell.jsx +++ b/superset/assets/javascripts/dashboard/components/SliceCell.jsx @@ -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 (