diff --git a/superset-frontend/spec/javascripts/dashboard/components/HeaderActionsDropdown_spec.jsx b/superset-frontend/spec/javascripts/dashboard/components/HeaderActionsDropdown_spec.jsx
index ea3b65ca28eb8..fa60986ceaa64 100644
--- a/superset-frontend/spec/javascripts/dashboard/components/HeaderActionsDropdown_spec.jsx
+++ b/superset-frontend/spec/javascripts/dashboard/components/HeaderActionsDropdown_spec.jsx
@@ -67,7 +67,7 @@ describe('HeaderActionsDropdown', () => {
}
describe('readonly-user', () => {
- const overrideProps = { userCanSave: false };
+ const overrideProps = { userCanSave: false, userCanShare: false };
it('should render the DropdownButton', () => {
const { wrapper } = setup(overrideProps);
@@ -89,9 +89,9 @@ describe('HeaderActionsDropdown', () => {
expect(menu.find(RefreshIntervalModal)).toExist();
});
- it('should render the ShareMenuItems', () => {
+ it('should not render the ShareMenuItems', () => {
const { menu } = setup(overrideProps);
- expect(menu.find(ShareMenuItems)).toExist();
+ expect(menu.find(ShareMenuItems)).not.toExist();
});
it('should not render the CssEditor', () => {
@@ -101,7 +101,7 @@ describe('HeaderActionsDropdown', () => {
});
describe('write-user', () => {
- const overrideProps = { userCanSave: true };
+ const overrideProps = { userCanSave: true, userCanShare: true };
it('should render the DropdownButton', () => {
const { wrapper } = setup(overrideProps);
@@ -135,7 +135,11 @@ describe('HeaderActionsDropdown', () => {
});
describe('write-user-with-edit-mode', () => {
- const overrideProps = { userCanSave: true, editMode: true };
+ const overrideProps = {
+ userCanSave: true,
+ editMode: true,
+ userCanShare: true,
+ };
it('should render the DropdownButton', () => {
const { wrapper } = setup(overrideProps);
diff --git a/superset-frontend/src/dashboard/actions/hydrate.js b/superset-frontend/src/dashboard/actions/hydrate.js
index 7cdaa2396d3ef..8065bf625fe3e 100644
--- a/superset-frontend/src/dashboard/actions/hydrate.js
+++ b/superset-frontend/src/dashboard/actions/hydrate.js
@@ -313,7 +313,17 @@ export const hydrateDashboard = (dashboardData, chartData, datasourcesData) => (
userId: String(user.userId), // legacy, please use state.user instead
dash_edit_perm: getPermissions('can_write', 'Dashboard', roles),
dash_save_perm: getPermissions('can_save_dash', 'Superset', roles),
+ dash_share_perm: getPermissions(
+ 'can_share_dashboard',
+ 'Superset',
+ roles,
+ ),
superset_can_explore: getPermissions('can_explore', 'Superset', roles),
+ superset_can_share: getPermissions(
+ 'can_share_chart',
+ 'Superset',
+ roles,
+ ),
superset_can_csv: getPermissions('can_csv', 'Superset', roles),
slice_can_edit: getPermissions('can_slice', 'Superset', roles),
common: {
diff --git a/superset-frontend/src/dashboard/components/Header.jsx b/superset-frontend/src/dashboard/components/Header.jsx
index 8ad6c57e69ad1..3bc68b0823db7 100644
--- a/superset-frontend/src/dashboard/components/Header.jsx
+++ b/superset-frontend/src/dashboard/components/Header.jsx
@@ -376,6 +376,7 @@ class Header extends React.PureComponent {
} = this.props;
const userCanEdit = dashboardInfo.dash_edit_perm;
+ const userCanShare = dashboardInfo.dash_share_perm;
const userCanSaveAs = dashboardInfo.dash_save_perm;
const refreshLimit =
dashboardInfo.common.conf.SUPERSET_DASHBOARD_PERIODICAL_REFRESH_LIMIT;
@@ -543,6 +544,7 @@ class Header extends React.PureComponent {
editMode={editMode}
hasUnsavedChanges={hasUnsavedChanges}
userCanEdit={userCanEdit}
+ userCanShare={userCanShare}
userCanSave={userCanSaveAs}
isLoading={isLoading}
showPropertiesModal={this.showPropertiesModal}
diff --git a/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx b/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx
index 5d27f1f7f5917..ba255fb3224aa 100644
--- a/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx
+++ b/superset-frontend/src/dashboard/components/HeaderActionsDropdown.jsx
@@ -54,6 +54,7 @@ const propTypes = {
startPeriodicRender: PropTypes.func.isRequired,
editMode: PropTypes.bool.isRequired,
userCanEdit: PropTypes.bool.isRequired,
+ userCanShare: PropTypes.bool.isRequired,
userCanSave: PropTypes.bool.isRequired,
isLoading: PropTypes.bool.isRequired,
layout: PropTypes.object.isRequired,
@@ -192,6 +193,7 @@ class HeaderActionsDropdown extends React.PureComponent {
expandedSlices,
onSave,
userCanEdit,
+ userCanShare,
userCanSave,
isLoading,
refreshLimit,
@@ -241,15 +243,17 @@ class HeaderActionsDropdown extends React.PureComponent {
/>
)}
-
+ {userCanShare && (
+
+ )}
= ({
isExpanded = [],
sliceName = '',
supersetCanExplore = false,
+ supersetCanShare = false,
supersetCanCSV = false,
sliceCanEdit = false,
slice,
@@ -172,6 +174,7 @@ const SliceHeader: FC = ({
exploreChart={exploreChart}
exportCSV={exportCSV}
supersetCanExplore={supersetCanExplore}
+ supersetCanShare={supersetCanShare}
supersetCanCSV={supersetCanCSV}
sliceCanEdit={sliceCanEdit}
componentId={componentId}
diff --git a/superset-frontend/src/dashboard/components/SliceHeaderControls/index.jsx b/superset-frontend/src/dashboard/components/SliceHeaderControls/index.jsx
index edef021377118..650a590ac15b0 100644
--- a/superset-frontend/src/dashboard/components/SliceHeaderControls/index.jsx
+++ b/superset-frontend/src/dashboard/components/SliceHeaderControls/index.jsx
@@ -43,6 +43,7 @@ const propTypes = {
isExpanded: PropTypes.bool,
updatedDttm: PropTypes.number,
supersetCanExplore: PropTypes.bool,
+ supersetCanShare: PropTypes.bool,
supersetCanCSV: PropTypes.bool,
sliceCanEdit: PropTypes.bool,
toggleExpandSlice: PropTypes.func,
@@ -61,6 +62,7 @@ const defaultProps = {
isCached: [],
isExpanded: false,
supersetCanExplore: false,
+ supersetCanShare: false,
supersetCanCSV: false,
sliceCanEdit: false,
};
@@ -72,7 +74,6 @@ const MENU_KEYS = {
EXPLORE_CHART: 'explore_chart',
EXPORT_CSV: 'export_csv',
RESIZE_LABEL: 'resize_label',
- SHARE_CHART: 'share_chart',
DOWNLOAD_AS_IMAGE: 'download_as_image',
};
@@ -188,6 +189,7 @@ class SliceHeaderControls extends React.PureComponent {
addSuccessToast,
addDangerToast,
isFullSize,
+ supersetCanShare,
} = this.props;
const crossFilterItems = getChartMetadataRegistry().items;
const isCrossFilter = Object.entries(crossFilterItems)
@@ -253,18 +255,20 @@ class SliceHeaderControls extends React.PureComponent {
)}
-
+ {supersetCanShare && (
+
+ )}
{resizeLabel}
diff --git a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
index 18cec534189dd..bfe775eb8e89d 100644
--- a/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
+++ b/superset-frontend/src/dashboard/components/gridComponents/Chart.jsx
@@ -65,6 +65,7 @@ const propTypes = {
isExpanded: PropTypes.bool.isRequired,
isCached: PropTypes.bool,
supersetCanExplore: PropTypes.bool.isRequired,
+ supersetCanShare: PropTypes.bool.isRequired,
supersetCanCSV: PropTypes.bool.isRequired,
sliceCanEdit: PropTypes.bool.isRequired,
addSuccessToast: PropTypes.func.isRequired,
@@ -256,6 +257,7 @@ export default class Chart extends React.Component {
toggleExpandSlice,
timeout,
supersetCanExplore,
+ supersetCanShare,
supersetCanCSV,
sliceCanEdit,
addSuccessToast,
@@ -311,6 +313,7 @@ export default class Chart extends React.Component {
updateSliceName={updateSliceName}
sliceName={sliceName}
supersetCanExplore={supersetCanExplore}
+ supersetCanShare={supersetCanShare}
supersetCanCSV={supersetCanCSV}
sliceCanEdit={sliceCanEdit}
componentId={componentId}
diff --git a/superset-frontend/src/dashboard/containers/Chart.jsx b/superset-frontend/src/dashboard/containers/Chart.jsx
index 94f88d3a9ef7f..31c0e3255c755 100644
--- a/superset-frontend/src/dashboard/containers/Chart.jsx
+++ b/superset-frontend/src/dashboard/containers/Chart.jsx
@@ -84,6 +84,7 @@ function mapStateToProps(
editMode: dashboardState.editMode,
isExpanded: !!dashboardState.expandedSlices[id],
supersetCanExplore: !!dashboardInfo.superset_can_explore,
+ supersetCanShare: !!dashboardInfo.superset_can_share,
supersetCanCSV: !!dashboardInfo.superset_can_csv,
sliceCanEdit: !!dashboardInfo.slice_can_edit,
ownCurrentState: dataMask.ownFilters?.[id]?.currentState,
diff --git a/superset/security/manager.py b/superset/security/manager.py
index 1c4419cfc5241..6472af68440ce 100644
--- a/superset/security/manager.py
+++ b/superset/security/manager.py
@@ -556,6 +556,8 @@ def create_custom_permissions(self) -> None:
self.add_permission_view_menu("all_datasource_access", "all_datasource_access")
self.add_permission_view_menu("all_database_access", "all_database_access")
self.add_permission_view_menu("all_query_access", "all_query_access")
+ self.add_permission_view_menu("can_share_dashboard", "Superset")
+ self.add_permission_view_menu("can_share_chart", "Superset")
def create_missing_perms(self) -> None:
"""
diff --git a/tests/security_tests.py b/tests/security_tests.py
index 0648104101cb2..f7e55174db924 100644
--- a/tests/security_tests.py
+++ b/tests/security_tests.py
@@ -670,12 +670,13 @@ def assert_can_gamma(self, perm_set):
self.assertIn(("can_csv", "Superset"), perm_set)
self.assertIn(("can_dashboard", "Superset"), perm_set)
self.assertIn(("can_explore", "Superset"), perm_set)
+ self.assertIn(("can_share_chart", "Superset"), perm_set)
+ self.assertIn(("can_share_dashboard", "Superset"), perm_set)
self.assertIn(("can_explore_json", "Superset"), perm_set)
self.assertIn(("can_fave_dashboards", "Superset"), perm_set)
self.assertIn(("can_fave_slices", "Superset"), perm_set)
self.assertIn(("can_save_dash", "Superset"), perm_set)
self.assertIn(("can_slice", "Superset"), perm_set)
- self.assertIn(("can_explore", "Superset"), perm_set)
self.assertIn(("can_explore_json", "Superset"), perm_set)
self.assertIn(("can_userinfo", "UserDBModelView"), perm_set)
self.assert_can_menu("Databases", perm_set)
@@ -868,6 +869,8 @@ def test_gamma_permissions(self):
self.assertIn(("can_csv", "Superset"), gamma_perm_set)
self.assertIn(("can_dashboard", "Superset"), gamma_perm_set)
self.assertIn(("can_explore", "Superset"), gamma_perm_set)
+ self.assertIn(("can_share_chart", "Superset"), gamma_perm_set)
+ self.assertIn(("can_share_dashboard", "Superset"), gamma_perm_set)
self.assertIn(("can_explore_json", "Superset"), gamma_perm_set)
self.assertIn(("can_fave_dashboards", "Superset"), gamma_perm_set)
self.assertIn(("can_fave_slices", "Superset"), gamma_perm_set)