diff --git a/superset-frontend/src/addSlice/AddSliceContainer.tsx b/superset-frontend/src/addSlice/AddSliceContainer.tsx
index 7e9f0a1a2ed54..fd22377314ac8 100644
--- a/superset-frontend/src/addSlice/AddSliceContainer.tsx
+++ b/superset-frontend/src/addSlice/AddSliceContainer.tsx
@@ -19,6 +19,9 @@
import React, { ReactNode } from 'react';
import rison from 'rison';
import { styled, t, SupersetClient, JsonResponse } from '@superset-ui/core';
+import { getUrlParam } from 'src/utils/urlUtils';
+import { URL_PARAMS } from 'src/constants';
+import { isNullish } from 'src/utils/common';
import Button from 'src/components/Button';
import { Select, Steps } from 'src/components';
import { FormLabel } from 'src/components/Form';
@@ -195,10 +198,12 @@ export default class AddSliceContainer extends React.PureComponent<
}
exploreUrl() {
+ const dashboardId = getUrlParam(URL_PARAMS.dashboardId);
const formData = encodeURIComponent(
JSON.stringify({
viz_type: this.state.visType,
datasource: this.state.datasource?.value,
+ ...(!isNullish(dashboardId) && { dashboardId }),
}),
);
return `/superset/explore/?form_data=${formData}`;
diff --git a/superset-frontend/src/constants.ts b/superset-frontend/src/constants.ts
index 8377c5b5f1a98..3d0fd5dd2d591 100644
--- a/superset-frontend/src/constants.ts
+++ b/superset-frontend/src/constants.ts
@@ -71,6 +71,10 @@ export const URL_PARAMS = {
name: 'dataset_id',
type: 'string',
},
+ dashboardId: {
+ name: 'dashboard_id',
+ type: 'string',
+ },
force: {
name: 'force',
type: 'boolean',
diff --git a/superset-frontend/src/dashboard/components/DashboardGrid.jsx b/superset-frontend/src/dashboard/components/DashboardGrid.jsx
index 4be8d6bc05d0f..72f86fff3210c 100644
--- a/superset-frontend/src/dashboard/components/DashboardGrid.jsx
+++ b/superset-frontend/src/dashboard/components/DashboardGrid.jsx
@@ -35,6 +35,7 @@ const propTypes = {
resizeComponent: PropTypes.func.isRequired,
setDirectPathToChild: PropTypes.func.isRequired,
width: PropTypes.number.isRequired,
+ dashboardId: PropTypes.number,
};
const defaultProps = {};
@@ -143,6 +144,7 @@ class DashboardGrid extends React.PureComponent {
editMode,
canEdit,
setEditMode,
+ dashboardId,
} = this.props;
const columnPlusGutterWidth =
(width + GRID_GUTTER_SIZE) / GRID_COLUMN_COUNT;
@@ -167,7 +169,11 @@ class DashboardGrid extends React.PureComponent {
>
}
buttonAction={() => {
- window.open('/chart/add', '_blank', 'noopener noreferrer');
+ window.open(
+ `/chart/add?dashboard_id=${dashboardId}`,
+ '_blank',
+ 'noopener noreferrer',
+ );
}}
image="chart.svg"
/>
@@ -186,7 +192,11 @@ class DashboardGrid extends React.PureComponent {
>
}
buttonAction={() => {
- window.open('/chart/add', '_blank', 'noopener noreferrer');
+ window.open(
+ `/chart/add?dashboard_id=${dashboardId}`,
+ '_blank',
+ 'noopener noreferrer',
+ );
}}
image="chart.svg"
/>
diff --git a/superset-frontend/src/dashboard/components/SliceAdder.jsx b/superset-frontend/src/dashboard/components/SliceAdder.jsx
index eeb83d7c56e46..22f8038ee494c 100644
--- a/superset-frontend/src/dashboard/components/SliceAdder.jsx
+++ b/superset-frontend/src/dashboard/components/SliceAdder.jsx
@@ -58,6 +58,7 @@ const propTypes = {
editMode: PropTypes.bool,
height: PropTypes.number,
filterboxMigrationState: FILTER_BOX_MIGRATION_STATES,
+ dashboardId: PropTypes.number,
};
const defaultProps = {
@@ -276,7 +277,11 @@ class SliceAdder extends React.Component {
buttonStyle="link"
buttonSize="xsmall"
onClick={() =>
- window.open('/chart/add', '_blank', 'noopener noreferrer')
+ window.open(
+ `/chart/add?dashboard_id=${this.props.dashboardId}`,
+ '_blank',
+ 'noopener noreferrer',
+ )
}
>
diff --git a/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx b/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx
index f240d6f525587..d8312cd60a9d0 100644
--- a/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx
+++ b/superset-frontend/src/dashboard/components/gridComponents/Tab.jsx
@@ -150,6 +150,7 @@ class Tab extends React.PureComponent {
isComponentVisible,
canEdit,
setEditMode,
+ dashboardId,
} = this.props;
const shouldDisplayEmptyState = tabComponent.children.length === 0;
@@ -183,7 +184,7 @@ class Tab extends React.PureComponent {
{t('You can')}{' '}
diff --git a/superset-frontend/src/dashboard/components/gridComponents/Tab.test.tsx b/superset-frontend/src/dashboard/components/gridComponents/Tab.test.tsx
index 82aab17014351..d995595c49100 100644
--- a/superset-frontend/src/dashboard/components/gridComponents/Tab.test.tsx
+++ b/superset-frontend/src/dashboard/components/gridComponents/Tab.test.tsx
@@ -294,5 +294,5 @@ test('Render tab content with no children, editMode: true, canEdit: true', () =>
).toBeVisible();
expect(
screen.getByRole('link', { name: 'create a new chart' }),
- ).toHaveAttribute('href', '/chart/add');
+ ).toHaveAttribute('href', '/chart/add?dashboard_id=23');
});
diff --git a/superset-frontend/src/dashboard/containers/DashboardGrid.jsx b/superset-frontend/src/dashboard/containers/DashboardGrid.jsx
index 96688476112cd..ca214fe878765 100644
--- a/superset-frontend/src/dashboard/containers/DashboardGrid.jsx
+++ b/superset-frontend/src/dashboard/containers/DashboardGrid.jsx
@@ -30,6 +30,7 @@ function mapStateToProps({ dashboardState, dashboardInfo }) {
return {
editMode: dashboardState.editMode,
canEdit: dashboardInfo.dash_edit_perm,
+ dashboardId: dashboardInfo.id,
};
}
diff --git a/superset-frontend/src/dashboard/containers/SliceAdder.jsx b/superset-frontend/src/dashboard/containers/SliceAdder.jsx
index 8c02a4a360e7f..078ded23d8ac8 100644
--- a/superset-frontend/src/dashboard/containers/SliceAdder.jsx
+++ b/superset-frontend/src/dashboard/containers/SliceAdder.jsx
@@ -29,6 +29,7 @@ function mapStateToProps(
return {
height: ownProps.height,
userId: dashboardInfo.userId,
+ dashboardId: dashboardInfo.id,
selectedSliceIds: dashboardState.sliceIds,
slices: sliceEntities.slices,
isLoading: sliceEntities.isLoading,
diff --git a/superset-frontend/src/dashboard/stylesheets/dashboard.less b/superset-frontend/src/dashboard/stylesheets/dashboard.less
index 4586913b0ac36..cdbdeb6481579 100644
--- a/superset-frontend/src/dashboard/stylesheets/dashboard.less
+++ b/superset-frontend/src/dashboard/stylesheets/dashboard.less
@@ -19,6 +19,7 @@
/* header has mysterious extra margin */
header.top {
margin-bottom: 2px;
+ z-index: 10;
}
body {
diff --git a/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx b/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx
index fc5703a2adaa2..1bef9da0d2762 100644
--- a/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx
+++ b/superset-frontend/src/explore/components/ExploreViewContainer/index.jsx
@@ -678,12 +678,17 @@ function mapStateToProps(state) {
const chartKey = Object.keys(charts)[0];
const chart = charts[chartKey];
+ let dashboardId = Number(explore.form_data?.dashboardId);
+ if (Number.isNaN(dashboardId)) {
+ dashboardId = undefined;
+ }
+
return {
isDatasourceMetaLoading: explore.isDatasourceMetaLoading,
datasource: explore.datasource,
datasource_type: explore.datasource.type,
datasourceId: explore.datasource_id,
- dashboardId: explore.form_data ? explore.form_data.dashboardId : undefined,
+ dashboardId,
controls: explore.controls,
can_overwrite: !!explore.can_overwrite,
can_add: !!explore.can_add,
diff --git a/superset-frontend/src/explore/components/SaveModal.tsx b/superset-frontend/src/explore/components/SaveModal.tsx
index bf2ed48701393..81e91fecd62c5 100644
--- a/superset-frontend/src/explore/components/SaveModal.tsx
+++ b/superset-frontend/src/explore/components/SaveModal.tsx
@@ -256,8 +256,7 @@ class SaveModal extends React.Component {
checked={this.state.action === 'saveas'}
onChange={() => this.changeAction('saveas')}
>
- {' '}
- {t('Save as ...')}
+ {t('Save as...')}
diff --git a/superset-frontend/src/views/components/MenuRight.tsx b/superset-frontend/src/views/components/MenuRight.tsx
index 1c46f6bcf079d..4c34b883491c4 100644
--- a/superset-frontend/src/views/components/MenuRight.tsx
+++ b/superset-frontend/src/views/components/MenuRight.tsx
@@ -18,7 +18,8 @@
*/
import React, { Fragment, useState, useEffect } from 'react';
import rison from 'rison';
-import { MainNav as Menu } from 'src/components/Menu';
+import { useSelector } from 'react-redux';
+import { Link } from 'react-router-dom';
import {
t,
styled,
@@ -26,12 +27,12 @@ import {
SupersetTheme,
SupersetClient,
} from '@superset-ui/core';
+import { MainNav as Menu } from 'src/components/Menu';
import { Tooltip } from 'src/components/Tooltip';
-import { Link } from 'react-router-dom';
import Icons from 'src/components/Icons';
import findPermission, { isUserAdmin } from 'src/dashboard/util/findPermission';
-import { useSelector } from 'react-redux';
import { UserWithPermissionsAndRoles } from 'src/types/bootstrapTypes';
+import { RootState } from 'src/dashboard/types';
import LanguagePicker from './LanguagePicker';
import DatabaseModal from '../CRUD/data/database/DatabaseModal';
import { uploadUserPerms } from '../CRUD/utils';
@@ -89,6 +90,9 @@ const RightMenu = ({
const user = useSelector(
state => state.user,
);
+ const dashboardId = useSelector(
+ state => state.dashboardInfo?.id,
+ );
const { roles } = user;
const {
@@ -162,7 +166,9 @@ const RightMenu = ({
},
{
label: t('Chart'),
- url: '/chart/add',
+ url: Number.isInteger(dashboardId)
+ ? `/chart/add?dashboard_id=${dashboardId}`
+ : '/chart/add',
icon: 'fa-fw fa-bar-chart',
perm: 'can_write',
view: 'Chart',