diff --git a/superset-frontend/spec/javascripts/dashboard/reducers/dashboardState_spec.js b/superset-frontend/spec/javascripts/dashboard/reducers/dashboardState_spec.js index 6fdd11cd73..14bb108d85 100644 --- a/superset-frontend/spec/javascripts/dashboard/reducers/dashboardState_spec.js +++ b/superset-frontend/spec/javascripts/dashboard/reducers/dashboardState_spec.js @@ -131,19 +131,22 @@ describe('dashboardState reducer', () => { expect(result.updatedColorScheme).toBe(false); }); - it('should set lastModifiedTime on save', () => { - const lastModifiedTime = new Date().getTime() / 1000; + it('should reset lastModifiedTime on save', () => { + const initTime = new Date().getTime() / 1000; dashboardStateReducer( { - lastModifiedTime, + lastModifiedTime: initTime, }, {}, ); + const lastModifiedTime = Math.round(new Date().getTime() / 1000); expect( - dashboardStateReducer({ hasUnsavedChanges: true }, { type: ON_SAVE }) - .lastModifiedTime, - ).toBeGreaterThanOrEqual(lastModifiedTime); + dashboardStateReducer( + { hasUnsavedChanges: true }, + { type: ON_SAVE, lastModifiedTime }, + ).lastModifiedTime, + ).toBeGreaterThanOrEqual(initTime); }); it('should clear the focused filter field', () => { diff --git a/superset-frontend/src/dashboard/actions/dashboardState.js b/superset-frontend/src/dashboard/actions/dashboardState.js index 67f475e061..a499fa9a8e 100644 --- a/superset-frontend/src/dashboard/actions/dashboardState.js +++ b/superset-frontend/src/dashboard/actions/dashboardState.js @@ -152,8 +152,8 @@ export function onChange() { } export const ON_SAVE = 'ON_SAVE'; -export function onSave() { - return { type: ON_SAVE }; +export function onSave(lastModifiedTime) { + return { type: ON_SAVE, lastModifiedTime }; } export const SET_REFRESH_FREQUENCY = 'SET_REFRESH_FREQUENCY'; @@ -161,9 +161,9 @@ export function setRefreshFrequency(refreshFrequency, isPersistent = false) { return { type: SET_REFRESH_FREQUENCY, refreshFrequency, isPersistent }; } -export function saveDashboardRequestSuccess() { +export function saveDashboardRequestSuccess(lastModifiedTime) { return dispatch => { - dispatch(onSave()); + dispatch(onSave(lastModifiedTime)); // clear layout undo history dispatch(UndoActionCreators.clearHistory()); }; @@ -199,7 +199,7 @@ export function saveDashboardRequest(data, id, saveType) { }, }) .then(response => { - dispatch(saveDashboardRequestSuccess()); + dispatch(saveDashboardRequestSuccess(response.json.last_modified_time)); dispatch(addSuccessToast(t('This dashboard was saved successfully.'))); return response; }) diff --git a/superset-frontend/src/dashboard/reducers/dashboardInfo.js b/superset-frontend/src/dashboard/reducers/dashboardInfo.js index 5c48a54356..01346d7a4f 100644 --- a/superset-frontend/src/dashboard/reducers/dashboardInfo.js +++ b/superset-frontend/src/dashboard/reducers/dashboardInfo.js @@ -25,7 +25,8 @@ export default function dashboardStateReducer(state = {}, action) { return { ...state, ...action.newInfo, - lastModifiedTime: new Date().getTime() / 1000, + // server-side compare last_modified_time in second level + lastModifiedTime: Math.round(new Date().getTime() / 1000), }; default: return state; diff --git a/superset-frontend/src/dashboard/reducers/dashboardState.js b/superset-frontend/src/dashboard/reducers/dashboardState.js index b852533545..b948e2c4a3 100644 --- a/superset-frontend/src/dashboard/reducers/dashboardState.js +++ b/superset-frontend/src/dashboard/reducers/dashboardState.js @@ -106,8 +106,8 @@ export default function dashboardStateReducer(state = {}, action) { maxUndoHistoryExceeded: false, editMode: false, updatedColorScheme: false, - // server-side compare last_modified_time in second level - lastModifiedTime: new Date().getTime() / 1000, + // server-side returns last_modified_time for latest change + lastModifiedTime: action.lastModifiedTime, }; }, [SET_UNSAVED_CHANGES]() { diff --git a/superset/views/core.py b/superset/views/core.py index 0157cb0747..97eef1fdff 100755 --- a/superset/views/core.py +++ b/superset/views/core.py @@ -1085,8 +1085,14 @@ class Superset(BaseSupersetView): # pylint: disable=too-many-public-methods DashboardDAO.set_dash_metadata(dash, data) session.merge(dash) session.commit() + + # get updated changed_on + dash = session.query(Dashboard).get(dashboard_id) + last_modified_time = dash.changed_on.replace(microsecond=0).timestamp() session.close() - return json_success(json.dumps({"status": "SUCCESS"})) + return json_success( + json.dumps({"status": "SUCCESS", "last_modified_time": last_modified_time,}) + ) @api @has_access_api