Skip to content

Commit 0b16bc2

Browse files
baloolaofftherailz
authored andcommitted
Fix #3359 Timeline delete layer support (#3363)
1 parent 39a8983 commit 0b16bc2

6 files changed

Lines changed: 180 additions & 17 deletions

File tree

web/client/epics/playback.js

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const {
2020
onRangeChanged
2121
} = require('../actions/timeline');
2222

23-
const { changeLayerProperties } = require('../actions/layers');
23+
const { changeLayerProperties, REMOVE_NODE } = require('../actions/layers');
2424

2525
const { error } = require('../actions/notifications');
2626

@@ -29,7 +29,7 @@ const { currentTimeSelector, layersWithTimeDataSelector, layerTimeSequenceSelect
2929
const { LOCATION_CHANGE } = require('react-router-redux');
3030

3131
const { currentFrameSelector, currentFrameValueSelector, lastFrameSelector, playbackRangeSelector, playbackSettingsSelector, frameDurationSelector, statusSelector } = require('../selectors/playback');
32-
const { selectedLayerName, selectedLayerUrl, selectedLayerData, selectedLayerTimeDimensionConfiguration, rangeSelector } = require('../selectors/timeline');
32+
const { selectedLayerName, selectedLayerUrl, selectedLayerData, selectedLayerTimeDimensionConfiguration, rangeSelector, selectedLayerSelector } = require('../selectors/timeline');
3333

3434
const pausable = require('../observables/pausable');
3535
const { wrapStartStop } = require('../observables/epics');
@@ -267,5 +267,16 @@ module.exports = {
267267
};
268268
})()
269269
)
270-
))
270+
)),
271+
272+
playbackStopWhenDeleteLayer: (action$, { getState = () => {} }= {}) =>
273+
action$
274+
.ofType(REMOVE_NODE)
275+
.filter( () =>
276+
!selectedLayerSelector(getState())
277+
&& statusSelector(getState()) === "PLAY"
278+
)
279+
.switchMap( () => Rx.Observable.of(stop()))
280+
281+
271282
};

web/client/epics/timeline.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@ const moment = require('moment');
55

66
const { SELECT_TIME, RANGE_CHANGED, ENABLE_OFFSET, timeDataLoading, rangeDataLoaded, onRangeChanged, selectLayer } = require('../actions/timeline');
77
const { setCurrentTime, UPDATE_LAYER_DIMENSION_DATA, setCurrentOffset } = require('../actions/dimension');
8+
const {REMOVE_NODE} = require('../actions/layers');
89
const {error} = require('../actions/notifications');
910

1011
const {getLayerFromId} = require('../selectors/layers');
11-
const { rangeSelector, selectedLayerName, selectedLayerUrl, isAutoSelectEnabled } = require('../selectors/timeline');
12+
const { rangeSelector, selectedLayerName, selectedLayerUrl, isAutoSelectEnabled, selectedLayerSelector } = require('../selectors/timeline');
1213
const { layerTimeSequenceSelectorCreator, timeDataSelector, offsetTimeSelector, currentTimeSelector, layersWithTimeDataSelector } = require('../selectors/dimension');
1314

1415
const { getNearestDate, roundRangeResolution, isTimeDomainInterval } = require('../utils/TimeUtils');
@@ -158,8 +159,9 @@ module.exports = {
158159
/**
159160
* Initializes the time line
160161
*/
161-
setupTimelineExistingSettings: (action$, { getState = () => { } } = {}) => action$.ofType(UPDATE_LAYER_DIMENSION_DATA)
162-
.exhaustMap(() => isAutoSelectEnabled(getState()) && !selectedLayerName(getState()) && get(layersWithTimeDataSelector(getState()), "[0].id")
162+
setupTimelineExistingSettings: (action$, { getState = () => { } } = {}) => action$.ofType(REMOVE_NODE, UPDATE_LAYER_DIMENSION_DATA)
163+
.exhaustMap(() => isAutoSelectEnabled(getState()) && get(layersWithTimeDataSelector(getState()), "[0].id")
164+
&& !selectedLayerSelector(getState())
163165
? Rx.Observable.of(selectLayer(get(layersWithTimeDataSelector(getState()), "[0].id")))
164166
.concat(
165167
Rx.Observable.of(1).switchMap( () =>

web/client/reducers/__tests__/dimension-test.js

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,49 @@ var dimension = require('../dimension');
1111
const { updateLayerDimensionData } = require('../../actions/dimension');
1212
const { layerDimensionDataSelectorCreator } = require('../../selectors/dimension');
1313

14-
it('dimension updateLayerDimensionData', () => {
15-
const action = updateLayerDimensionData("TEST_LAYER", "time", {
16-
name: "time",
17-
domain: "123--123"
14+
describe('Test the dimension reducer', () => {
15+
it('dimension updateLayerDimensionData', () => {
16+
const action = updateLayerDimensionData("TEST_LAYER", "time", {
17+
name: "time",
18+
domain: "123--123"
19+
});
20+
const state = dimension( undefined, action);
21+
expect(state).toExist();
22+
expect(layerDimensionDataSelectorCreator("TEST_LAYER", "time")( {
23+
dimension: state
24+
}).name).toBe("time");
1825
});
19-
const state = dimension( undefined, action);
20-
expect(state).toExist();
21-
expect(layerDimensionDataSelectorCreator("TEST_LAYER", "time")( {
22-
dimension: state
23-
}).name).toBe("time");
26+
it('removing a layer-related data from dimensin state', () => {
27+
const action = {
28+
type: 'REMOVE_NODE',
29+
node: 'sample1'
30+
};
31+
const initialState = {
32+
currentTime: '00:00:00z',
33+
data: {
34+
dimension1: { sample1: {}, sample2: {}},
35+
dimension2: { sample2: {}}
36+
}
37+
};
38+
const state = dimension(initialState, action);
39+
expect(state).toExist();
40+
expect(layerDimensionDataSelectorCreator('sample1', 'dimension1')( {
41+
dimension: state
42+
})).toNotExist();
43+
expect(layerDimensionDataSelectorCreator('sample2', 'dimension1')( {
44+
dimension: state
45+
})).toExist();
46+
});
47+
it('removing a layer when there is no data in dimensin state', () => {
48+
const action = {
49+
type: 'REMOVE_NODE',
50+
node: 'sample'
51+
};
52+
const initialState = {
53+
currentTime: '00:00:00z'
54+
};
55+
const state = dimension(initialState, action);
56+
expect(state).toExist();
57+
});
58+
2459
});
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright 2018, GeoSolutions Sas.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree.
7+
*/
8+
9+
const timeline = require('../timeline');
10+
const {rangeDataLoaded, selectLayer, timeDataLoading} = require('../../actions/timeline');
11+
const expect = require('expect');
12+
13+
describe('Test the timeline reducer', () => {
14+
it('change the layer histogram and rangedata', () => {
15+
const initialState = {
16+
rangeData: {
17+
layer1: { range: 'old range', histogram: 'old histogram'},
18+
layer2: { }
19+
}
20+
};
21+
const state = timeline(initialState, rangeDataLoaded('layer1', 'new Range', 'new histogram', 'domain'));
22+
expect(state).toExist();
23+
expect(state.rangeData.layer1.range).toBe('new Range');
24+
expect(state.rangeData.layer1.histogram).toBe('new histogram');
25+
expect(state.rangeData.layer1.domain).toBe('domain');
26+
});
27+
it('select a layer', () => {
28+
const initialState = {
29+
rangeData: {
30+
layer1: { range: 'old range', histogram: 'old histogram'},
31+
layer2: { }
32+
}
33+
};
34+
const state = timeline(initialState, selectLayer('layer1'));
35+
expect(state).toExist();
36+
expect(state.selectedLayer).toBe('layer1');
37+
});
38+
it('layer is loading', () => {
39+
const initialState = {
40+
rangeData: {
41+
layer1: { range: 'old range', histogram: 'old histogram'},
42+
layer2: { }
43+
}
44+
};
45+
const state = timeline(initialState, timeDataLoading('layer1', true));
46+
expect(state).toExist();
47+
expect(state.loading.layer1).toBe(true);
48+
});
49+
it('remove a layer', () => {
50+
const initialState = {
51+
rangeData: {
52+
layer1: { range: 'old range', histogram: 'old histogram'},
53+
layer2: { }
54+
}
55+
};
56+
const action = {
57+
type: 'REMOVE_NODE',
58+
node: 'layer1'
59+
};
60+
const state = timeline(initialState, action);
61+
expect(state).toExist();
62+
expect(state.rangeData.layer1).toNotExist();
63+
64+
});
65+
it('remove a layer that is not selected', () => {
66+
const initialState = {
67+
selectedLayer: 'layer2',
68+
rangeData: {
69+
layer1: { range: 'old range', histogram: 'old histogram'},
70+
layer2: { }
71+
}
72+
};
73+
const action = {
74+
type: 'REMOVE_NODE',
75+
node: 'layer1'
76+
};
77+
const state = timeline(initialState, action);
78+
expect(state).toExist();
79+
expect(state.rangeData.layer1).toNotExist();
80+
expect(state.selectedLayer).toBe('layer2');
81+
expect(state.rangeData.layer2).toExist();
82+
});
83+
it('remove a selected layer with no rangeData or loading data', () => {
84+
const initialState = {
85+
selectedLayer: 'layer3',
86+
rangeData: {
87+
layer1: { range: 'old range', histogram: 'old histogram'},
88+
layer2: { }
89+
}
90+
};
91+
const action = {
92+
type: 'REMOVE_NODE',
93+
node: 'layer3'
94+
};
95+
const state = timeline(initialState, action);
96+
expect(state).toExist();
97+
expect(state.rangeData.layer1).toExist();
98+
expect(state.rangeData.layer2).toExist();
99+
expect(state.selectedLayer).toNotExist();
100+
});
101+
});

web/client/reducers/dimension.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
const { UPDATE_LAYER_DIMENSION_DATA, SET_CURRENT_TIME, SET_OFFSET_TIME, MOVE_TIME } = require('../actions/dimension');
2+
const { REMOVE_NODE } = require('../actions/layers');
23
const { set } = require('../utils/ImmutableUtils');
34
const moment = require('moment');
4-
5+
const {mapValues, pickBy } = require('lodash');
56

67
/**
78
* Provide state for current time and dimension info.
@@ -49,6 +50,10 @@ module.exports = (state = {}, action) => {
4950
}
5051
return set(`currentTime`, action.time, state);
5152
}
53+
case REMOVE_NODE: {
54+
const newData = mapValues(state.data, (o) => pickBy(o, (values, keys) => keys !== action.node));
55+
return set(`data`, newData, state);
56+
}
5257
default:
5358
return state;
5459
}

web/client/reducers/timeline.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
const { RANGE_CHANGED } = require('../actions/timeline');
2+
const { REMOVE_NODE } = require('../actions/layers');
23
const { RANGE_DATA_LOADED, LOADING, SELECT_LAYER, MOUSE_EVENT } = require('../actions/timeline');
34
const { set } = require('../utils/ImmutableUtils');
4-
5+
const { assign, pickBy, has } = require('lodash');
56

67
/**
78
* Provides state for the timeline. Example:
@@ -72,6 +73,14 @@ module.exports = (state = {
7273
case MOUSE_EVENT: {
7374
return set('mouseEvent', action.eventData, state);
7475
}
76+
case REMOVE_NODE: {
77+
let newState = state;
78+
return assign({}, state, {
79+
rangeData: has(newState.rangeData, action.node) ? pickBy(newState.rangeData, (values, key) => key !== action.node) : newState.rangeData,
80+
loading: has(newState.rangeData, action.node) ? pickBy(newState.loading, (values, key) => key !== action.node) : newState.loading,
81+
selectedLayer: state.selectedLayer === action.node ? undefined : state.selectedLayer
82+
});
83+
}
7584
default:
7685
return state;
7786
}

0 commit comments

Comments
 (0)