• 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

37.65
/web/client/components/mapviews/MapViewsSupport.jsx
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 React, { useRef, Suspense, lazy, useState, useCallback, useEffect, useReducer } from 'react';
10
import {
11
    ButtonGroup,
12
    Glyphicon,
13
    Checkbox,
14
    ButtonToolbar
15
} from 'react-bootstrap';
16
import uuid from 'uuid';
17
import max from 'lodash/max';
18
import undoable from 'redux-undo';
19
import identity from 'lodash/identity';
20

21
import MapViewsList from './MapViewsList';
22
import MapViewsProgressBar from './MapViewsProgressBar';
23
import FormControl from '../misc/DebouncedFormControl';
24
import { DefaultViewValues } from '../../utils/MapViewsUtils';
25
import Message from '../I18N/Message';
26
import Loader from '../misc/Loader';
27
import ButtonMS from '../misc/Button';
28
import tooltip from '../misc/enhancers/tooltip';
29
import { MapLibraries } from '../../utils/MapTypeUtils';
30
const Button = tooltip(ButtonMS);
1✔
31

32
const mapViewSupports = {
1✔
33
    [MapLibraries.LEAFLET]: lazy(() => import(/* webpackChunkName: 'supports/leafletMapViews' */ '../map/leaflet/MapViewsSupport')),
×
34
    [MapLibraries.OPENLAYERS]: lazy(() => import(/* webpackChunkName: 'supports/olMapViews' */ '../map/openlayers/MapViewsSupport')),
×
35
    [MapLibraries.CESIUM]: lazy(() => import(/* webpackChunkName: 'supports/cesiumMapViews' */ '../map/cesium/MapViewsSupport'))
1✔
36
};
37

38
const MapViewSettings = lazy(() => import('./MapViewSettings'));
1✔
39

40
const UPDATE_VIEWS_STATE = 'UPDATE_VIEWS_STATE';
1✔
41
const UNDO_VIEWS_STATE = 'UNDO_VIEWS_STATE';
1✔
42
const REDO_VIEWS_STATE = 'REDO_VIEWS_STATE';
1✔
43

44
const handlers = {
1✔
45
    [UPDATE_VIEWS_STATE]: (state, newState) => ({
4✔
46
        ...state,
47
        ...newState
48
    })
49
};
50

51
const reducer = (state, action) => {
1✔
52
    return (handlers[action.type] || identity)(state, action.payload);
4!
53
};
54

55
const historyMapViewsStateReducer = undoable(reducer, {
1✔
56
    limit: 20,
57
    undoType: UNDO_VIEWS_STATE,
58
    redoType: REDO_VIEWS_STATE,
59
    jumpType: '',
60
    jumpToPastType: '',
61
    jumpToFutureType: '',
62
    clearHistoryType: ''
63
});
64

65
const computeDurationSum = (views) => views?.reduce((sum, view) => sum + (view?.duration ?? DefaultViewValues.DURATION) * 1000, 0) ?? 0;
16!
66

67
const useMapViewsNavigation = ({
1✔
68
    currentIndex,
69
    views,
70
    onInit,
71
    onChangeView
72
}) => {
73

74
    const [play, setPlay] = useState(false);
11✔
75
    const [navigationProgress, setNavigationProgress] = useState(0);
11✔
76
    const viewsTimeTotalLength = computeDurationSum(views);
11✔
77
    const viewsTimeSegments = views.map((view, idx) => ({ view, duration: computeDurationSum(views.filter((vw, jdx) => jdx < idx)) }));
11✔
78

79
    useEffect(() => {
11✔
80
        if (!play) {
6!
81
            setNavigationProgress(Math.round((viewsTimeSegments?.[currentIndex]?.duration ?? 0) / viewsTimeTotalLength * 100));
6✔
82
        }
83
    }, [currentIndex, play]);
84

85
    useEffect(() => {
11✔
86
        function detectVisibilityChange() {
87
            if (document.visibilityState !== 'visible') {
×
88
                setPlay(false);
×
89
            }
90
        }
91

92
        let animationFrame;
93
        let stop = false;
4✔
94

95
        if (play) {
4!
96
            let startTime = Date.now();
×
97
            let index = currentIndex === -1 ? 0 : currentIndex;
×
98
            let initialDelta = viewsTimeSegments?.[index]?.duration;
×
99
            let mainStartTime = startTime;
×
100
            let currentView = views[index >= views.length ? 0 : index];
×
101
            onInit(currentView);
×
102
            const animate = () => {
×
103
                if (!stop) {
×
104
                    animationFrame = requestAnimationFrame(animate);
×
105
                    const currentTime = Date.now();
×
106
                    const delta = currentTime - startTime;
×
107
                    const duration = (currentView?.duration ?? DefaultViewValues.DURATION) * 1000;
×
108
                    // check single view duration time
109
                    if (delta >= duration) {
×
110
                        startTime = Date.now();
×
111
                        const previousIndex = index >= views.length ? 0 : index;
×
112
                        const nextIndex = (previousIndex + 1) >= views.length ? 0 : previousIndex + 1;
×
113
                        const nextView = views[nextIndex];
×
114
                        onChangeView(nextView);
×
115
                        currentView = nextView;
×
116
                        index = nextIndex;
×
117
                    }
118
                    // check global navigation duration time
119
                    const mainDelta = (currentTime + initialDelta) - mainStartTime;
×
120
                    const percentage = Math.round((mainDelta / viewsTimeTotalLength) * 100);
×
121
                    const currentViewPercentage = Math.round((delta / duration) * 100);
×
122
                    if ((currentViewPercentage % 5) === 0) {
×
123
                        setNavigationProgress(percentage);
×
124
                    }
125
                    if (mainDelta >= viewsTimeTotalLength) {
×
126
                        mainStartTime = Date.now();
×
127
                        initialDelta = 0;
×
128
                    }
129
                }
130
            };
131
            animate(index);
×
132
            document.addEventListener('visibilitychange', detectVisibilityChange);
×
133
        }
134
        return () => {
4✔
135
            stop = true;
4✔
136
            if (animationFrame) {
4!
137
                cancelAnimationFrame(animationFrame);
×
138
            }
139
            if (play) {
4!
140
                document.removeEventListener('visibilitychange', detectVisibilityChange);
×
141
            }
142
        };
143
    }, [play]);
144

145
    return {
11✔
146
        play,
147
        setPlay,
148
        navigationProgress,
149
        viewsTimeSegments,
150
        viewsTimeTotalLength
151
    };
152
};
153

154
function MapViewsSupport({
155
    mapType,
156
    onSelectView = () => { },
11✔
157
    onUpdateViews = () => { },
11✔
158
    onUpdateResources = () => { },
11✔
159
    onUpdateServices = () => { },
11✔
160
    views: viewsProp = [],
2✔
161
    selectedId,
162
    defaultTitle = 'Map View',
11✔
163
    layers,
164
    groups,
165
    locale,
166
    resources: resourcesProp = [],
11✔
167
    services,
168
    selectedService,
169
    defaultServices,
170
    defaultSelectedService,
171
    edit,
172
    hide,
173
    ...props
174
}) {
175

176
    const [mapViewsStateHistory, dispatch] = useReducer(historyMapViewsStateReducer, {});
11✔
177
    const setViews = (views) => dispatch({ type: UPDATE_VIEWS_STATE, payload: { views } });
11✔
178
    const setResources = (resources) => dispatch({ type: UPDATE_VIEWS_STATE, payload: { resources } });
11✔
179
    const setMapViewsState = ({ views, resources }) => dispatch({ type: UPDATE_VIEWS_STATE, payload: { views, resources } });
11✔
180

181
    useEffect(() => {
11✔
182
        setMapViewsState({ views: viewsProp, resources: resourcesProp });
4✔
183
    }, []);
184

185
    const [triggerUpdate, setTriggerUpdate] = useState(0);
11✔
186
    const [expandedSections, setExpandedSections] = useState({});
11✔
187
    function handleHistory(historyActionType) {
188
        let nextState;
189
        if (historyActionType === UNDO_VIEWS_STATE) {
×
UNCOV
190
            nextState = mapViewsStateHistory?.past[mapViewsStateHistory?.past.length - 1];
×
191
        }
192
        if (historyActionType === REDO_VIEWS_STATE) {
×
UNCOV
193
            nextState = mapViewsStateHistory?.future[mapViewsStateHistory?.future.length - 1];
×
194
        }
195
        dispatch({ type: historyActionType });
×
196
        onUpdateViews(nextState.views);
×
197
        onUpdateResources(nextState.resources);
×
UNCOV
198
        setTriggerUpdate(triggerUpdate + 1);
×
199
    }
200

201
    const {
202
        views = [],
4✔
203
        resources = []
4✔
204
    } = mapViewsStateHistory?.present || {};
11✔
205

206
    const [expanded, setExpanded] = useState('');
11✔
207
    const [showDescription, setShowDescription] = useState(true);
11✔
208
    const [showViewsGeometries, setShowViewsGeometries] = useState(false);
11✔
209
    const [showClipGeometries, setShowClipGeometries] = useState(false);
11✔
210

211
    const selected = views.find(view => view.id === selectedId);
11✔
212
    const currentIndex = views.indexOf(selected);
11✔
213

214
    const [initApi, setInitApi] = useState(false);
11✔
215
    const api = useRef();
11✔
216
    function apiRef(newApi) {
217
        api.current = newApi;
3✔
218
        if (!initApi) {
3!
219
            setInitApi(true);
3✔
220
        }
221
    }
222

223
    function handleCreateView(copyView) {
UNCOV
224
        const currentMaxCountInTitles = views.length > 0 && max(
×
225
            views
226
                .map(view => {
227
                    const titleRegex = new RegExp(`${defaultTitle} \\(([0-9]+)\\)`);
×
228
                    const match = (view.title || '').match(titleRegex)?.[1];
×
UNCOV
229
                    return match ? parseFloat(match) : undefined;
×
230
                })
UNCOV
231
                .filter(value => value !== undefined)
×
232
        );
UNCOV
233
        const maxCount = currentMaxCountInTitles && !isNaN(currentMaxCountInTitles)
×
234
            ? currentMaxCountInTitles
235
            : 0;
UNCOV
236
        const newView = {
×
237
            duration: DefaultViewValues.DURATION,
238
            flyTo: true,
239
            ...(copyView ? copyView : api.current.getView()),
×
240
            title: `${defaultTitle} (${maxCount + 1})`,
241
            id: uuid()
242
        };
UNCOV
243
        const newViews = currentIndex === -1
×
244
            ? [...views, newView]
245
            : views.reduce((acc, view, idx) => idx === currentIndex ? [...acc, view, newView] : [...acc, view], []);
×
246
        setViews(newViews);
×
247
        onSelectView(newView.id);
×
248
        onUpdateViews(newViews);
×
249
        if (!services && views.length === 0) {
×
UNCOV
250
            onUpdateServices(defaultSelectedService);
×
251
        }
252
    }
253

254
    function handleRemoveView(view) {
255
        const newViews = views.filter((vw) => vw.id !== view.id);
×
256
        setViews(newViews);
×
UNCOV
257
        onUpdateViews(newViews);
×
258
    }
259

260
    function handleSelectView(view, allowFlyTo) {
261
        if (view && api?.current?.setView) {
×
UNCOV
262
            api.current.setView(allowFlyTo ? view : { ...view, flyTo: false });
×
263
        }
UNCOV
264
        onSelectView(view.id);
×
265
    }
266

267
    function handleUpdateView(newView) {
268
        const newViews = views.map((view) => view.id === newView.id ? newView : view);
×
269
        setViews(newViews);
×
UNCOV
270
        onUpdateViews(newViews);
×
271
    }
272
    function handleCaptureView(newView) {
UNCOV
273
        const newViews = views.map((view) => view.id === newView.id ? ({
×
274
            ...newView,
275
            ...api.current.getView()
276
        }) : view);
277
        setViews(newViews);
×
UNCOV
278
        onUpdateViews(newViews);
×
279
    }
280

281
    const prevViews = useRef();
11✔
282
    prevViews.current = views;
11✔
283

284
    const handleMove = useCallback((dragIndex, hoverIndex) => {
11✔
285
        let newViews = [...prevViews.current];
×
286
        newViews.splice(dragIndex, 1);
×
287
        newViews.splice(hoverIndex, 0, prevViews.current[dragIndex]);
×
UNCOV
288
        setViews(newViews);
×
289
    }, []);
290

291
    function handleMoveEnd() {
UNCOV
292
        onUpdateViews(views);
×
293
    }
294

295
    function handleStepMove(delta) {
296
        if (views[currentIndex + delta]) {
×
UNCOV
297
            handleSelectView(views[currentIndex + delta]);
×
298
        }
299
    }
300

301
    function handleChangeOnSelected(properties) {
UNCOV
302
        const newViews = views.map((view) => view.id === selected.id ? ({
×
303
            ...view,
304
            ...properties
305
        }) : view);
306
        setViews(newViews);
×
UNCOV
307
        onUpdateViews(newViews);
×
308
    }
309

310
    function handleUpdateResource(id, data) {
311
        const hasResource = !!resources.find(res => res.id === id);
×
312
        const newResources = hasResource
×
UNCOV
313
            ? resources.map((res) => res.id === id ? { id, data } : res)
×
314
            : [...resources, { id, data }];
315
        setResources(newResources);
×
UNCOV
316
        onUpdateResources(newResources);
×
317
    }
318

319
    const {
320
        play,
321
        setPlay,
322
        navigationProgress,
323
        viewsTimeSegments,
324
        viewsTimeTotalLength
325
    } = useMapViewsNavigation({
11✔
326
        currentIndex,
327
        views,
328
        onInit: (currentView) => {
329
            handleSelectView(currentView);
×
UNCOV
330
            setExpanded('');
×
331
        },
332
        onChangeView: (nextView) => {
UNCOV
333
            handleSelectView(nextView, true);
×
334
        }
335
    });
336

337
    // set the initial view
338
    // only once on mount
339
    const init = useRef(false);
11✔
340
    useEffect(() => {
11✔
341
        if (initApi && !init.current) {
7✔
342
            init.current = true;
3✔
343
            if (selected) {
3✔
344
                // delay the initial set view
345
                // waiting that the zoom from map has been completed
346
                setTimeout(() => {
2✔
347
                    api.current.setView({
2✔
348
                        ...selected,
349
                        // remove fly animation to the initial view
350
                        flyTo: false
351
                    });
352
                }, 500);
353
            }
354
        }
355
    }, [initApi]);
356

357
    const Support = mapViewSupports[mapType];
11✔
358

359
    if (!Support || !edit && views?.length === 0 || hide) {
11✔
360
        return null;
3✔
361
    }
362
    return (
8✔
363
        <>
364
            <Suspense fallback={<div />}>
365
                <Support
366
                    {...props}
367
                    selectedId={selectedId}
368
                    views={views}
369
                    apiRef={apiRef}
370
                    showViewsGeometries={showViewsGeometries}
371
                    resources={resources}
372
                    showClipGeometries={showClipGeometries}
373
                />
374
            </Suspense>
375
            {(edit && views?.length === 0)
21✔
376
                ? (
377
                    <div className="ms-map-views">
378
                        <div className="ms-map-views-wrapper">
379
                            <div className="ms-map-views-header">
380
                                <div className="ms-map-views-title">
381
                                    <Message msgId="mapViews.addInitialView" />
382
                                </div>
383
                                <ButtonToolbar>
384
                                    <ButtonGroup>
385
                                        {(mapViewsStateHistory?.past?.length || 0) > 0 && <Button
9!
386
                                            bsStyle="primary"
387
                                            className="square-button-md"
388
                                            disabled={(mapViewsStateHistory?.past?.length || 0) === 0}
×
UNCOV
389
                                            onClick={() => handleHistory(UNDO_VIEWS_STATE)}
×
390
                                            tooltipId="mapViews.undoChanges"
391
                                            tooltipPosition="bottom"
392
                                        >
393
                                            <Glyphicon glyph="undo" />
394
                                        </Button>}
395
                                        <Button
396
                                            bsStyle="primary"
397
                                            className="square-button-md"
398
                                            onClick={handleCreateView.bind(null, undefined)}
399
                                            tooltipId="mapViews.addNewView"
400
                                            tooltipPosition="bottom"
401
                                        >
402
                                            <Glyphicon glyph="plus" />
403
                                        </Button>
404
                                    </ButtonGroup>
405
                                </ButtonToolbar>
406
                            </div>
407
                        </div>
408
                    </div>
409
                ) : (
UNCOV
410
                    <div className="ms-map-views" onClick={(event) => event.stopPropagation()}>
×
411
                        <div className="ms-map-views-wrapper">
412
                            <MapViewsProgressBar
413
                                play={play}
414
                                currentIndex={currentIndex}
415
                                progress={navigationProgress}
416
                                segments={viewsTimeSegments}
417
                                totalLength={viewsTimeTotalLength}
418
                                onSelect={view => {
419
                                    if (play) {
×
UNCOV
420
                                        setPlay(false);
×
421
                                    }
UNCOV
422
                                    handleSelectView(view);
×
423
                                }}
424
                            />
425
                            <div className="ms-map-views-header">
426
                                {(selected?.description && !expanded) ?
15!
427
                                    <Button
428
                                        className="square-button-md no-border"
429
                                        style={{ borderRadius: '50%', marginRight: 4 }}
UNCOV
430
                                        onClick={() => setShowDescription(!showDescription)}
×
431
                                        tooltipId={showDescription ? 'mapViews.hideDescription' : 'mapViews.showDescription'}
5!
432
                                        tooltipPosition="bottom"
433
                                    >
434
                                        <Glyphicon glyph={showDescription ? "chevron-down" : "chevron-right"} />
5!
435
                                    </Button>
436
                                    : null}
437
                                <div className="ms-map-views-title">
438
                                    {expanded === 'settings'
5!
439
                                        ? (
440
                                            <FormControl
441
                                                key={`${selected?.id}-${triggerUpdate}`}
442
                                                value={selected?.title}
UNCOV
443
                                                onChange={val => handleChangeOnSelected({ title: val })}
×
444
                                            />
445
                                        )
446
                                        : selected?.title}
447
                                </div>
448
                                <ButtonToolbar>
449
                                    {!play && <ButtonGroup>
10✔
450
                                        <Button
451
                                            bsStyle={expanded === 'list' ? 'success' : 'primary'}
5!
452
                                            className="square-button-md"
453
                                            active={expanded === 'list'}
UNCOV
454
                                            onClick={() => setExpanded(expanded !== 'list' ? 'list' : '')}
×
455
                                            tooltipId={expanded === 'list' ? 'mapViews.hideViewsList' : 'mapViews.showViewsList'}
5!
456
                                            tooltipPosition="bottom"
457
                                        >
458
                                            <Glyphicon glyph="list" />
459
                                        </Button>
460
                                    </ButtonGroup>}
461
                                    {(!play && edit) && <ButtonGroup>
12✔
462
                                        <Button
463
                                            bsStyle="primary"
464
                                            className="square-button-md"
465
                                            disabled={expanded === 'settings'}
466
                                            onClick={handleCreateView.bind(null, undefined)}
467
                                            tooltipId={selected ? 'mapViews.addNewViewBelowSelected' : 'mapViews.addNewView'}
2!
468
                                            tooltipPosition="bottom"
469
                                        >
470
                                            <Glyphicon glyph="plus" />
471
                                        </Button>
472
                                        <Button
473
                                            bsStyle="primary"
474
                                            className="square-button-md"
475
                                            disabled={!selected || expanded === 'settings'}
4✔
476
                                            onClick={handleCreateView.bind(null, selected)}
477
                                            tooltipId="mapViews.copyCurrentView"
478
                                            tooltipPosition="bottom"
479
                                        >
480
                                            <Glyphicon glyph="duplicate" />
481
                                        </Button>
482
                                        <Button
483
                                            bsStyle={expanded === 'settings' ? 'success' : 'primary'}
2!
484
                                            className="square-button-md"
485
                                            active={expanded === 'settings'}
486
                                            disabled={!selected}
UNCOV
487
                                            onClick={() => setExpanded(expanded !== 'settings' ? 'settings' : '')}
×
488
                                            tooltipId={expanded === 'settings' ? 'mapViews.stopEdit' : 'mapViews.edit'}
2!
489
                                            tooltipPosition="bottom"
490
                                        >
491
                                            <Glyphicon glyph="pencil" />
492
                                        </Button>
493
                                        <Button
494
                                            bsStyle="primary"
495
                                            className="square-button-md"
496
                                            disabled={(mapViewsStateHistory?.past?.length || 0) === 0}
4✔
UNCOV
497
                                            onClick={() => handleHistory(UNDO_VIEWS_STATE)}
×
498
                                            tooltipId="mapViews.undoChanges"
499
                                            tooltipPosition="bottom"
500
                                        >
501
                                            <Glyphicon glyph="undo" />
502
                                        </Button>
503
                                        <Button
504
                                            bsStyle="primary"
505
                                            className="square-button-md"
506
                                            disabled={(mapViewsStateHistory?.future?.length || 0) === 0}
4✔
UNCOV
507
                                            onClick={() => handleHistory(REDO_VIEWS_STATE)}
×
508
                                            tooltipId="mapViews.redoChanges"
509
                                            tooltipPosition="bottom"
510
                                        >
511
                                            <Glyphicon glyph="redo" />
512
                                        </Button>
513
                                    </ButtonGroup>}
514
                                    <ButtonGroup>
515
                                        <Button
516
                                            bsStyle="primary"
517
                                            className="square-button-md"
UNCOV
518
                                            onClick={() => handleSelectView(views[0])}
×
519
                                            disabled={currentIndex === 0 || play}
5!
520
                                            tooltipId="mapViews.gotToFirstView"
521
                                            tooltipPosition="bottom"
522
                                        >
523
                                            <Glyphicon glyph="fast-backward" />
524
                                        </Button>
525
                                        <Button
526
                                            bsStyle="primary"
527
                                            className="square-button-md"
UNCOV
528
                                            onClick={() => handleStepMove(-1)}
×
529
                                            disabled={!views[currentIndex - 1] || play}
5!
530
                                            tooltipId="mapViews.gotToPreviousView"
531
                                            tooltipPosition="bottom"
532
                                        >
533
                                            <Glyphicon glyph="step-backward" />
534
                                        </Button>
535
                                        <Button
536
                                            bsStyle="primary"
537
                                            className="square-button-md"
538
                                            active={!!play}
539
                                            disabled={views?.length === 1}
UNCOV
540
                                            onClick={() => setPlay(!play)}
×
541
                                            tooltipId={play ? 'mapViews.pause' : 'mapViews.play'}
5!
542
                                            tooltipPosition="bottom"
543
                                        >
544
                                            <Glyphicon glyph={play ? 'pause' : 'play'} />
5!
545
                                        </Button>
546
                                        <Button
547
                                            bsStyle="primary"
548
                                            className="square-button-md"
UNCOV
549
                                            onClick={() => handleStepMove(1)}
×
550
                                            disabled={!views[currentIndex + 1] || play}
5!
551
                                            tooltipId="mapViews.gotToNextView"
552
                                            tooltipPosition="bottom"
553
                                        >
554
                                            <Glyphicon glyph="step-forward" />
555
                                        </Button>
556
                                        <Button
557
                                            bsStyle="primary"
558
                                            className="square-button-md"
UNCOV
559
                                            onClick={() => handleSelectView(views[views?.length - 1])}
×
560
                                            disabled={currentIndex === views?.length - 1 || play}
5!
561
                                            tooltipId="mapViews.gotToLastView"
562
                                            tooltipPosition="bottom"
563
                                        >
564
                                            <Glyphicon glyph="fast-forward" />
565
                                        </Button>
566
                                    </ButtonGroup>
567
                                </ButtonToolbar>
568
                            </div>
569
                            <div className="ms-map-views-body">
570
                                {expanded === 'list' &&
5!
571
                                    <MapViewsList
572
                                        views={views}
573
                                        edit={edit}
574
                                        selectedId={selected?.id}
575
                                        onSelect={handleSelectView}
576
                                        onMove={handleMove}
577
                                        onMoveEnd={handleMoveEnd}
578
                                        onRemove={handleRemoveView}
579
                                        options={
580
                                            <>
UNCOV
581
                                                {api.current?.options?.showClipGeometriesEnabled && <Checkbox checked={showViewsGeometries} onChange={() => setShowViewsGeometries(!showViewsGeometries)}>
×
582
                                                    <Message msgId="mapViews.showViewsGeometries" />
583
                                                </Checkbox>}
584
                                            </>
585
                                        }
586
                                    />
587
                                }
588
                                {(expanded === 'settings' && selected) &&
5!
589
                                    <Suspense fallback={<div style={{ display: 'flex', justifyContent: 'center', padding: 8, width: '100%' }}><Loader size={30}/></div>}>
590
                                        <MapViewSettings
591
                                            key={`${selected.id}-${triggerUpdate}`}
592
                                            expandedSections={expandedSections}
593
                                            onExpandSection={(value) =>
UNCOV
594
                                                setExpandedSections((prevSections) => ({ ...prevSections, ...value }))
×
595
                                            }
596
                                            view={selected}
597
                                            api={api.current}
598
                                            onChange={handleUpdateView}
599
                                            onCaptureView={handleCaptureView}
600
                                            layers={layers}
601
                                            groups={groups}
602
                                            locale={locale}
603
                                            services={services}
604
                                            selectedService={selectedService}
605
                                            resources={resources}
606
                                            onUpdateResource={handleUpdateResource}
607
                                            showClipGeometries={showClipGeometries}
608
                                            onShowClipGeometries={setShowClipGeometries}
609
                                        />
610
                                    </Suspense>
611
                                }
612
                            </div>
613
                        </div>
614
                        {(!expanded && showDescription && selected?.description) && <div
20✔
615
                            className="ms-map-views-description">
616
                            <div dangerouslySetInnerHTML={{ __html: selected.description }} />
617
                        </div>
618
                        }
619
                    </div>
620
                )}
621

622
        </>
623
    );
624
}
625

626
export default MapViewsSupport;
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

© 2025 Coveralls, Inc