Skip to content

Commit

Permalink
Fix #2615. Avoid widgets clear while saving (#2649)
Browse files Browse the repository at this point in the history
  • Loading branch information
offtherailz authored Feb 28, 2018
1 parent b4e1dfc commit 4064803
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 25 deletions.
24 changes: 20 additions & 4 deletions web/client/actions/maps.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const MAP_ERROR = 'MAP_ERROR';
const SAVE_ALL = 'SAVE_ALL';
const DISPLAY_METADATA_EDIT = 'DISPLAY_METADATA_EDIT';
const RESET_UPDATING = 'RESET_UPDATING';
const SAVING_MAP = 'SAVING_MAP';
const SAVE_MAP = 'SAVE_MAP';
const PERMISSIONS_LIST_LOADING = 'PERMISSIONS_LIST_LOADING';
const PERMISSIONS_LIST_LOADED = 'PERMISSIONS_LIST_LOADED';
Expand Down Expand Up @@ -325,9 +326,21 @@ function saveMap(map, resourceId) {
map
};
}
/**
* Performed before start saving a new map
* @memberof actions.maps
* @param {object} metadata
* @return {action} type SAVING_MAP action
*/
function savingMap(metadata) {
return {
type: SAVING_MAP,
metadata
};
}

/**
* performed when want to disaplay/hide the metadata editing window
* performed when want to display/hide the metadata editing window
* @memberof actions.maps
* @param {boolean} displayMetadataEditValue true to display, false to hide
* @return {action} type `DISPLAY_METADATA_EDIT`, with the arguments as they are named
Expand Down Expand Up @@ -591,12 +604,12 @@ function createThumbnail(map, metadataMap, nameThumbnail, dataThumbnail, categor
}

/**
* Save all the metadata and thubnail, if needed.
* Save all the metadata and thumbnail, if needed.
* @memberof actions.maps
* @param {object} map the map object
* @param {object} metadataMap metadata for the map
* @param {string} nameThumbnail the name for the thubnail
* @param {string} dataThumbnail the data to save for the thubnail
* @param {string} nameThumbnail the name for the thumbnail
* @param {string} dataThumbnail the data to save for the thumbnail
* @param {string} categoryThumbnail the category for the thumbnails
* @param {number} resourceIdMap the id of the map
* @param {object} [options] options for the request
Expand Down Expand Up @@ -673,6 +686,7 @@ function deleteThumbnail(resourceId, resourceIdMap, options, reset) {
*/
function createMap(metadata, content, thumbnail, options) {
return (dispatch) => {
dispatch(savingMap(metadata));
GeoStoreApi.createResource(metadata, content, "MAP", options).then((response) => {
let resourceId = response.data;
if (thumbnail && thumbnail.data) {
Expand Down Expand Up @@ -898,6 +912,7 @@ module.exports = {
ATTRIBUTE_UPDATED,
PERMISSIONS_UPDATED,
SAVE_MAP,
SAVING_MAP,
THUMBNAIL_ERROR,
PERMISSIONS_LIST_LOADING,
PERMISSIONS_LIST_LOADED,
Expand Down Expand Up @@ -944,6 +959,7 @@ module.exports = {
permissionsLoading,
permissionsLoaded,
attributeUpdated,
savingMap,
saveMap,
thumbnailError,
createMap,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ describe('widgets builderConfiguration enhancer', () => {
setTimeout(() => {
expect(document.querySelector('.empty-state-container')).toExist();
done();
}, 100);
}, 20);

}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const rxjsConfig = require('recompose/rxjsObservableConfig').default;
setObservableConfig(rxjsConfig);


describe('index enhancer', () => {
describe('wfsTable enhancer', () => {
beforeEach((done) => {
document.body.innerHTML = '<div id="container"></div>';
setTimeout(done);
Expand Down Expand Up @@ -60,7 +60,6 @@ describe('index enhancer', () => {
} else if (props.pages && props.features.length > 0 && props.pages[0] === 40) {
expect(props.pages[1]).toBe(60);
done();

}
}));
ReactDOM.render(<Sink virtualScroll layer={{
Expand Down
5 changes: 3 additions & 2 deletions web/client/epics/__tests__/epicTestUtils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

const Rx = require('rxjs');
const { isFunction } = require('lodash');
const { ActionsObservable, combineEpics } = require('redux-observable');
const TEST_TIMEOUT = "EPICTEST:TIMEOUT";
module.exports = {
Expand All @@ -9,12 +10,12 @@ module.exports = {
* @param {number} count the number of actions to wait (note, the stream)
* @param {object|object[]} action the action(s) to trigger
* @param {function} callback The check function, called after `count` actions received
* @param {Object} [state={}] the state
* @param {Object|function} [state={}] the state or a function that return it
*/
testEpic: (epic, count, action, callback, state = {}) => {
const actions = new Rx.Subject();
const actions$ = new ActionsObservable(actions);
const store = { getState: () => state };
const store = { getState: () => isFunction(state) ? state() : state};
epic(actions$, store)
.take(count)
.toArray()
Expand Down
129 changes: 129 additions & 0 deletions web/client/epics/__tests__/widgets-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Copyright 2018, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
var expect = require('expect');
const { testEpic, addTimeoutEpic, TEST_TIMEOUT } = require('./epicTestUtils');

const {
clearWidgetsOnLocationChange
} = require('../widgets');
const {
CLEAR_WIDGETS
} = require('../../actions/widgets');
const {
savingMap,
mapCreated
} = require('../../actions/maps');
const {
configureMap
} = require('../../actions/config');
const { LOCATION_CHANGE } = require('react-router-redux');

describe('widgets Epics', () => {
it('clearWidgetsOnLocationChange triggers CLEAR_WIDGETS on LOCATION_CHANGE', (done) => {
const checkActions = actions => {
expect(actions.length).toBe(1);
const action = actions[0];
expect(action.type).toBe(CLEAR_WIDGETS);
done();
};
let count = 0;
testEpic(clearWidgetsOnLocationChange,
1,
[configureMap(), { type: LOCATION_CHANGE, payload: {
pathname: "newPath"
}}],
checkActions,
() => {
return count++
? {
routing: {
location: "new"
}
}
: {
routing: {
location: "old"
}
};
});
});
it('clearWidgetsOnLocationChange stops CLEAR_WIDGETS triggers if saving', (done) => {
const checkActions = actions => {
expect(actions.length).toBe(1);
const action = actions[0];
expect(action.type).toBe(TEST_TIMEOUT);
done();
};
let count = 0;
testEpic(addTimeoutEpic(clearWidgetsOnLocationChange, 20),
1,
[
configureMap(),
savingMap(),
{
type: LOCATION_CHANGE,
payload: {
pathname: "newPath"
}
}
],
checkActions,
() => {
return count++
? {
routing: {
location: "new"
}
}
: {
routing: {
location: "old"
}
};
});
});
it('clearWidgetsOnLocationChange restores CLEAR_WIDGETS triggers after save completed', (done) => {
const checkActions = actions => {
expect(actions.length).toBe(1);
const action = actions[0];
expect(action.type).toBe(CLEAR_WIDGETS);
done();
};
let count = 0;
testEpic(clearWidgetsOnLocationChange,
1,
[configureMap(),
savingMap(),
{
type: LOCATION_CHANGE,
payload: {
pathname: "newPath"
}
},
mapCreated(),
{
type: LOCATION_CHANGE, payload: {
pathname: "newPath"
}
}],
checkActions,
() => {
return count++
? {
routing: {
location: "new"
}
}
: {
routing: {
location: "old"
}
};
});
});
});
28 changes: 14 additions & 14 deletions web/client/epics/maps.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ const deleteMapAndAssociatedResourcesEpic = (action$, store) =>
return Rx.Observable.forkJoin(
// delete details
deleteResourceById(thumbnailsId, options),
// delete thumbanil
// delete thumbnail
deleteResourceById(detailsId, options),
// delete map
deleteResourceById(mapId, options)
Expand Down Expand Up @@ -255,19 +255,19 @@ const storeDetailsInfoEpic = (action$, store) =>
return !mapId ?
Rx.Observable.empty() :
Rx.Observable.fromPromise(
GeoStoreApi.getResourceAttribute(mapId, "details")
.then(res => res.data).catch(() => {
return null;
})
)
.switchMap((details) => {
if (!details) {
return Rx.Observable.empty();
}
return Rx.Observable.of(
detailsLoaded(mapId, details)
);
});
GeoStoreApi.getResourceAttribute(mapId, "details")
.then(res => res.data).catch(() => {
return null;
})
)
.switchMap((details) => {
if (!details) {
return Rx.Observable.empty();
}
return Rx.Observable.of(
detailsLoaded(mapId, details)
);
});
});


Expand Down
15 changes: 13 additions & 2 deletions web/client/epics/widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const {EXPORT_CSV, EXPORT_IMAGE, clearWidgets} = require('../actions/widgets');
const {
MAP_CONFIG_LOADED
} = require('../actions/config');
const { MAP_CREATED, SAVING_MAP, MAP_ERROR } = require('../actions/maps');
const {LOCATION_CHANGE} = require('react-router-redux');
const {saveAs} = require('file-saver');
const FileUtils = require('../utils/FileUtils');
Expand All @@ -15,6 +16,16 @@ const outerHTML = (node) => {
parent.appendChild(node.cloneNode(true));
return parent.innerHTML;
};
/**
* Disables action emissions on the stream between SAVING_MAP and MAP_CREATED or MAP_ERROR events.
* This is needed to avoid widget clear when LOCATION_CHANGE because of a map save.
*/
const getValidLocationChange = action$ =>
action$.ofType(SAVING_MAP, MAP_CREATED, MAP_ERROR)
.startWith({type: MAP_CONFIG_LOADED}) // just dummy action to trigger the first switchMap
.switchMap(action => action.type === SAVING_MAP ? Rx.Observable.never() : action$)
.filter(({type} = {}) => type === LOCATION_CHANGE);

module.exports = {
exportWidgetData: action$ =>
action$.ofType(EXPORT_CSV)
Expand All @@ -23,10 +34,10 @@ module.exports = {
csv
], {type: "text/csv"}), title + ".csv")))
.filter( () => false),
clearWidgetsOnlocationChange: (action$, {getState = () => {}} = {}) =>
clearWidgetsOnLocationChange: (action$, {getState = () => {}} = {}) =>
action$.ofType(MAP_CONFIG_LOADED).switchMap( () => {
const location = get(getState(), "routing.location");
return action$.ofType(LOCATION_CHANGE)
return action$.let(getValidLocationChange)
.filter( () => {
const newLocation = get(getState(), "routing.location");
return newLocation !== location;
Expand Down

0 comments on commit 4064803

Please sign in to comment.