Skip to content

Commit

Permalink
feat(dashboard): Display a loading spinner while dashboard is being s…
Browse files Browse the repository at this point in the history
…aved (#22588)
  • Loading branch information
kgabryje committed Jan 10, 2023
1 parent 8bf6d80 commit 399f6e3
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 3 deletions.
14 changes: 14 additions & 0 deletions superset-frontend/src/dashboard/actions/dashboardState.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,9 +203,20 @@ export function setOverrideConfirm(overwriteConfirmMetadata) {
};
}

export const SAVE_DASHBOARD_STARTED = 'SAVE_DASHBOARD_STARTED';
export function saveDashboardStarted() {
return { type: SAVE_DASHBOARD_STARTED };
}

export const SAVE_DASHBOARD_FINISHED = 'SAVE_DASHBOARD_FINISHED';
export function saveDashboardFinished() {
return { type: SAVE_DASHBOARD_FINISHED };
}

export function saveDashboardRequest(data, id, saveType) {
return (dispatch, getState) => {
dispatch({ type: UPDATE_COMPONENTS_PARENTS_LIST });
dispatch(saveDashboardStarted());

const { dashboardFilters, dashboardLayout } = getState();
const layout = dashboardLayout.present;
Expand Down Expand Up @@ -291,6 +302,7 @@ export function saveDashboardRequest(data, id, saveType) {
const chartConfiguration = handleChartConfiguration();
dispatch(setChartConfiguration(chartConfiguration));
}
dispatch(saveDashboardFinished());
dispatch(addSuccessToast(t('This dashboard was saved successfully.')));
return response;
};
Expand Down Expand Up @@ -322,6 +334,7 @@ export function saveDashboardRequest(data, id, saveType) {
if (lastModifiedTime) {
dispatch(saveDashboardRequestSuccess(lastModifiedTime));
}
dispatch(saveDashboardFinished());
// redirect to the new slug or id
window.history.pushState(
{ event: 'dashboard_properties_changed' },
Expand All @@ -347,6 +360,7 @@ export function saveDashboardRequest(data, id, saveType) {
if (typeof message === 'string' && message === 'Forbidden') {
errorText = t('You do not have permission to edit this dashboard');
}
dispatch(saveDashboardFinished());
dispatch(addDangerToast(errorText));
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { waitFor } from '@testing-library/react';

import {
removeSliceFromDashboard,
SAVE_DASHBOARD_STARTED,
saveDashboardRequest,
SET_OVERRIDE_CONFIRM,
} from 'src/dashboard/actions/dashboardState';
Expand Down Expand Up @@ -104,10 +105,11 @@ describe('dashboardState actions', () => {
});
const thunk = saveDashboardRequest(newDashboardData, 1, 'save_dash');
thunk(dispatch, getState);
expect(dispatch.callCount).toBe(1);
expect(dispatch.callCount).toBe(2);
expect(dispatch.getCall(0).args[0].type).toBe(
UPDATE_COMPONENTS_PARENTS_LIST,
);
expect(dispatch.getCall(1).args[0].type).toBe(SAVE_DASHBOARD_STARTED);
});

it('should post dashboard data with updated redux state', () => {
Expand Down Expand Up @@ -162,10 +164,10 @@ describe('dashboardState actions', () => {
expect(getStub.callCount).toBe(1);
expect(postStub.callCount).toBe(0);
await waitFor(() =>
expect(dispatch.getCall(1).args[0].type).toBe(SET_OVERRIDE_CONFIRM),
expect(dispatch.getCall(2).args[0].type).toBe(SET_OVERRIDE_CONFIRM),
);
expect(
dispatch.getCall(1).args[0].overwriteConfirmMetadata.dashboardId,
dispatch.getCall(2).args[0].overwriteConfirmMetadata.dashboardId,
).toBe(id);
});

Expand Down
1 change: 1 addition & 0 deletions superset-frontend/src/dashboard/actions/hydrate.js
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,7 @@ export const hydrateDashboard =
editMode: canEdit && editMode,
isPublished: dashboard.published,
hasUnsavedChanges: false,
dashboardIsSaving: false,
maxUndoHistoryExceeded: false,
lastModifiedTime: dashboard.changed_on,
isRefreshing: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,20 @@ describe('DashboardBuilder', () => {
(setDirectPathToChild as jest.Mock).mockReset();
});

it('should not display a loading spinner when saving is not in progress', () => {
const { queryByAltText } = setup();

expect(queryByAltText('Loading...')).not.toBeInTheDocument();
});

it('should display a loading spinner when saving is in progress', async () => {
const { findByAltText } = setup({
dashboardState: { dashboardIsSaving: true },
});

expect(await findByAltText('Loading...')).toBeVisible();
});

describe('when nativeFiltersEnabled', () => {
beforeEach(() => {
(isFeatureEnabled as jest.Mock).mockImplementation(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
const canEdit = useSelector<RootState, boolean>(
({ dashboardInfo }) => dashboardInfo.dash_edit_perm,
);
const dashboardIsSaving = useSelector<RootState, boolean>(
({ dashboardState }) => dashboardState.dashboardIsSaving,
);
const nativeFilters = useSelector((state: RootState) => state.nativeFilters);
const focusedFilterId = nativeFilters?.focusedFilterId;
const fullSizeChartId = useSelector<RootState, number | null>(
Expand Down Expand Up @@ -533,6 +536,15 @@ const DashboardBuilder: FC<DashboardBuilderProps> = () => {
</StyledDashboardContent>
</div>
</StyledContent>
{dashboardIsSaving && (
<Loading
css={css`
&& {
position: fixed;
}
`}
/>
)}
</StyledDiv>
);
};
Expand Down
14 changes: 14 additions & 0 deletions superset-frontend/src/dashboard/reducers/dashboardState.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ import {
ON_FILTERS_REFRESH_SUCCESS,
SET_DATASETS_STATUS,
SET_OVERRIDE_CONFIRM,
SAVE_DASHBOARD_STARTED,
SAVE_DASHBOARD_FINISHED,
} from '../actions/dashboardState';
import { HYDRATE_DASHBOARD } from '../actions/hydrate';

Expand Down Expand Up @@ -111,6 +113,18 @@ export default function dashboardStateReducer(state = {}, action) {
[ON_CHANGE]() {
return { ...state, hasUnsavedChanges: true };
},
[SAVE_DASHBOARD_STARTED]() {
return {
...state,
dashboardIsSaving: true,
};
},
[SAVE_DASHBOARD_FINISHED]() {
return {
...state,
dashboardIsSaving: false,
};
},
[ON_SAVE]() {
return {
...state,
Expand Down
1 change: 1 addition & 0 deletions superset-frontend/src/dashboard/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export type DashboardState = {
isRefreshing: boolean;
isFiltersRefreshing: boolean;
hasUnsavedChanges: boolean;
dashboardIsSaving: boolean;
colorScheme: string;
sliceIds: number[];
directPathLastUpdated: number;
Expand Down

0 comments on commit 399f6e3

Please sign in to comment.