Skip to content

Commit

Permalink
feat: Makes "Add to dashboard" in Save chart modal paginated (#23634)
Browse files Browse the repository at this point in the history
  • Loading branch information
michael-s-molina authored Apr 18, 2023
1 parent 0c0d2b3 commit d6b6d9e
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 264 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,6 @@ export function interceptDatasets() {
cy.intercept('GET', `/api/v1/dashboard/*/datasets`).as('getDatasets');
}

export function interceptDashboardasync() {
cy.intercept('GET', `/dashboardasync/api/read*`).as('getDashboardasync');
}

export function interceptFilterState() {
cy.intercept('POST', `/api/v1/dashboard/*/filter_state*`).as(
'postFilterState',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@
* under the License.
*/

import {
interceptGet as interceptDashboardGet,
interceptDashboardasync,
} from '../dashboard/utils';
import { interceptGet as interceptDashboardGet } from '../dashboard/utils';

export function interceptFiltering() {
cy.intercept('GET', `/api/v1/chart/?q=*`).as('filtering');
Expand Down Expand Up @@ -61,12 +58,10 @@ export function setFilter(filter: string, option: string) {

export function saveChartToDashboard(dashboardName: string) {
interceptDashboardGet();
interceptDashboardasync();
interceptUpdate();
interceptExploreGet();

cy.getBySel('query-save-button').click();
cy.wait('@getDashboardasync');
cy.getBySelLike('chart-modal').should('be.visible');
cy.get(
'[data-test="save-chart-modal-select-dashboard-form"] [aria-label="Select a dashboard"]',
Expand Down
37 changes: 0 additions & 37 deletions superset-frontend/src/explore/actions/saveModalActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,6 @@ export function setSaveChartModalVisibility(isVisible) {
return { type: SET_SAVE_CHART_MODAL_VISIBILITY, isVisible };
}

export function fetchDashboards(userId) {
return function fetchDashboardsThunk(dispatch) {
return SupersetClient.get({
endpoint: `/dashboardasync/api/read?_flt_0_owners=${userId}`,
})
.then(({ json }) => {
const choices = json.pks.map((id, index) => ({
value: id,
label: (json.result[index] || {}).dashboard_title,
}));
choices.sort((a, b) =>
a.label.localeCompare(b.label, {
sensitivity: 'base',
numeric: true,
}),
);

return dispatch(fetchDashboardsSucceeded(choices));
})
.catch(() => dispatch(fetchDashboardsFailed(userId)));
};
}

export const SAVE_SLICE_FAILED = 'SAVE_SLICE_FAILED';
export function saveSliceFailed() {
return { type: SAVE_SLICE_FAILED };
Expand Down Expand Up @@ -241,20 +218,6 @@ export const createDashboard = dashboardName => async dispatch => {
}
};

// Get existing dashboard from ID
export const getDashboard = dashboardId => async dispatch => {
try {
const response = await SupersetClient.get({
endpoint: `/api/v1/dashboard/${dashboardId}`,
});

return response.json;
} catch (error) {
dispatch(saveSliceFailed());
throw error;
}
};

// Get dashboards the slice is added to
export const getSliceDashboards = slice => async dispatch => {
try {
Expand Down
68 changes: 0 additions & 68 deletions superset-frontend/src/explore/actions/saveModalActions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,48 +23,13 @@ import { ADD_TOAST } from 'src/components/MessageToasts/actions';
import {
createDashboard,
createSlice,
fetchDashboards,
FETCH_DASHBOARDS_FAILED,
FETCH_DASHBOARDS_SUCCEEDED,
getDashboard,
getSliceDashboards,
SAVE_SLICE_FAILED,
SAVE_SLICE_SUCCESS,
updateSlice,
getSlicePayload,
} from './saveModalActions';

/**
* Tests fetchDashboards action
*/

const userId = 1;
const fetchDashboardsEndpoint = `glob:*/dashboardasync/api/read?_flt_0_owners=${1}`;
const mockDashboardData = {
pks: ['id'],
result: [{ id: 'id', dashboard_title: 'dashboard title' }],
};

test('fetchDashboards handles success', async () => {
fetchMock.reset();
fetchMock.get(fetchDashboardsEndpoint, mockDashboardData);
const dispatch = sinon.spy();
await fetchDashboards(userId)(dispatch);
expect(fetchMock.calls(fetchDashboardsEndpoint)).toHaveLength(1);
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(FETCH_DASHBOARDS_SUCCEEDED);
});

test('fetchDashboards handles failure', async () => {
fetchMock.reset();
fetchMock.get(fetchDashboardsEndpoint, { throws: 'error' });
const dispatch = sinon.spy();
await fetchDashboards(userId)(dispatch);
expect(fetchMock.calls(fetchDashboardsEndpoint)).toHaveLength(4); // 3 retries
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(FETCH_DASHBOARDS_FAILED);
});

const sliceId = 10;
const sliceName = 'New chart';
const vizType = 'sample_viz_type';
Expand Down Expand Up @@ -176,7 +141,6 @@ test('createSlice handles failure', async () => {
expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_FAILED);
});

const dashboardId = 14;
const dashboardName = 'New dashboard';
const dashboardResponsePayload = {
id: 14,
Expand Down Expand Up @@ -214,38 +178,6 @@ test('createDashboard handles failure', async () => {
expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_FAILED);
});

/**
* Tests getDashboard action
*/

const getDashboardEndpoint = `glob:*/api/v1/dashboard/${dashboardId}`;
test('getDashboard handles success', async () => {
fetchMock.reset();
fetchMock.get(getDashboardEndpoint, dashboardResponsePayload);
const dispatch = sinon.spy();
const dashboard = await getDashboard(dashboardId)(dispatch);
expect(fetchMock.calls(getDashboardEndpoint)).toHaveLength(1);
expect(dispatch.callCount).toBe(0);
expect(dashboard).toEqual(dashboardResponsePayload);
});

test('getDashboard handles failure', async () => {
fetchMock.reset();
fetchMock.get(getDashboardEndpoint, { throws: sampleError });
const dispatch = sinon.spy();
let caughtError;
try {
await getDashboard(dashboardId)(dispatch);
} catch (error) {
caughtError = error;
}

expect(caughtError).toEqual(sampleError);
expect(fetchMock.calls(getDashboardEndpoint)).toHaveLength(4);
expect(dispatch.callCount).toBe(1);
expect(dispatch.getCall(0).args[0].type).toBe(SAVE_SLICE_FAILED);
});

test('updateSlice with add to new dashboard handles success', async () => {
fetchMock.reset();
fetchMock.put(updateSliceEndpoint, sliceResponsePayload);
Expand Down
24 changes: 6 additions & 18 deletions superset-frontend/src/explore/components/SaveModal.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,8 @@ import React from 'react';
import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { bindActionCreators } from 'redux';
import { Provider } from 'react-redux';

import { shallow } from 'enzyme';
import { styledMount as mount } from 'spec/helpers/theming';
import { Radio } from 'src/components/Radio';
import Button from 'src/components/Button';
import sinon from 'sinon';
Expand All @@ -39,6 +37,7 @@ const initialState = {
chart: {},
saveModal: {
dashboards: [],
isVisible: true,
},
explore: {
datasource: {},
Expand All @@ -57,6 +56,7 @@ const initialState = {
const initialStore = mockStore(initialState);

const defaultProps = {
addDangerToast: jest.fn(),
onHide: () => ({}),
actions: bindActionCreators(saveModalActions, arg => {
if (typeof arg === 'function') {
Expand All @@ -83,6 +83,7 @@ const queryStore = mockStore({
chart: {},
saveModal: {
dashboards: [],
isVisible: true,
},
explore: {
datasource: { name: 'test', type: 'query' },
Expand Down Expand Up @@ -144,8 +145,7 @@ test('renders the right footer buttons when existing dashboard selected', () =>
test('renders the right footer buttons when new dashboard selected', () => {
const wrapper = getWrapper();
wrapper.setState({
saveToDashboardId: null,
newDashboardName: 'Test new dashboard',
dashboard: { label: 'Test new dashboard', value: 'Test new dashboard' },
});
const footerWrapper = shallow(wrapper.find(StyledModal).props().footer);
const saveAndGoDash = footerWrapper
Expand Down Expand Up @@ -186,27 +186,15 @@ test('sets action when overwriting slice', () => {
expect(wrapperForOverwrite.state().action).toBe('overwrite');
});

test('fetches dashboards on component mount', () => {
sinon.spy(defaultProps.actions, 'fetchDashboards');
mount(
<Provider store={initialStore}>
<SaveModal {...defaultProps} />
</Provider>,
);
expect(defaultProps.actions.fetchDashboards.calledOnce).toBe(true);

defaultProps.actions.fetchDashboards.restore();
});

test('updates slice name and selected dashboard', () => {
const wrapper = getWrapper();
const dashboardId = mockEvent.value;

wrapper.instance().onSliceNameChange(mockEvent);
expect(wrapper.state().newSliceName).toBe(mockEvent.target.value);

wrapper.instance().onDashboardSelectChange(dashboardId);
expect(wrapper.state().saveToDashboardId).toBe(dashboardId);
wrapper.instance().onDashboardChange({ value: dashboardId });
expect(wrapper.state().dashboard.value).toBe(dashboardId);
});

test('removes alert', () => {
Expand Down
Loading

0 comments on commit d6b6d9e

Please sign in to comment.