• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geosolutions-it / MapStore2 / 12831531306

17 Jan 2025 03:01PM UTC coverage: 77.182% (+0.07%) from 77.115%
12831531306

Pull #10746

github

web-flow
Merge 501dbaeea into 4e4dabc03
Pull Request #10746: Fix #10739 Changing correctly resolutions limits when switching map CRS

30373 of 47156 branches covered (64.41%)

34 of 43 new or added lines in 2 files covered. (79.07%)

126 existing lines in 15 files now uncovered.

37769 of 48935 relevant lines covered (77.18%)

35.14 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.51
/web/client/epics/mapviews.js
1
/*
2
 * Copyright 2022, 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
import { Observable } from 'rxjs';
10
import { isEmpty, isString } from 'lodash';
11
import {
12
    SELECT_VIEW,
13
    UPDATE_VIEWS,
14
    ACTIVATE_VIEWS,
15
    SETUP_VIEWS,
16
    HIDE_VIEWS,
17
    setPreviousView,
18
    updateResources,
19
    hideViews
20
} from '../actions/mapviews';
21
import {
22
    TOGGLE_CONTROL,
23
    SET_CONTROL_PROPERTY,
24
    setControlProperty
25
} from '../actions/controls';
26
import {
27
    removeAdditionalLayer,
28
    updateAdditionalLayer
29
} from '../actions/additionallayers';
30
import { CATALOG_CLOSE } from '../actions/catalog';
31
import { MAP_CONFIG_LOADED } from '../actions/config';
32
import { VISUALIZATION_MODE_CHANGED } from '../actions/maptype';
33
import {
34
    getSelectedMapView,
35
    getResourceById,
36
    getPreviousView,
37
    getMapViewsResources,
38
    isMapViewsHidden,
39
    isMapViewsActive
40
} from '../selectors/mapviews';
41
import { BROWSE_DATA } from '../actions/layers';
42
import { CLOSE_FEATURE_GRID } from '../actions/featuregrid';
43
import { layersSelector, rawGroupsSelector } from '../selectors/layers';
44
import {
45
    isShallowEqualBy
46
} from '../utils/ReselectUtils';
47
import { getResourceFromLayer } from '../api/MapViews';
48

49
import { MAP_VIEWS_LAYERS_OWNER, formatClippingFeatures, isViewLayerChanged, mergeViewGroups, mergeViewLayers } from '../utils/MapViewsUtils';
50
import { isCesium } from '../selectors/maptype';
51
import { getDerivedLayersVisibility } from '../utils/LayersUtils';
52

53
const deepCompare = isShallowEqualBy();
1✔
54

55
const updateResourcesObservable = (view, store) => {
1✔
56
    const state = store.getState();
1✔
57
    const resources = getMapViewsResources(state);
1✔
58
    const { layers = [], mask = {} } = view || {};
1!
59
    return Observable.defer(() => {
1✔
60
        const mapLayers = layersSelector(state);
1✔
61
        const maskLayerResource = isString(mask.resourceId) ? getResourceById(state, mask.resourceId) : undefined;
1!
62
        const maskVectorLayer = mapLayers?.find(layer => layer.id === maskLayerResource?.data?.id);
2✔
63
        const checkResources = [
1✔
64
            {
65
                resource: maskLayerResource,
66
                options: mask,
67
                vectorLayer: maskVectorLayer
68
            },
69
            ...layers
70
                .filter(({ clippingLayerResourceId }) => clippingLayerResourceId)
1✔
71
                .map(({ clippingLayerResourceId }) => {
72
                    const layerResource = isString(clippingLayerResourceId) ? getResourceById(state, clippingLayerResourceId) : undefined;
1!
73
                    const vectorLayer = mapLayers?.find(layer => layer.id === layerResource?.data?.id);
1✔
74
                    return {
1✔
75
                        resource: layerResource,
76
                        vectorLayer
77
                    };
78
                })
79
        ];
80
        return Promise.all(
1✔
81
            checkResources
82
                .filter(({ resource }) => resource)
2✔
83
                .map(({ resource, options, vectorLayer }) =>
84
                    getResourceFromLayer({
2✔
85
                        resourceId: resource.id,
86
                        layer: {
87
                            ...(vectorLayer?.features && {
3✔
88
                                features: vectorLayer?.features
89
                            }),
90
                            ...resource.data
91
                        },
92
                        inverse: options?.inverse,
93
                        offset: options?.offset,
94
                        resources
95
                    })
96
                        .then((response) => response)
2✔
UNCOV
97
                        .catch(() => ({ id: resource.id, error: true }))
×
98
                )
99
        );
100
    });
101
};
102

103
export const updateMapViewsLayers = (action$, store) =>
1✔
104
    action$.ofType(
2✔
105
        SELECT_VIEW,
106
        UPDATE_VIEWS,
107
        ACTIVATE_VIEWS,
108
        HIDE_VIEWS,
109
        SETUP_VIEWS,
110
        MAP_CONFIG_LOADED,
111
        VISUALIZATION_MODE_CHANGED
112
    )
113
        .filter(() => {
114
            const state = store.getState();
2✔
115
            return !isMapViewsHidden(state) && isMapViewsActive(state);
2✔
116
        })
117
        .switchMap((action) => {
118
            const state = store.getState();
2✔
119
            const previousView = getPreviousView(state);
2✔
120
            const currentView =  getSelectedMapView(state);
2✔
121
            const { layers = [], groups = [], mask = {}, id: viewId } = currentView || {};
2✔
122
            const shouldUpdate = !!(
2✔
123
                action.type === VISUALIZATION_MODE_CHANGED
6✔
124
                || !deepCompare(previousView?.layers || [], layers)
4✔
125
                || !deepCompare(previousView?.mask || {}, mask)
2✔
126
                || !deepCompare(previousView?.groups || [], groups)
2✔
127
            );
128
            if (!shouldUpdate) {
2✔
129
                return Observable.of(
1✔
130
                    setPreviousView(currentView)
131
                );
132
            }
133
            const mapLayers = layersSelector(state);
1✔
134
            const mergedGroups = mergeViewGroups(
1✔
135
                rawGroupsSelector(state),
136
                currentView, true);
137
            const mergedLayers = mergeViewLayers(mapLayers, currentView);
1✔
138
            const updatedLayers = getDerivedLayersVisibility(mergedLayers, mergedGroups);
1✔
139
            const changedLayers = updatedLayers.filter((uLayer) => {
1✔
140
                const currentLayer = (mapLayers || []).find(layer => layer.id === uLayer.id);
3!
141
                return isViewLayerChanged(uLayer, currentLayer);
2✔
142
            });
143
            const resources = getMapViewsResources(state);
1✔
144
            return updateResourcesObservable(currentView, store)
1✔
145
                .switchMap((allResources) => {
146
                    const checkedResources = allResources.filter(({ error }) => !error);
2✔
147
                    const updatedResources = checkedResources.filter(resource => resource.updated);
2✔
148
                    const maskLayerResource = isString(mask.resourceId) && checkedResources.find((resource) => resource.id === mask.resourceId);
1✔
149
                    return Observable.of(
1✔
150
                        ...(updatedResources.length > 0 ? [
1!
151
                            updateResources(resources.map((resource) => {
152
                                const { updated, ...updatedResource } = updatedResources.find(uResource => uResource.id === resource.id) || {};
3!
153
                                return !isEmpty(updatedResource) ? updatedResource : resource;
2!
154
                            }))
155
                        ] : []),
156
                        setPreviousView(currentView),
157
                        removeAdditionalLayer({ owner: MAP_VIEWS_LAYERS_OWNER }),
158
                        ...changedLayers
159
                            .map((layer) => {
160
                                const clipPolygonLayerResource = isString(layer.clippingLayerResourceId) && checkedResources.find((resource) => resource.id === layer.clippingLayerResourceId);
2✔
161
                                const clippingPolygon = isString(layer.clippingPolygonFeatureId)
1✔
162
                                    && formatClippingFeatures(clipPolygonLayerResource?.data?.collection?.features)?.find(feature => feature.id === layer.clippingPolygonFeatureId);
1✔
163
                                return updateAdditionalLayer(
1✔
164
                                    layer.id,
165
                                    MAP_VIEWS_LAYERS_OWNER,
166
                                    'override',
167
                                    {
168
                                        ...layer,
169
                                        ...(clippingPolygon && { clippingPolygon })
2✔
170
                                    }
171
                                );
172
                            }),
173
                        ...(isCesium(state) && maskLayerResource?.data?.collection?.features
3!
174
                            ? [updateAdditionalLayer(
175
                                `${viewId}-mask`,
176
                                MAP_VIEWS_LAYERS_OWNER,
177
                                'overlay',
178
                                {
179
                                    id: `${viewId}-mask`,
180
                                    type: 'vector',
181
                                    features: maskLayerResource.data.collection.features,
182
                                    visibility: true,
183
                                    style: {
184
                                        format: 'geostyler',
185
                                        body: {
186
                                            name: '',
187
                                            rules: [
188
                                                {
189
                                                    name: '',
190
                                                    symbolizers: [{
191
                                                        kind: 'Fill',
192
                                                        color: '#ffffff',
193
                                                        fillOpacity: 0,
194
                                                        msClampToGround: true,
195
                                                        msClassificationType: '3d'
196
                                                    }]
197
                                                }
198
                                            ]
199
                                        }
200
                                    }
201
                                }
202
                            )]
203
                            : [])
204
                    );
205
                });
206
        });
207

208
export const removeMapViewsLayersWhenDeactivated = (action$) =>
1✔
209
    action$.ofType(ACTIVATE_VIEWS)
1✔
210
        .filter((action) => !action.active)
1✔
211
        .switchMap(() => {
212
            return Observable.of(
1✔
213
                removeAdditionalLayer({ owner: MAP_VIEWS_LAYERS_OWNER }),
214
                setPreviousView()
215
            );
216
        });
217

218
const controlsToCheck = ['drawer', 'metadataexplorer', 'print', 'queryPanel'];
1✔
219

220
export const closePluginWhenMapViewsActivate = (action$, store) =>
1✔
221
    action$.ofType(ACTIVATE_VIEWS)
1✔
222
        .filter((action) => action.active)
1✔
223
        .switchMap(() => {
224
            const state = store.getState();
1✔
225
            const shouldClosePlugins = !!controlsToCheck.find((key) => !!state?.controls?.[key]?.enabled);
1✔
226
            return shouldClosePlugins
1!
227
                ? Observable.of(
228
                    ...controlsToCheck.map((control) => setControlProperty(control, 'enabled', false))
4✔
229
                )
230
                : Observable.empty();
231
        });
232

233
export const hideMapViewsBasedOnLayoutChanges = (action$, store) =>
1✔
234
    action$.ofType(
2✔
235
        TOGGLE_CONTROL,
236
        SET_CONTROL_PROPERTY,
237
        CATALOG_CLOSE,
238
        MAP_CONFIG_LOADED,
239
        BROWSE_DATA,
240
        CLOSE_FEATURE_GRID
241
    )
242
        .filter((action) =>
243
            [CATALOG_CLOSE, MAP_CONFIG_LOADED, BROWSE_DATA, CLOSE_FEATURE_GRID].includes(action.type)
2✔
244
            || controlsToCheck.includes(action.control)
245
        )
246
        .switchMap(() => {
247
            const state = store.getState();
2✔
248
            const shouldBeHidden = !!controlsToCheck.find((key) => !!state?.controls?.[key]?.enabled)
5✔
249
                || !!state?.featuregrid?.open;
250
            return shouldBeHidden
2✔
251
                ? Observable.of(
252
                    removeAdditionalLayer({ owner: MAP_VIEWS_LAYERS_OWNER }),
253
                    setPreviousView(),
254
                    hideViews(true)
255
                )
256
                : Observable.of(
257
                    hideViews(false)
258
                );
259
        });
260

261
export default {
262
    updateMapViewsLayers,
263
    removeMapViewsLayersWhenDeactivated,
264
    closePluginWhenMapViewsActivate,
265
    hideMapViewsBasedOnLayoutChanges
266
};
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc