@@ -202,7 +211,7 @@ class SliceAdder extends React.Component {
this.state.filteredSlices.length > 0 && (
(
@@ -96,13 +100,19 @@ class SliceHeaderControls extends React.PureComponent {
)}
-
+ {this.props.sliceCanEdit && (
+
+ )}
-
+ {this.props.supersetCanExplore && (
+
+ )}
);
diff --git a/superset/assets/src/dashboard/components/gridComponents/Chart.jsx b/superset/assets/src/dashboard/components/gridComponents/Chart.jsx
index 4742d71bfb8c9..9f8d723e03f13 100644
--- a/superset/assets/src/dashboard/components/gridComponents/Chart.jsx
+++ b/superset/assets/src/dashboard/components/gridComponents/Chart.jsx
@@ -29,6 +29,8 @@ const propTypes = {
removeFilter: PropTypes.func.isRequired,
editMode: PropTypes.bool.isRequired,
isExpanded: PropTypes.bool.isRequired,
+ supersetCanExplore: PropTypes.bool.isRequired,
+ sliceCanEdit: PropTypes.bool.isRequired,
};
// we use state + shouldComponentUpdate() logic to prevent perf-wrecking
@@ -155,6 +157,8 @@ class Chart extends React.Component {
sliceName,
toggleExpandSlice,
timeout,
+ supersetCanExplore,
+ sliceCanEdit,
} = this.props;
const { width } = this.state;
@@ -179,6 +183,8 @@ class Chart extends React.Component {
exportCSV={this.exportCSV}
updateSliceName={updateSliceName}
sliceName={sliceName}
+ supersetCanExplore={supersetCanExplore}
+ sliceCanEdit={sliceCanEdit}
/>
{/*
diff --git a/superset/assets/src/dashboard/containers/Chart.jsx b/superset/assets/src/dashboard/containers/Chart.jsx
index 61627d21fc44e..107e6c778ff1d 100644
--- a/superset/assets/src/dashboard/containers/Chart.jsx
+++ b/superset/assets/src/dashboard/containers/Chart.jsx
@@ -40,6 +40,8 @@ function mapStateToProps(
}),
editMode: dashboardState.editMode,
isExpanded: !!dashboardState.expandedSlices[id],
+ supersetCanExplore: !!dashboardInfo.superset_can_explore,
+ sliceCanEdit: !!dashboardInfo.slice_can_edit,
};
}
diff --git a/superset/assets/src/dashboard/containers/DashboardHeader.jsx b/superset/assets/src/dashboard/containers/DashboardHeader.jsx
index fe7e7bb84eb14..19be06cd0e85d 100644
--- a/superset/assets/src/dashboard/containers/DashboardHeader.jsx
+++ b/superset/assets/src/dashboard/containers/DashboardHeader.jsx
@@ -10,8 +10,9 @@ import {
saveFaveStar,
fetchCharts,
startPeriodicRender,
+ updateCss,
onChange,
- saveDashboard,
+ saveDashboardRequest,
setMaxUndoHistoryExceeded,
maxUndoHistoryToast,
} from '../actions/dashboardState';
@@ -42,6 +43,7 @@ function mapStateToProps({
(undoableLayout.present[DASHBOARD_HEADER_ID] || {}).meta || {}
).text,
expandedSlices: dashboard.expandedSlices,
+ css: dashboard.css,
charts,
userId: dashboardInfo.userId,
isStarred: !!dashboard.isStarred,
@@ -66,8 +68,9 @@ function mapDispatchToProps(dispatch) {
fetchCharts,
startPeriodicRender,
updateDashboardTitle,
+ updateCss,
onChange,
- onSave: saveDashboard,
+ onSave: saveDashboardRequest,
setMaxUndoHistoryExceeded,
maxUndoHistoryToast,
},
diff --git a/superset/assets/src/dashboard/reducers/dashboardState.js b/superset/assets/src/dashboard/reducers/dashboardState.js
index 2d44399827b44..25234943cac91 100644
--- a/superset/assets/src/dashboard/reducers/dashboardState.js
+++ b/superset/assets/src/dashboard/reducers/dashboardState.js
@@ -14,13 +14,13 @@ import {
TOGGLE_BUILDER_PANE,
TOGGLE_EXPAND_SLICE,
TOGGLE_FAVE_STAR,
- UPDATE_DASHBOARD_TITLE,
+ UPDATE_CSS,
} from '../actions/dashboardState';
export default function dashboardStateReducer(state = {}, action) {
const actionHandlers = {
- [UPDATE_DASHBOARD_TITLE]() {
- return { ...state, title: action.title };
+ [UPDATE_CSS]() {
+ return { ...state, css: action.css };
},
[ADD_SLICE]() {
const updatedSliceIds = new Set(state.sliceIds);
diff --git a/superset/assets/src/dashboard/reducers/getInitialState.js b/superset/assets/src/dashboard/reducers/getInitialState.js
index b20904349bd33..f129bf79bbf25 100644
--- a/superset/assets/src/dashboard/reducers/getInitialState.js
+++ b/superset/assets/src/dashboard/reducers/getInitialState.js
@@ -58,10 +58,7 @@ export default function(bootstrapData) {
future: [],
};
- delete dashboard.position_json;
- delete dashboard.css;
-
- // creat a lookup to sync layout names with slice names
+ // create a lookup to sync layout names with slice names
const chartIdToLayoutId = {};
Object.values(layout).forEach(layoutComponent => {
if (layoutComponent.type === CHART_TYPE) {
@@ -124,6 +121,8 @@ export default function(bootstrapData) {
userId: user_id,
dash_edit_perm: dashboard.dash_edit_perm,
dash_save_perm: dashboard.dash_save_perm,
+ superset_can_explore: dashboard.superset_can_explore,
+ slice_can_edit: dashboard.slice_can_edit,
common,
},
dashboardState: {
@@ -131,6 +130,7 @@ export default function(bootstrapData) {
refresh: false,
filters,
expandedSlices: dashboard.metadata.expanded_slices || {},
+ css: dashboard.css || '',
editMode: false,
showBuilderPane: false,
hasUnsavedChanges: false,
diff --git a/superset/assets/src/dashboard/stylesheets/builder.less b/superset/assets/src/dashboard/stylesheets/builder.less
index 7c14056054e04..ecf192ec1e87f 100644
--- a/superset/assets/src/dashboard/stylesheets/builder.less
+++ b/superset/assets/src/dashboard/stylesheets/builder.less
@@ -46,9 +46,14 @@
/* @TODO remove upon new theme */
.btn.btn-primary {
background: @almost-black !important;
+ border-color: @almost-black;
color: white !important;
}
+.dropdown-toggle.btn.btn-primary .caret {
+ color: white;
+}
+
.background--transparent {
background-color: transparent;
}
diff --git a/superset/assets/src/dashboard/stylesheets/dashboard.less b/superset/assets/src/dashboard/stylesheets/dashboard.less
index 8d8c8be8c37c1..57567860dba62 100644
--- a/superset/assets/src/dashboard/stylesheets/dashboard.less
+++ b/superset/assets/src/dashboard/stylesheets/dashboard.less
@@ -38,6 +38,29 @@
}
}
+.dashboard .dashboard-header {
+ #save-dash-split-button {
+ border-radius: 0;
+ margin-left: -8px;
+ height: 30px;
+ width: 30px;
+
+ &.btn.btn-primary {
+ border-left-color: white;
+ }
+
+ .caret {
+ position: absolute;
+ top: 24px;
+ left: 3px;
+ }
+
+ & + .dropdown-menu.dropdown-menu-right {
+ min-width: unset;
+ }
+ }
+}
+
.dashboard .chart-header,
.dashboard .dashboard-header {
.dropdown-menu {
@@ -63,7 +86,7 @@
padding: 0 16px;
position: absolute;
top: 0;
- right: -22px;
+ right: -16px; //increase the click-able area for the button
&:hover {
cursor: pointer;
@@ -80,12 +103,17 @@
.is-cached & {
background-color: @pink;
- margin-right: 6px;
}
.vertical-dots-container & {
display: block;
}
+
+ a[role="menuitem"] & {
+ width: 8px;
+ height: 8px;
+ margin-right: 8px;
+ }
}
diff --git a/superset/assets/src/dashboard/util/constants.js b/superset/assets/src/dashboard/util/constants.js
index d682687623cf1..ef2c8bb45d634 100644
--- a/superset/assets/src/dashboard/util/constants.js
+++ b/superset/assets/src/dashboard/util/constants.js
@@ -41,3 +41,7 @@ export const DANGER_TOAST = 'DANGER_TOAST';
// undo-redo
export const UNDO_LIMIT = 50;
+
+// save dash options
+export const SAVE_TYPE_OVERWRITE = 'overwrite';
+export const SAVE_TYPE_NEWDASHBOARD = 'newDashboard';
diff --git a/superset/assets/src/modules/utils.js b/superset/assets/src/modules/utils.js
index eb937bb0a6595..c5d4e75450ae9 100644
--- a/superset/assets/src/modules/utils.js
+++ b/superset/assets/src/modules/utils.js
@@ -198,7 +198,7 @@ export function slugify(string) {
export function getAjaxErrorMsg(error) {
const respJSON = error.responseJSON;
- return (respJSON && respJSON.message) ? respJSON.message :
+ return (respJSON && respJSON.error) ? respJSON.error :
error.responseText;
}