From f83b9793425f4cd256c7472e9325b769394f2eb9 Mon Sep 17 00:00:00 2001 From: leakingoxide <45320817+leakingoxide@users.noreply.github.com> Date: Wed, 24 Apr 2019 23:43:13 +0200 Subject: [PATCH] Store last selected dashboard in sessionStorage (#7181) * Store last selected dashboard in sessionStorage * Fix tests --- .../explore/components/SaveModal_spec.jsx | 30 +++++++++++-------- .../src/explore/components/SaveModal.jsx | 14 ++++++++- superset/views/core.py | 1 + 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/superset/assets/spec/javascripts/explore/components/SaveModal_spec.jsx b/superset/assets/spec/javascripts/explore/components/SaveModal_spec.jsx index e7be94db96..d334688a4d 100644 --- a/superset/assets/spec/javascripts/explore/components/SaveModal_spec.jsx +++ b/superset/assets/spec/javascripts/explore/components/SaveModal_spec.jsx @@ -19,6 +19,7 @@ import React from 'react'; import configureStore from 'redux-mock-store'; import thunk from 'redux-thunk'; +import { bindActionCreators } from 'redux'; import { shallow, mount } from 'enzyme'; import { Modal, Button, Radio } from 'react-bootstrap'; @@ -52,7 +53,12 @@ describe('SaveModal', () => { const defaultProps = { onHide: () => ({}), - actions: saveModalActions, + actions: bindActionCreators(saveModalActions, (arg) => { + if (typeof arg === 'function') { + return arg(jest.fn); + } + return arg; + }), form_data: { datasource: '107__table' }, }; const mockEvent = { @@ -108,15 +114,15 @@ describe('SaveModal', () => { it('componentDidMount', () => { sinon.spy(SaveModal.prototype, 'componentDidMount'); - sinon.spy(saveModalActions, 'fetchDashboards'); + sinon.spy(defaultProps.actions, 'fetchDashboards'); mount(, { context: { store }, }); expect(SaveModal.prototype.componentDidMount.calledOnce).toBe(true); - expect(saveModalActions.fetchDashboards.calledOnce).toBe(true); + expect(defaultProps.actions.fetchDashboards.calledOnce).toBe(true); SaveModal.prototype.componentDidMount.restore(); - saveModalActions.fetchDashboards.restore(); + defaultProps.actions.fetchDashboards.restore(); }); it('onChange', () => { @@ -139,7 +145,7 @@ describe('SaveModal', () => { .callsFake(() => ({ url: 'mockURL', payload: defaultProps.form_data })); sinon - .stub(saveModalActions, 'saveSlice') + .stub(defaultProps.actions, 'saveSlice') .callsFake(() => Promise.resolve({ data: { dashboard: '/mock/', slice: { slice_url: '/mock/' } } }), ); @@ -147,13 +153,13 @@ describe('SaveModal', () => { afterEach(() => { exploreUtils.getExploreUrlAndPayload.restore(); - saveModalActions.saveSlice.restore(); + defaultProps.actions.saveSlice.restore(); }); it('should save slice', () => { const wrapper = getWrapper(); wrapper.instance().saveOrOverwrite(true); - const args = saveModalActions.saveSlice.getCall(0).args; + const args = defaultProps.actions.saveSlice.getCall(0).args; expect(args[0]).toEqual(defaultProps.form_data); }); @@ -167,7 +173,7 @@ describe('SaveModal', () => { wrapper.setState({ saveToDashboardId }); wrapper.instance().saveOrOverwrite(true); - const args = saveModalActions.saveSlice.getCall(0).args; + const args = defaultProps.actions.saveSlice.getCall(0).args; expect(args[1].save_to_dashboard_id).toBe(saveToDashboardId); }); @@ -181,7 +187,7 @@ describe('SaveModal', () => { wrapper.setState({ newDashboardName }); wrapper.instance().saveOrOverwrite(true); - const args = saveModalActions.saveSlice.getCall(0).args; + const args = defaultProps.actions.saveSlice.getCall(0).args; expect(args[1].new_dashboard_name).toBe(newDashboardName); }); }); @@ -251,13 +257,13 @@ describe('SaveModal', () => { }); it('removeAlert', () => { - sinon.spy(saveModalActions, 'removeSaveModalAlert'); + sinon.spy(defaultProps.actions, 'removeSaveModalAlert'); const wrapper = getWrapper(); wrapper.setProps({ alert: 'old alert' }); wrapper.instance().removeAlert(); - expect(saveModalActions.removeSaveModalAlert.callCount).toBe(1); + expect(defaultProps.actions.removeSaveModalAlert.callCount).toBe(1); expect(wrapper.state().alert).toBeNull(); - saveModalActions.removeSaveModalAlert.restore(); + defaultProps.actions.removeSaveModalAlert.restore(); }); }); diff --git a/superset/assets/src/explore/components/SaveModal.jsx b/superset/assets/src/explore/components/SaveModal.jsx index 37e633d4ba..908f2922e3 100644 --- a/superset/assets/src/explore/components/SaveModal.jsx +++ b/superset/assets/src/explore/components/SaveModal.jsx @@ -54,7 +54,14 @@ class SaveModal extends React.Component { }; } componentDidMount() { - this.props.actions.fetchDashboards(this.props.userId); + this.props.actions.fetchDashboards(this.props.userId).then(() => { + const dashboardIds = this.props.dashboards.map(dashboard => dashboard.value); + let recentDashboard = sessionStorage.getItem('save_chart_recent_dashboard'); + recentDashboard = recentDashboard && parseInt(recentDashboard, 10); + if (recentDashboard !== null && dashboardIds.indexOf(recentDashboard) !== -1) { + this.setState({ saveToDashboardId: recentDashboard, addToDash: 'existing' }); + } + }); } onChange(name, event) { switch (name) { @@ -125,6 +132,11 @@ class SaveModal extends React.Component { sliceParams.goto_dash = gotodash; this.props.actions.saveSlice(this.props.form_data, sliceParams).then(({ data }) => { + if (data.dashboard_id === null) { + sessionStorage.removeItem('save_chart_recent_dashboard'); + } else { + sessionStorage.setItem('save_chart_recent_dashboard', data.dashboard_id); + } // Go to new slice url or dashboard url if (gotodash) { window.location = supersetURL(data.dashboard); diff --git a/superset/views/core.py b/superset/views/core.py index 04fff7b109..569708ab7b 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -1489,6 +1489,7 @@ class Superset(BaseSupersetView): 'can_overwrite': is_owner(slc, g.user), 'form_data': slc.form_data, 'slice': slc.data, + 'dashboard_id': dash.id if dash else None, } if request.args.get('goto_dash') == 'true':