@opengeoweb/core 15.1.0 → 15.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.esm.js CHANGED
@@ -1,16 +1,16 @@
1
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { Grid, InputLabel, Paper, Box, Typography, CircularProgress, List, ListSubheader, ListItemButton, ListItemText, DialogContentText, TextField, InputAdornment, Button, FormControl, MenuItem, useTheme, Tooltip, ListItem, ListItemIcon, Checkbox, Popper, Fade, styled, LinearProgress, Autocomplete, Switch, Select } from '@mui/material';
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { FormControl, MenuItem, Grid, InputLabel, Paper, Box, Typography, CircularProgress, List, ListSubheader, ListItemButton, ListItemText, DialogContentText, TextField, InputAdornment, Button, useTheme, Tooltip, ListItem, ListItemIcon, Checkbox, Popper, Fade, styled, LinearProgress, Autocomplete, Switch, Select } from '@mui/material';
3
3
  import React, { useMemo, useState, useCallback, useEffect, useContext } from 'react';
4
- import { safelyInitI18nForTestsAndStories, sharedTranslations, SHARED_NAMESPACE, CustomIconButton, CustomDialog, TooltipSelect, CustomTooltip, ToggleMenu, AlertIcon, useConfirmationDialog, useScrollingInIsolation, sliderHeaderStyle, CustomSlider, tooltipContainerStyles, renderCounter, AlertBanner, CustomAccordion, PROJECTION, calculateStartSize, useWheelStopPropagation, ToolContainerDraggable, sessionStorageProvider, useDebounce, usePrevious, dateUtils } from '@opengeoweb/shared';
5
- import { queryWMSLayersTree, invalidateWMSGetCapabilities, LayerType, webmapUtils, queryWMSServiceInfo, queryWMSLayers, getWMSServiceId, generateLayerId, WMJSDimension, getWMLayerById, getMapDimURL, handleDateUtilsISOString, WMLayer } from '@opengeoweb/webmap';
6
- import { filterLayers, mapSelectors, layerActions, layerTypes, layerSelectors, mapActions, mapEnums, loadingIndicatorSelectors, layerUtils, serviceSelectors, serviceActions, uiSelectors, uiTypes, useSetupDialog, getUserAddedServices, uiActions, drawingToolSelectors, syncGroupsSelectors, syncConstants, getViewObjectForSyncGroup, getViewObjectForMapId, loadingIndicatorActions, genericSelectors, genericActions, defaultLayers, getSingularDrawtoolDrawLayerId, syncGroupsSelector, syncGroupsActions, routerUtils, mapUtils } from '@opengeoweb/store';
7
- import { connect, useDispatch, useSelector, useStore, Provider } from 'react-redux';
4
+ import { safelyInitI18nForTestsAndStories, sharedTranslations, SHARED_NAMESPACE, TooltipSelect, CustomIconButton, CustomDialog, CustomTooltip, ToggleMenu, AlertIcon, useConfirmationDialog, useScrollingInIsolation, sliderHeaderStyle, CustomSlider, tooltipContainerStyles, renderCounter, AlertBanner, CustomAccordion, PROJECTION, calculateStartSize, useWheelStopPropagation, ToolContainerDraggable, sessionStorageProvider, useDebounce, dateUtils, usePrevious } from '@opengeoweb/shared';
5
+ import { webmapUtils, queryWMSLayersTree, invalidateWMSGetCapabilities, LayerType, queryWMSServiceInfo, queryWMSLayers, getWMSServiceId, generateLayerId, WMJSDimension, getWMLayerById, getMapDimURL, handleDateUtilsISOString, WMLayer } from '@opengeoweb/webmap';
8
6
  import _, { isEqual, isArray, range, zip, throttle } from 'lodash';
9
- import { Cached, Add, MapAdd, CollapseSmall, CollapseMedium, CollapseLarge, CollapseWindow, ExpandWindow, LayersAdd, CloudLoading, ColumnCollapsed, ColumnCollapse, DragHandle as DragHandle$1, None, FastForward, AutoUpdateActive, Both, Delete, Visibility, VisibilityOff, Copy, Overlayers, WorldMapProjection, Layers, Search, Exclamation, MyLocation, Airplane, Region, Pinned, Close, ExitDomain, LocationInfo, Measure, Options, Info, ThemeWrapper, lightTheme, FlagBritain, FlagNetherlands, FlagFinland, FlagNorway } from '@opengeoweb/theme';
7
+ import { useDispatch, useSelector, connect, useStore, Provider } from 'react-redux';
8
+ import { mapSelectors, layerSelectors, layerActions, layerTypes, filterLayers, mapActions, mapEnums, loadingIndicatorSelectors, layerUtils, serviceSelectors, serviceActions, uiSelectors, uiTypes, useSetupDialog, getUserAddedServices, uiActions, drawingToolSelectors, syncGroupsSelectors, syncConstants, getViewObjectForSyncGroup, getViewObjectForMapId, loadingIndicatorActions, genericSelectors, genericActions, defaultLayers, getSingularDrawtoolDrawLayerId, syncGroupsSelector, syncGroupsActions, routerUtils, mapUtils } from '@opengeoweb/store';
10
9
  import i18n from 'i18next';
11
10
  import { useTranslation, I18nextProvider } from 'react-i18next';
12
- import { TIME_SLIDER_NAMESPACE, timesliderTranslations, defaultTimeSpan, AutoUpdateButton, BackwardForwardStepButton, NowButton, handleSetNowEvent, AnimationLengthButton, AnimationLength, SpeedButton, TimeSpanButton, secondsPerPxFromCanvasWidth, getNewCenterOfFixedPointZoom, TimeStepButton, OptionsMenuButton, PlayButton, defaultTimeStep, TimeSliderButtons, TimeSliderCurrentTimeBox, TimeSliderLegend, onsetNewDateDebounced, defaultSecondsPerPx, moveSelectedTimePx, TimeSlider, getFilteredTime } from '@opengeoweb/time-slider';
11
+ import { TIME_SLIDER_NAMESPACE, timesliderTranslations, defaultTimeSpan, AutoUpdateButton, BackwardForwardStepButton, NowButton, handleSetNowEvent, AnimationLengthButton, AnimationLength, SpeedButton, TimeSpanButton, secondsPerPxFromCanvasWidth, getNewCenterOfFixedPointZoom, TimeStepButton, OptionsMenuButton, PlayButton, defaultTimeStep, TimeSliderButtons, TimeSliderCurrentTimeBox, TimeSliderLegend, onsetNewDateDebounced, getFilteredTime, defaultSecondsPerPx, moveSelectedTimePx, TimeSlider } from '@opengeoweb/time-slider';
13
12
  import { webmapReactTranslations, WEBMAP_REACT_NAMESPACE, webmapTranslations, WEBMAP_NAMESPACE, openLayersGetMapImageStore, LayerInfoButton, useEDRGetCollectionDetails, defaultEdrStyles, LayerInfoDialog, MapControlButton, MapDimensionSelect, dimensionConfig, DimensionSelectDialog, DimensionSelectButton, Clock, LegendDialog, LegendButton, MapContext, emptyGeoJSON, MapFeatureClass, setMapCenter, OpenLayersFeatureLayer, OpenLayersMapDraw, makeTimeList, useGetWMLayerInstance, getIsInsideAcceptanceTime, OpenLayersLayer, MapMeasure, useSetIntervalWhenVisible, TimeContext, OpenLayersMapView, WMSLayer, genericOpenLayersFeatureStyle, OpenLayersGetFeatureInfo, MapControls, OpenLayersZoomControl, getLayerUpdateInfo, publicLayers } from '@opengeoweb/webmap-react';
13
+ import { Cached, Add, MapAdd, CollapseSmall, CollapseMedium, CollapseLarge, CollapseWindow, ExpandWindow, LayersAdd, CloudLoading, ColumnCollapsed, ColumnCollapse, DragHandle as DragHandle$1, None, FastForward, AutoUpdateActive, Both, Delete, Visibility, VisibilityOff, Copy, Overlayers, WorldMapProjection, Layers, Search, Exclamation, MyLocation, Airplane, Region, Pinned, Close, ExitDomain, LocationInfo, Measure, Options, Info, ThemeWrapper, lightTheme, FlagBritain, FlagNetherlands, FlagFinland, FlagNorway } from '@opengeoweb/theme';
14
14
  import { ReactSortable } from 'react-sortablejs';
15
15
  import Sortable from 'sortablejs';
16
16
  import { Box as Box$1, Stack } from '@mui/system';
@@ -128,7 +128,8 @@ var en = {
128
128
  "delete-dialog-cancel": "Cancel",
129
129
  "delete-dialog-confirm": "Delete",
130
130
  "map-options-button": "Location or Measuring tool",
131
- "map-measure-tool": "Measuring tool"
131
+ "map-measure-tool": "Measuring tool",
132
+ "data-outdated": "Outdated data"
132
133
  };
133
134
  var fi = {
134
135
  feature_info_title: "Napsauta karttaa nähdäksesi lisätietoja.",
@@ -389,7 +390,8 @@ var nl = {
389
390
  "delete-dialog-cancel": "Annuleren",
390
391
  "delete-dialog-confirm": "Verwijderen",
391
392
  "map-options-button": "Locatie informatie en Meten",
392
- "map-measure-tool": "Meten"
393
+ "map-measure-tool": "Meten",
394
+ "data-outdated": "Data is niet actueel"
393
395
  };
394
396
  var coreTranslations = {
395
397
  en: en,
@@ -708,6 +710,192 @@ function _regeneratorRuntime() {
708
710
  })();
709
711
  }
710
712
 
713
+ /* *
714
+ * Licensed under the Apache License, Version 2.0 (the "License");
715
+ * you may not use this file except in compliance with the License.
716
+ * You may obtain a copy of the License at
717
+ *
718
+ * http://www.apache.org/licenses/LICENSE-2.0
719
+ *
720
+ * Unless required by applicable law or agreed to in writing, software
721
+ * distributed under the License is distributed on an "AS IS" BASIS,
722
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
723
+ * See the License for the specific language governing permissions and
724
+ * limitations under the License.
725
+ *
726
+ * Copyright 2023 - Koninklijk Nederlands Meteorologisch Instituut (KNMI)
727
+ * Copyright 2023 - Finnish Meteorological Institute (FMI)
728
+ * Copyright 2024 - The Norwegian Meteorological Institute (MET Norway)
729
+ * */
730
+ var CORE_NAMESPACE = 'core';
731
+ var initCoreReactI18n = function initCoreReactI18n() {
732
+ safelyInitI18nForTestsAndStories(i18n, CORE_NAMESPACE, [{
733
+ ns: CORE_NAMESPACE,
734
+ translations: coreTranslations
735
+ }, {
736
+ ns: WEBMAP_REACT_NAMESPACE,
737
+ translations: webmapReactTranslations
738
+ }, {
739
+ ns: WEBMAP_NAMESPACE,
740
+ translations: webmapTranslations
741
+ }, {
742
+ ns: SHARED_NAMESPACE,
743
+ translations: sharedTranslations
744
+ }, {
745
+ ns: TIME_SLIDER_NAMESPACE,
746
+ translations: timesliderTranslations
747
+ }]);
748
+ };
749
+ var ns = [CORE_NAMESPACE, TIME_SLIDER_NAMESPACE];
750
+ var useCoreTranslation = function useCoreTranslation() {
751
+ return useTranslation(ns);
752
+ };
753
+
754
+ var BaseLayers = function BaseLayers(_ref) {
755
+ var _availableBaseLayers$;
756
+ var selectedBaseLayers = _ref.selectedBaseLayers,
757
+ availableBaseLayers = _ref.availableBaseLayers,
758
+ onChangeBaseLayers = _ref.onChangeBaseLayers,
759
+ icon = _ref.icon,
760
+ tooltipPrefix = _ref.tooltipPrefix;
761
+ var _useCoreTranslation = useCoreTranslation(),
762
+ t = _useCoreTranslation.t;
763
+ if (!(availableBaseLayers != null && availableBaseLayers.length)) {
764
+ return jsx("div", {
765
+ children: t('layermanager-baselayers-no-available')
766
+ });
767
+ }
768
+ var nonEmptyTooltipPrefix = tooltipPrefix != null ? tooltipPrefix : t('layermanager-layer') + ": ";
769
+ var selectedBaseLayerId = typeof selectedBaseLayers[0] !== 'undefined' ? selectedBaseLayers[0].id : '';
770
+ var list = availableBaseLayers.map(function (layer) {
771
+ return {
772
+ value: layer.id
773
+ };
774
+ });
775
+ var currentIndex = availableBaseLayers.findIndex(function (layer) {
776
+ return selectedBaseLayerId === layer.id;
777
+ });
778
+ return jsx(FormControl, {
779
+ style: {
780
+ width: '100%'
781
+ },
782
+ children: jsxs(TooltipSelect, {
783
+ IconComponent: icon,
784
+ currentIndex: currentIndex,
785
+ disableUnderline: true,
786
+ inputProps: {
787
+ SelectDisplayProps: {
788
+ 'data-testid': 'selectBaseLayer'
789
+ }
790
+ },
791
+ isEnabled: true,
792
+ list: list,
793
+ onChange: function onChange(event) {
794
+ onChangeBaseLayers(event.target.value);
795
+ },
796
+ onChangeMouseWheel: function onChangeMouseWheel(e) {
797
+ return onChangeBaseLayers(e.value);
798
+ },
799
+ style: {
800
+ maxWidth: '100%'
801
+ },
802
+ tooltip: "" + nonEmptyTooltipPrefix + ((_availableBaseLayers$ = availableBaseLayers[currentIndex]) == null ? void 0 : _availableBaseLayers$.name),
803
+ value: selectedBaseLayerId,
804
+ children: [jsx(MenuItem, {
805
+ disabled: true,
806
+ children: t('layermanager-baselayers-title')
807
+ }), availableBaseLayers.map(function (baseLayer) {
808
+ return jsx(MenuItem, {
809
+ value: baseLayer.id,
810
+ children: baseLayer.name
811
+ }, baseLayer.id);
812
+ })]
813
+ })
814
+ });
815
+ };
816
+
817
+ // Generate a layer id for an available baselayer to ensure same available baselayers have unique id's in case of multiple maps
818
+ // If already in selectedBaseLayers based on name or id, keep current id
819
+ var constructLayerId = function constructLayerId(baseLayer, selectedBaseLayers) {
820
+ var foundLayer = selectedBaseLayers.find(function (selectedBaseLayer) {
821
+ return (baseLayer == null ? void 0 : baseLayer.id) === (selectedBaseLayer == null ? void 0 : selectedBaseLayer.id) || baseLayer.name === selectedBaseLayer.name;
822
+ });
823
+ return foundLayer ? foundLayer.id : webmapUtils.generateLayerId();
824
+ };
825
+ var constructListAvailableBaseLayers = function constructListAvailableBaseLayers(selectedBaseLayers, preloadedAvailableBaseLayers, mapId) {
826
+ // Ensure we use unique id's for the base layers - excepting the ones that are currently selected, reuse the existing ids
827
+ // Add mapId of map these available base layers are added for
828
+ var baseLayersWithMapId = preloadedAvailableBaseLayers.map(function (baseLayer) {
829
+ var layerId = constructLayerId(baseLayer, selectedBaseLayers);
830
+ return Object.assign({}, baseLayer, {
831
+ mapId: mapId,
832
+ id: layerId
833
+ });
834
+ });
835
+ // Ensure that current selected baselayer(s) are in the baseLayersWithMapId array, otherwise add them
836
+ return selectedBaseLayers.reduce(function (list, selectedBaseLayer) {
837
+ var foundLayer = baseLayersWithMapId.find(function (layer) {
838
+ return layer.id === (selectedBaseLayer == null ? void 0 : selectedBaseLayer.id);
839
+ });
840
+ if (foundLayer) {
841
+ return list;
842
+ }
843
+ return list.concat(Object.assign({}, selectedBaseLayer, {
844
+ mapId: mapId
845
+ }));
846
+ }, baseLayersWithMapId);
847
+ };
848
+ var areAvailableBaseLayersSame = function areAvailableBaseLayersSame(availableBaseLayerList, newBaseLayerList) {
849
+ var availableList = availableBaseLayerList.map(function (layer) {
850
+ return layer.name;
851
+ });
852
+ var newList = newBaseLayerList.map(function (layer) {
853
+ return layer.name;
854
+ });
855
+ return isEqual(availableList, newList);
856
+ };
857
+ var BaseLayersConnect = function BaseLayersConnect(_ref) {
858
+ var mapId = _ref.mapId,
859
+ preloadedAvailableBaseLayers = _ref.preloadedAvailableBaseLayers,
860
+ tooltipPrefix = _ref.tooltipPrefix,
861
+ icon = _ref.icon;
862
+ var dispatch = useDispatch();
863
+ var selectedBaseLayers = useSelector(function (store) {
864
+ return mapSelectors.getMapBaseLayers(store, mapId);
865
+ });
866
+ var currentAvailableBaseLayers = useSelector(function (store) {
867
+ return layerSelectors.getAvailableBaseLayersForMap(store, mapId);
868
+ });
869
+ React.useEffect(function () {
870
+ var availableBaseLayersToBeAdded = constructListAvailableBaseLayers(selectedBaseLayers, preloadedAvailableBaseLayers, mapId);
871
+ var areBaseLayersSame = areAvailableBaseLayersSame(availableBaseLayersToBeAdded, currentAvailableBaseLayers);
872
+ if (!areBaseLayersSame) {
873
+ dispatch(layerActions.setAvailableBaseLayers({
874
+ layers: availableBaseLayersToBeAdded,
875
+ mapId: mapId
876
+ }));
877
+ }
878
+ // eslint-disable-next-line react-hooks/exhaustive-deps
879
+ }, [mapId, preloadedAvailableBaseLayers]);
880
+ var onChangeBaseLayers = function onChangeBaseLayers(newSelectedLayerId) {
881
+ var newBaseLayer = currentAvailableBaseLayers.filter(function (layer) {
882
+ return layer.id === newSelectedLayerId;
883
+ });
884
+ dispatch(layerActions.setBaseLayers({
885
+ mapId: mapId,
886
+ layers: newBaseLayer,
887
+ origin: layerTypes.LayerActionOrigin.layerManager
888
+ }));
889
+ };
890
+ return jsx(BaseLayers, {
891
+ availableBaseLayers: currentAvailableBaseLayers,
892
+ icon: icon,
893
+ onChangeBaseLayers: onChangeBaseLayers,
894
+ selectedBaseLayers: selectedBaseLayers,
895
+ tooltipPrefix: tooltipPrefix
896
+ });
897
+ };
898
+
711
899
  var preset = {
712
900
  presetType: "mapPreset",
713
901
  presetId: "mapPreset-1",
@@ -928,47 +1116,6 @@ var defaultConfigurations = /*#__PURE__*/Object.freeze({
928
1116
  preloadedDefaultMapServices: preloadedDefaultMapServices
929
1117
  });
930
1118
 
931
- /* *
932
- * Licensed under the Apache License, Version 2.0 (the "License");
933
- * you may not use this file except in compliance with the License.
934
- * You may obtain a copy of the License at
935
- *
936
- * http://www.apache.org/licenses/LICENSE-2.0
937
- *
938
- * Unless required by applicable law or agreed to in writing, software
939
- * distributed under the License is distributed on an "AS IS" BASIS,
940
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
941
- * See the License for the specific language governing permissions and
942
- * limitations under the License.
943
- *
944
- * Copyright 2023 - Koninklijk Nederlands Meteorologisch Instituut (KNMI)
945
- * Copyright 2023 - Finnish Meteorological Institute (FMI)
946
- * Copyright 2024 - The Norwegian Meteorological Institute (MET Norway)
947
- * */
948
- var CORE_NAMESPACE = 'core';
949
- var initCoreReactI18n = function initCoreReactI18n() {
950
- safelyInitI18nForTestsAndStories(i18n, CORE_NAMESPACE, [{
951
- ns: CORE_NAMESPACE,
952
- translations: coreTranslations
953
- }, {
954
- ns: WEBMAP_REACT_NAMESPACE,
955
- translations: webmapReactTranslations
956
- }, {
957
- ns: WEBMAP_NAMESPACE,
958
- translations: webmapTranslations
959
- }, {
960
- ns: SHARED_NAMESPACE,
961
- translations: sharedTranslations
962
- }, {
963
- ns: TIME_SLIDER_NAMESPACE,
964
- translations: timesliderTranslations
965
- }]);
966
- };
967
- var ns = [CORE_NAMESPACE, TIME_SLIDER_NAMESPACE];
968
- var useCoreTranslation = function useCoreTranslation() {
969
- return useTranslation(ns);
970
- };
971
-
972
1119
  var WMSLayerTreeHeader = function WMSLayerTreeHeader(_ref) {
973
1120
  var serviceName = _ref.serviceName,
974
1121
  onClickReload = _ref.onClickReload;
@@ -1818,151 +1965,6 @@ var returnCorrectSize = function returnCorrectSize(sizeResult) {
1818
1965
  return sizeSmall;
1819
1966
  };
1820
1967
 
1821
- var BaseLayers = function BaseLayers(_ref) {
1822
- var _availableBaseLayers$;
1823
- var selectedBaseLayers = _ref.selectedBaseLayers,
1824
- availableBaseLayers = _ref.availableBaseLayers,
1825
- onChangeBaseLayers = _ref.onChangeBaseLayers,
1826
- icon = _ref.icon,
1827
- tooltipPrefix = _ref.tooltipPrefix;
1828
- var _useCoreTranslation = useCoreTranslation(),
1829
- t = _useCoreTranslation.t;
1830
- if (!(availableBaseLayers != null && availableBaseLayers.length)) {
1831
- return jsx("div", {
1832
- children: t('layermanager-baselayers-no-available')
1833
- });
1834
- }
1835
- var nonEmptyTooltipPrefix = tooltipPrefix != null ? tooltipPrefix : t('layermanager-layer') + ": ";
1836
- var selectedBaseLayerId = typeof selectedBaseLayers[0] !== 'undefined' ? selectedBaseLayers[0].id : '';
1837
- var list = availableBaseLayers.map(function (layer) {
1838
- return {
1839
- value: layer.id
1840
- };
1841
- });
1842
- var currentIndex = availableBaseLayers.findIndex(function (layer) {
1843
- return selectedBaseLayerId === layer.id;
1844
- });
1845
- return jsx(FormControl, {
1846
- style: {
1847
- width: '100%'
1848
- },
1849
- children: jsxs(TooltipSelect, {
1850
- IconComponent: icon,
1851
- currentIndex: currentIndex,
1852
- disableUnderline: true,
1853
- inputProps: {
1854
- SelectDisplayProps: {
1855
- 'data-testid': 'selectBaseLayer'
1856
- }
1857
- },
1858
- isEnabled: true,
1859
- list: list,
1860
- onChange: function onChange(event) {
1861
- onChangeBaseLayers(event.target.value);
1862
- },
1863
- onChangeMouseWheel: function onChangeMouseWheel(e) {
1864
- return onChangeBaseLayers(e.value);
1865
- },
1866
- style: {
1867
- maxWidth: '100%'
1868
- },
1869
- tooltip: "" + nonEmptyTooltipPrefix + ((_availableBaseLayers$ = availableBaseLayers[currentIndex]) == null ? void 0 : _availableBaseLayers$.name),
1870
- value: selectedBaseLayerId,
1871
- children: [jsx(MenuItem, {
1872
- disabled: true,
1873
- children: t('layermanager-baselayers-title')
1874
- }), availableBaseLayers.map(function (baseLayer) {
1875
- return jsx(MenuItem, {
1876
- value: baseLayer.id,
1877
- children: baseLayer.name
1878
- }, baseLayer.id);
1879
- })]
1880
- })
1881
- });
1882
- };
1883
-
1884
- // Generate a layer id for an available baselayer to ensure same available baselayers have unique id's in case of multiple maps
1885
- // If already in selectedBaseLayers based on name or id, keep current id
1886
- var constructLayerId = function constructLayerId(baseLayer, selectedBaseLayers) {
1887
- var foundLayer = selectedBaseLayers.find(function (selectedBaseLayer) {
1888
- return (baseLayer == null ? void 0 : baseLayer.id) === (selectedBaseLayer == null ? void 0 : selectedBaseLayer.id) || baseLayer.name === selectedBaseLayer.name;
1889
- });
1890
- return foundLayer ? foundLayer.id : webmapUtils.generateLayerId();
1891
- };
1892
- var constructListAvailableBaseLayers = function constructListAvailableBaseLayers(selectedBaseLayers, preloadedAvailableBaseLayers, mapId) {
1893
- // Ensure we use unique id's for the base layers - excepting the ones that are currently selected, reuse the existing ids
1894
- // Add mapId of map these available base layers are added for
1895
- var baseLayersWithMapId = preloadedAvailableBaseLayers.map(function (baseLayer) {
1896
- var layerId = constructLayerId(baseLayer, selectedBaseLayers);
1897
- return Object.assign({}, baseLayer, {
1898
- mapId: mapId,
1899
- id: layerId
1900
- });
1901
- });
1902
- // Ensure that current selected baselayer(s) are in the baseLayersWithMapId array, otherwise add them
1903
- return selectedBaseLayers.reduce(function (list, selectedBaseLayer) {
1904
- var foundLayer = baseLayersWithMapId.find(function (layer) {
1905
- return layer.id === (selectedBaseLayer == null ? void 0 : selectedBaseLayer.id);
1906
- });
1907
- if (foundLayer) {
1908
- return list;
1909
- }
1910
- return list.concat(Object.assign({}, selectedBaseLayer, {
1911
- mapId: mapId
1912
- }));
1913
- }, baseLayersWithMapId);
1914
- };
1915
- var areAvailableBaseLayersSame = function areAvailableBaseLayersSame(availableBaseLayerList, newBaseLayerList) {
1916
- var availableList = availableBaseLayerList.map(function (layer) {
1917
- return layer.name;
1918
- });
1919
- var newList = newBaseLayerList.map(function (layer) {
1920
- return layer.name;
1921
- });
1922
- return isEqual(availableList, newList);
1923
- };
1924
- var BaseLayersConnect = function BaseLayersConnect(_ref) {
1925
- var mapId = _ref.mapId,
1926
- preloadedAvailableBaseLayers = _ref.preloadedAvailableBaseLayers,
1927
- tooltipPrefix = _ref.tooltipPrefix,
1928
- icon = _ref.icon;
1929
- var dispatch = useDispatch();
1930
- var selectedBaseLayers = useSelector(function (store) {
1931
- return mapSelectors.getMapBaseLayers(store, mapId);
1932
- });
1933
- var currentAvailableBaseLayers = useSelector(function (store) {
1934
- return layerSelectors.getAvailableBaseLayersForMap(store, mapId);
1935
- });
1936
- React.useEffect(function () {
1937
- var availableBaseLayersToBeAdded = constructListAvailableBaseLayers(selectedBaseLayers, preloadedAvailableBaseLayers, mapId);
1938
- var areBaseLayersSame = areAvailableBaseLayersSame(availableBaseLayersToBeAdded, currentAvailableBaseLayers);
1939
- if (!areBaseLayersSame) {
1940
- dispatch(layerActions.setAvailableBaseLayers({
1941
- layers: availableBaseLayersToBeAdded,
1942
- mapId: mapId
1943
- }));
1944
- }
1945
- // eslint-disable-next-line react-hooks/exhaustive-deps
1946
- }, [mapId, preloadedAvailableBaseLayers]);
1947
- var onChangeBaseLayers = function onChangeBaseLayers(newSelectedLayerId) {
1948
- var newBaseLayer = currentAvailableBaseLayers.filter(function (layer) {
1949
- return layer.id === newSelectedLayerId;
1950
- });
1951
- dispatch(layerActions.setBaseLayers({
1952
- mapId: mapId,
1953
- layers: newBaseLayer,
1954
- origin: layerTypes.LayerActionOrigin.layerManager
1955
- }));
1956
- };
1957
- return jsx(BaseLayers, {
1958
- availableBaseLayers: currentAvailableBaseLayers,
1959
- icon: icon,
1960
- onChangeBaseLayers: onChangeBaseLayers,
1961
- selectedBaseLayers: selectedBaseLayers,
1962
- tooltipPrefix: tooltipPrefix
1963
- });
1964
- };
1965
-
1966
1968
  var _excluded$6 = ["mapId", "preloadedAvailableBaseLayers", "preloadedServices", "tooltip", "settings"];
1967
1969
  var _onRenderTree = function onRenderTree(_ref) {
1968
1970
  var service = _ref.service,
@@ -2248,6 +2250,12 @@ var AcceptanceTime = function AcceptanceTime(_ref) {
2248
2250
  }, {
2249
2251
  value: '10',
2250
2252
  text: '00:10'
2253
+ }, {
2254
+ value: '15',
2255
+ text: '00:15'
2256
+ }, {
2257
+ value: '20',
2258
+ text: '00:20'
2251
2259
  }, {
2252
2260
  value: '30',
2253
2261
  text: '00:30'
@@ -4780,6 +4788,7 @@ var LayerInfoButtonConnect = function LayerInfoButtonConnect(_ref) {
4780
4788
  mapId = _ref.mapId,
4781
4789
  serviceUrl = _ref.serviceUrl,
4782
4790
  layerName = _ref.layerName,
4791
+ layerId = _ref.layerId,
4783
4792
  _ref$source = _ref.source,
4784
4793
  source = _ref$source === void 0 ? 'app' : _ref$source;
4785
4794
  var dispatch = useDispatch();
@@ -4789,6 +4798,9 @@ var LayerInfoButtonConnect = function LayerInfoButtonConnect(_ref) {
4789
4798
  var currentLayerInfo = useSelector(function (store) {
4790
4799
  return layerSelectors.getActiveLayerInfo(store);
4791
4800
  });
4801
+ var currentLayerStyle = useSelector(function (store) {
4802
+ return layerSelectors.getLayerStyle(store, layerId);
4803
+ });
4792
4804
  var isActive = layerName === (currentLayerInfo == null ? void 0 : currentLayerInfo.layerName) && serviceUrl === (currentLayerInfo == null ? void 0 : currentLayerInfo.serviceUrl) && isOpenInStore;
4793
4805
  var onClick = function onClick() {
4794
4806
  if (!isActive) {
@@ -4796,7 +4808,8 @@ var LayerInfoButtonConnect = function LayerInfoButtonConnect(_ref) {
4796
4808
  layerName: layerName,
4797
4809
  serviceUrl: serviceUrl,
4798
4810
  source: source,
4799
- mapId: mapId
4811
+ mapId: mapId,
4812
+ style: currentLayerStyle
4800
4813
  }));
4801
4814
  } else {
4802
4815
  dispatch(layerActions.hideLayerInfo());
@@ -4834,6 +4847,7 @@ var LayerInfoDialogConnect = function LayerInfoDialogConnect(_ref) {
4834
4847
  onClose: onCloseDialog,
4835
4848
  onMouseDown: setDialogOrder,
4836
4849
  order: dialogOrder,
4850
+ selectedStyle: layerInfo == null ? void 0 : layerInfo.style,
4837
4851
  serviceName: currentService == null ? void 0 : currentService.name,
4838
4852
  serviceUrl: currentService == null ? void 0 : currentService.serviceUrl,
4839
4853
  source: source
@@ -4939,6 +4953,7 @@ var LayerRowConnect = /*#__PURE__*/React.memo(function (_ref) {
4939
4953
  layerShowLayerInfoLayout: jsx(LayerInfoButtonConnect, {
4940
4954
  isFeatureLayer: isFeatureLayer,
4941
4955
  isLayerMissing: isLayerMissing,
4956
+ layerId: layerId,
4942
4957
  layerName: layerName,
4943
4958
  mapId: mapId,
4944
4959
  serviceUrl: layerServiceUrl
@@ -6086,6 +6101,12 @@ var ClockConnect = function ClockConnect(_ref) {
6086
6101
  var isMapClockVisible = useSelector(function (store) {
6087
6102
  return mapSelectors.getIsClockVisible(store, mapId);
6088
6103
  });
6104
+ var clockPosition = useSelector(function (store) {
6105
+ return mapSelectors.getClockPosition(store, mapId);
6106
+ });
6107
+ var clockSize = useSelector(function (store) {
6108
+ return mapSelectors.getClockSize(store, mapId);
6109
+ });
6089
6110
  var onToggleClock = function onToggleClock(isClockVisible) {
6090
6111
  dispatch(mapActions.toggleClock({
6091
6112
  mapId: mapId,
@@ -6093,9 +6114,27 @@ var ClockConnect = function ClockConnect(_ref) {
6093
6114
  origin: mapEnums.MapActionOrigin.map
6094
6115
  }));
6095
6116
  };
6117
+ var onSetPosition = function onSetPosition(position) {
6118
+ dispatch(mapActions.setClockPositionSize({
6119
+ mapId: mapId,
6120
+ position: position,
6121
+ origin: mapEnums.MapActionOrigin.map
6122
+ }));
6123
+ };
6124
+ var onSetSize = function onSetSize(size) {
6125
+ dispatch(mapActions.setClockPositionSize({
6126
+ mapId: mapId,
6127
+ size: size,
6128
+ origin: mapEnums.MapActionOrigin.map
6129
+ }));
6130
+ };
6096
6131
  return jsx(Clock, {
6097
6132
  isVisible: isMapClockVisible,
6133
+ onSetPosition: onSetPosition,
6134
+ onSetSize: onSetSize,
6098
6135
  onToggleClock: onToggleClock,
6136
+ position: clockPosition,
6137
+ size: clockSize,
6099
6138
  time: selectedTime
6100
6139
  });
6101
6140
  };
@@ -6929,16 +6968,34 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref)
6929
6968
  hoverSelect = _ref.hoverSelect;
6930
6969
  var store = useStore();
6931
6970
  var dispatch = useDispatch();
6971
+ var activeDrawToolId = useSelector(drawingToolSelectors.getActiveDrawToolId);
6972
+ var activeDrawMode = useSelector(function (store) {
6973
+ return drawingToolSelectors.getActiveDrawMode(store, activeDrawToolId);
6974
+ });
6975
+ var shouldAllowMultipleShapes = useSelector(function (store) {
6976
+ return drawingToolSelectors.getShouldAllowMultipleShapes(store, activeDrawToolId);
6977
+ });
6978
+ var geoJSONIntersectionLayerId = useSelector(function (store) {
6979
+ return drawingToolSelectors.getGeoJSONIntersectionLayerId(store, activeDrawToolId);
6980
+ });
6981
+ var geoJSONIntersectionBoundsLayerId = useSelector(function (store) {
6982
+ return drawingToolSelectors.getGeoJSONIntersectionBoundsLayerId(store, activeDrawToolId);
6983
+ });
6932
6984
  var onFeatureClick = React.useCallback(function (feature) {
6933
6985
  var previouslySelectedFeatureIndex = layer.selectedFeatureIndex;
6934
6986
  var selectedFeatureIndex = layer.geojson.features.findIndex(function (feat) {
6935
6987
  return feature[0] && feat.id === feature[0].getId();
6936
6988
  });
6937
- if (selectedFeatureIndex !== -1 && selectedFeatureIndex !== previouslySelectedFeatureIndex) {
6989
+ if (selectedFeatureIndex !== -1) {
6938
6990
  dispatch(layerActions.setSelectedFeature({
6939
6991
  layerId: layerId,
6940
6992
  selectedFeatureIndex: selectedFeatureIndex
6941
6993
  }));
6994
+ dispatch(layerActions.toggleFeatureMode({
6995
+ layerId: layerId,
6996
+ isInEditMode: true,
6997
+ drawMode: ''
6998
+ }));
6942
6999
  dispatch(layerActions.updateFeatureProperties({
6943
7000
  layerId: layerId,
6944
7001
  properties: {
@@ -6957,23 +7014,39 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref)
6957
7014
  }
6958
7015
  }
6959
7016
  }, [dispatch, layer.geojson, layer.selectedFeatureIndex, layerId]);
7017
+ var onNoFeatureClick = React.useCallback(function () {
7018
+ if (activeDrawToolId) {
7019
+ // do not disable edit mode when a drawing tool is active
7020
+ return;
7021
+ }
7022
+ dispatch(layerActions.toggleFeatureMode({
7023
+ layerId: layerId,
7024
+ isInEditMode: false,
7025
+ drawMode: ''
7026
+ }));
7027
+ }, [activeDrawToolId, dispatch, layerId]);
7028
+ var onViewOnlyFeatureClick = React.useCallback(function (feature) {
7029
+ if (activeDrawToolId) {
7030
+ // do not select another feature when a drawing tool is active
7031
+ return;
7032
+ }
7033
+ onFeatureClick(feature);
7034
+ }, [activeDrawToolId, onFeatureClick]);
6960
7035
  var updateFeature = React.useCallback(function (geojson, reason) {
6961
7036
  if (!layerId) {
6962
7037
  window.console.error('updateFeature without layerId');
6963
7038
  return;
6964
7039
  }
6965
- var activeDrawToolId = drawingToolSelectors.getActiveDrawToolId(store.getState());
6966
- var activeDrawMode = drawingToolSelectors.getActiveDrawMode(store.getState(), activeDrawToolId);
6967
7040
  dispatch(layerActions.updateFeature({
6968
7041
  geojson: geojson,
6969
7042
  reason: reason,
6970
7043
  layerId: layerId,
6971
- shouldAllowMultipleShapes: drawingToolSelectors.getShouldAllowMultipleShapes(store.getState(), activeDrawToolId),
6972
- geoJSONIntersectionLayerId: drawingToolSelectors.getGeoJSONIntersectionLayerId(store.getState(), activeDrawToolId),
6973
- geoJSONIntersectionBoundsLayerId: drawingToolSelectors.getGeoJSONIntersectionBoundsLayerId(store.getState(), activeDrawToolId),
7044
+ shouldAllowMultipleShapes: shouldAllowMultipleShapes,
7045
+ geoJSONIntersectionLayerId: geoJSONIntersectionLayerId,
7046
+ geoJSONIntersectionBoundsLayerId: geoJSONIntersectionBoundsLayerId,
6974
7047
  selectionType: activeDrawMode == null ? void 0 : activeDrawMode.selectionType
6975
7048
  }));
6976
- }, [dispatch, store, layerId]);
7049
+ }, [layerId, dispatch, shouldAllowMultipleShapes, geoJSONIntersectionLayerId, geoJSONIntersectionBoundsLayerId, activeDrawMode == null ? void 0 : activeDrawMode.selectionType]);
6977
7050
  var exitFeatureDrawMode = React.useCallback(function (reason) {
6978
7051
  if (!layerId) {
6979
7052
  window.console.error('exitFeatureDrawMode without layerId');
@@ -7003,6 +7076,8 @@ var OpenLayersFeatureLayerConnect = function OpenLayersFeatureLayerConnect(_ref)
7003
7076
  exitDrawModeCallback: exitFeatureDrawMode,
7004
7077
  geojson: layer.geojson,
7005
7078
  isInEditMode: layer.isInEditMode || false,
7079
+ onNoFeatureClick: onNoFeatureClick,
7080
+ onViewOnlyFeatureClick: onViewOnlyFeatureClick,
7006
7081
  selectedFeatureIndex: layer.selectedFeatureIndex || 0,
7007
7082
  updateGeojson: updateFeature,
7008
7083
  viewOnlyStyle: style
@@ -7185,6 +7260,15 @@ function useFitAndHighlightWarningFeature(_ref) {
7185
7260
  }
7186
7261
  }, [view, warningDialogFeatures, srs, dispatch, mapId]);
7187
7262
  }
7263
+ /** Compare value with current time and if difference is more than factor times timeStep returns true */
7264
+ var getIsOutdated = function getIsOutdated(compareValue, timeStep, factor) {
7265
+ var currentDate = dateUtils.utc();
7266
+ var diff = dateUtils.differenceInMinutes(currentDate, dateUtils.createDate(compareValue));
7267
+ if (diff > timeStep * factor) {
7268
+ return true;
7269
+ }
7270
+ return false;
7271
+ };
7188
7272
 
7189
7273
  var OlMapViewLayerConnect = function OlMapViewLayerConnect(layerProps) {
7190
7274
  var layerId = layerProps.layerId,
@@ -7819,7 +7903,7 @@ var MapOptionsButtonConnect = function MapOptionsButtonConnect(_ref) {
7819
7903
  * @param {object} [controls.zoomControls] **optional** controls: object - toggle the map controls, zoomControls defaults to true
7820
7904
  */
7821
7905
  var OlMapViewConnect = function OlMapViewConnect(_ref) {
7822
- var _useSelector2, _featureProperties$va;
7906
+ var _useSelector2, _useSelector3, _featureProperties$va;
7823
7907
  var mapId = _ref.mapId,
7824
7908
  children = _ref.children,
7825
7909
  _ref$controls = _ref.controls,
@@ -7921,7 +8005,21 @@ var OlMapViewConnect = function OlMapViewConnect(_ref) {
7921
8005
  var isAnimating = (_useSelector2 = useSelector(function (store) {
7922
8006
  return mapSelectors.linkedMapAnimationInfo(store, mapId);
7923
8007
  })) == null ? void 0 : _useSelector2.isAnimating;
8008
+ var autoUpdateLayerId = useSelector(function (store) {
8009
+ return mapSelectors.getAutoUpdateLayerId(store, mapId);
8010
+ });
8011
+ var shouldAutoUpdate = useSelector(function (store) {
8012
+ return mapSelectors.isAutoUpdating(store, mapId);
8013
+ });
8014
+ var autoUpdateLayerMaxValue = (_useSelector3 = useSelector(function (store) {
8015
+ return layerSelectors.getLayerTimeDimension(store, autoUpdateLayerId);
8016
+ })) == null ? void 0 : _useSelector3.maxValue;
8017
+ var autoUpdateTimeStep = useSelector(function (store) {
8018
+ return layerSelectors.getTimeStepForLayerId(store, autoUpdateLayerId);
8019
+ });
7924
8020
  var dispatch = useDispatch();
8021
+ var _useCoreTranslation = useCoreTranslation(),
8022
+ t = _useCoreTranslation.t;
7925
8023
  var updateLayerInformation = React.useCallback(function (payload) {
7926
8024
  var _payload$layerDimensi, _payload$layerDimensi2;
7927
8025
  var updatedPayLoad = Object.assign({}, payload, {
@@ -8122,6 +8220,28 @@ var OlMapViewConnect = function OlMapViewConnect(_ref) {
8122
8220
  // eslint-disable-next-line react-hooks/exhaustive-deps
8123
8221
  }, [mapId, updateLayerInformation, layerIds]);
8124
8222
  useSetIntervalWhenVisible(refetchLayers, 60000);
8223
+ /** Check if the autoUpdate layer has outdated data and inform the user by setting the map error */
8224
+ var checkIfDataOutdated = React.useCallback(function () {
8225
+ if (!shouldAutoUpdate || !autoUpdateLayerId || !autoUpdateLayerMaxValue || !autoUpdateTimeStep) {
8226
+ dispatch(mapActions.setMapPresetError({
8227
+ mapId: mapId,
8228
+ error: undefined
8229
+ }));
8230
+ return;
8231
+ }
8232
+ // check that the difference is more than 4 timesteps with the current time
8233
+ var isOutdated = getIsOutdated(autoUpdateLayerMaxValue, autoUpdateTimeStep, 4);
8234
+ dispatch(mapActions.setMapPresetError({
8235
+ mapId: mapId,
8236
+ error: isOutdated ? t('data-outdated') : undefined
8237
+ }));
8238
+ }, [autoUpdateLayerId, autoUpdateLayerMaxValue, autoUpdateTimeStep, dispatch, mapId, shouldAutoUpdate, t]);
8239
+ // Check every minute if data is outdated
8240
+ useSetIntervalWhenVisible(checkIfDataOutdated, 60000);
8241
+ // Recheck if data is outdated if the function is updated
8242
+ React.useEffect(function () {
8243
+ checkIfDataOutdated();
8244
+ }, [checkIfDataOutdated]);
8125
8245
  useMapViewLoadingIndicator(mapId, mapLayerIds);
8126
8246
  var _React$useState2 = React.useState({
8127
8247
  debugMode: false
@@ -9040,8 +9160,15 @@ var TimeSliderConnect = function TimeSliderConnect(_ref) {
9040
9160
  var _React$useState = React.useState(selectedTime),
9041
9161
  unfilteredSelectedTime = _React$useState[0],
9042
9162
  setUnfilteredSelectedTime = _React$useState[1];
9163
+ // Store unfilteredSelectedTime in a ref for callbacks
9164
+ var unfilteredSelectedTimeRef = React.useRef(unfilteredSelectedTime);
9165
+ React.useEffect(function () {
9166
+ unfilteredSelectedTimeRef.current = unfilteredSelectedTime;
9167
+ }, [unfilteredSelectedTime]);
9043
9168
  // Reference to the last time value set by this timeslider
9044
9169
  var lastTimeValueAsSetByThisTimeSlider = React.useRef();
9170
+ // Track the last selectedTime we processed to avoid unnecessary updates
9171
+ var lastProcessedSelectedTime = React.useRef(selectedTime);
9045
9172
  // Set new time in the redux state
9046
9173
  var _onSetNewDate = React.useCallback(function (newDate) {
9047
9174
  // Remember that this timeslider has set this time
@@ -9061,22 +9188,59 @@ var TimeSliderConnect = function TimeSliderConnect(_ref) {
9061
9188
  }, [dispatch, isAnimating, mapId, sourceId]);
9062
9189
  // Update local state when time is updated outside of this component, e.g. during animation or syncgroups
9063
9190
  React.useEffect(function () {
9191
+ // Only update if selectedTime has actually changed (not just timeStep)
9192
+ if (lastProcessedSelectedTime.current === selectedTime) {
9193
+ return;
9194
+ }
9064
9195
  var selectedTimeAsIsoString = timeToIso(selectedTime);
9065
- if (selectedTimeAsIsoString !== lastTimeValueAsSetByThisTimeSlider.current) {
9196
+ // Check if this is our own update bouncing back
9197
+ var isOurOwnUpdate = selectedTimeAsIsoString === lastTimeValueAsSetByThisTimeSlider.current;
9198
+ if (isOurOwnUpdate) {
9199
+ // Our update was processed, clear the flag and update tracking
9200
+ lastTimeValueAsSetByThisTimeSlider.current = undefined;
9201
+ lastProcessedSelectedTime.current = selectedTime;
9202
+ } else {
9203
+ // Time changed from outside this component (e.g., backward/forward buttons, animation)
9204
+ // Cancel any pending debounced updates and sync local state
9205
+ onsetNewDateDebounced.cancel();
9206
+ lastProcessedSelectedTime.current = selectedTime;
9066
9207
  setUnfilteredSelectedTime(selectedTime);
9208
+ // Clear the flag so we don't block future external updates to this same time
9209
+ lastTimeValueAsSetByThisTimeSlider.current = undefined;
9067
9210
  }
9068
9211
  }, [selectedTime]);
9212
+ // Store timeStep in a ref so we can use the latest value without causing re-renders
9213
+ var timeStepRef = React.useRef(timeStep);
9214
+ var prevTimeStepRef = React.useRef(timeStep);
9215
+ React.useEffect(function () {
9216
+ var timeStepChanged = prevTimeStepRef.current !== timeStep;
9217
+ prevTimeStepRef.current = timeStep;
9218
+ timeStepRef.current = timeStep;
9219
+ // When timestep changes, apply smart rounding to current time
9220
+ // For large timesteps (>12h), round to nearest hour instead of timestep
9221
+ if (timeStepChanged) {
9222
+ var roundingStep = timeStep > 12 * 60 ? 60 : timeStep;
9223
+ var snappedTime = getFilteredTime(unfilteredSelectedTime, roundingStep, dataStartTime, dataEndTime);
9224
+ if (snappedTime !== unfilteredSelectedTime) {
9225
+ setUnfilteredSelectedTime(snappedTime);
9226
+ onsetNewDateDebounced(timeToIso(snappedTime), _onSetNewDate);
9227
+ }
9228
+ }
9229
+ }, [timeStep, unfilteredSelectedTime, dataStartTime, dataEndTime, _onSetNewDate]);
9069
9230
  // Function used by timeslider components to update the unfiltered selected time
9070
9231
  var setUnfilteredSelectedTimeFn = React.useCallback(function (unfilteredSelectedTimeFromComponents) {
9071
- var makeFilteredSelectedTime = function makeFilteredSelectedTime(timeValue) {
9072
- return getFilteredTime(timeValue, timeStep, dataStartTime, dataEndTime);
9073
- };
9074
- setUnfilteredSelectedTime(unfilteredSelectedTimeFromComponents);
9075
- var filteredIsoTime = makeFilteredSelectedTime(unfilteredSelectedTimeFromComponents);
9076
- if (selectedTime !== filteredIsoTime) {
9077
- onsetNewDateDebounced(timeToIso(filteredIsoTime), _onSetNewDate);
9232
+ // Only update if the value has actually changed
9233
+ if (unfilteredSelectedTimeFromComponents === unfilteredSelectedTimeRef.current) {
9234
+ return;
9078
9235
  }
9079
- }, [dataEndTime, dataStartTime, _onSetNewDate, selectedTime, timeStep]);
9236
+ // Snap to nearest timestep when clicking/dragging on timeslider
9237
+ // For timesteps >= 1 hour, snap to nearest hour
9238
+ // For smaller timesteps, snap to the timestep itself (e.g., 5min, 10min, 15min)
9239
+ var roundingStep = timeStepRef.current >= 60 ? 60 : timeStepRef.current;
9240
+ var timeToSet = getFilteredTime(unfilteredSelectedTimeFromComponents, roundingStep, dataStartTime, dataEndTime);
9241
+ setUnfilteredSelectedTime(timeToSet);
9242
+ onsetNewDateDebounced(timeToIso(timeToSet), _onSetNewDate);
9243
+ }, [dataEndTime, dataStartTime, _onSetNewDate]);
9080
9244
  // Move animation bar when user changes time using time picker
9081
9245
  // Animation bar however cannot be moved into a time where there is no data
9082
9246
  var moveAnimationUsingCalendar = function moveAnimationUsingCalendar(newTime) {
@@ -9099,8 +9263,13 @@ var TimeSliderConnect = function TimeSliderConnect(_ref) {
9099
9263
  }));
9100
9264
  };
9101
9265
  var onCalendarSelect = function onCalendarSelect(newSelectedTime) {
9102
- setUnfilteredSelectedTimeFn(newSelectedTime);
9103
- moveAnimationUsingCalendar(newSelectedTime);
9266
+ // When user explicitly sets time via calendar, snap to nearest available timestep
9267
+ // For large timesteps (>12h), round to nearest hour instead of timestep
9268
+ var roundingStep = timeStep > 12 * 60 ? 60 : timeStep;
9269
+ var snappedTime = getFilteredTime(newSelectedTime, roundingStep, dataStartTime, dataEndTime);
9270
+ setUnfilteredSelectedTime(snappedTime);
9271
+ onsetNewDateDebounced(timeToIso(snappedTime), _onSetNewDate);
9272
+ moveAnimationUsingCalendar(snappedTime);
9104
9273
  };
9105
9274
  var secondsPerPx = useSelector(function (store) {
9106
9275
  return mapSelectors.getMapTimeSliderSecondsPerPx(store, mapId);
@@ -9116,10 +9285,15 @@ var TimeSliderConnect = function TimeSliderConnect(_ref) {
9116
9285
  var event = _ref2.event,
9117
9286
  deltaY = _ref2.deltaY;
9118
9287
  if (!(event.ctrlKey || event.metaKey || event.shiftKey || event.altKey)) {
9119
- var pixelsPerScroll = -deltaY * timeStep / (2 * secondsPerPx);
9120
- moveSelectedTimePx(pixelsPerScroll, timeSliderWidth, centerTime, dataStartTime, dataEndTime, secondsPerPx, timeStep, unfilteredSelectedTime, setUnfilteredSelectedTimeFn);
9288
+ if (deltaY === 0) {
9289
+ return;
9290
+ }
9291
+ // timeStepRef.current is in minutes, convert to seconds
9292
+ var timeStepInSeconds = timeStepRef.current * 60;
9293
+ var pixelsPerScroll = -deltaY / Math.abs(deltaY) * (timeStepInSeconds / secondsPerPx);
9294
+ moveSelectedTimePx(pixelsPerScroll, timeSliderWidth, centerTime, dataStartTime, dataEndTime, secondsPerPx, timeStepRef.current, unfilteredSelectedTimeRef.current, setUnfilteredSelectedTimeFn);
9121
9295
  }
9122
- }, [timeSliderWidth, centerTime, dataEndTime, dataStartTime, secondsPerPx, setUnfilteredSelectedTimeFn, timeStep, unfilteredSelectedTime]);
9296
+ }, [timeSliderWidth, centerTime, dataEndTime, dataStartTime, secondsPerPx, setUnfilteredSelectedTimeFn]);
9123
9297
  React.useEffect(function () {
9124
9298
  if (isTimeScrollingEnabled && mapWindowRef != null && mapWindowRef.current) {
9125
9299
  var handleWheel = function handleWheel(event) {
@@ -9328,7 +9502,9 @@ var ConfigurableMapConnect = function ConfigurableMapConnect(_ref) {
9328
9502
  mapId: mapId,
9329
9503
  layer: {
9330
9504
  geojson: emptyGeoJSON,
9331
- layerType: LayerType.featureLayer
9505
+ layerType: LayerType.featureLayer,
9506
+ isSelectable: false,
9507
+ isInEditMode: false
9332
9508
  },
9333
9509
  layerId: getSingularDrawtoolDrawLayerId(mapId),
9334
9510
  origin: 'ConfigurableMapConnect'
@@ -10501,7 +10677,7 @@ var SelectedFeature = function SelectedFeature(_ref) {
10501
10677
  return Math.abs(lat) + "\xB0 " + latHemisphere + ", " + Math.abs(lon) + "\xB0 " + lonHemisphere;
10502
10678
  };
10503
10679
  var formattedCoordinates = useMemo(function () {
10504
- if (feature && feature.geometry.type === 'Point') {
10680
+ if ((feature == null ? void 0 : feature.geometry.type) === 'Point') {
10505
10681
  var latitude = feature.geometry.coordinates[1];
10506
10682
  var longitude = feature.geometry.coordinates[0];
10507
10683
  return getFormattedCoordinates(latitude, longitude);
@@ -11035,4 +11211,4 @@ var storyUtils = /*#__PURE__*/Object.freeze({
11035
11211
  useDefaultMapSettings: useDefaultMapSettings
11036
11212
  });
11037
11213
 
11038
- export { CORE_NAMESPACE, ConfigurableMapConnect, CoreI18nProvider, CoreStoreProvider, CoreThemeProvider, CoreThemeStoreProvider, DemoWrapper, DemoWrapperConnect, HarmonieTempAndPrecipPreset, LanguageSelect, LayerInfoButtonConnect, LayerInfoDialogConnect, LayerManager, BaseLayerRow as LayerManagerBaseLayerRow, LayerManagerConnect, DescriptionRow as LayerManagerDescriptionRow, HeaderOptions as LayerManagerHeaderOptions, LayerContainerRow as LayerManagerLayerContainerRow, LayerManagerMapButtonConnect, LegendConnect, LegendMapButtonConnect, LoadingIndicatorProgressBar, LocationSearch, LocationSearchConnect, MultiDimensionSelectMapButtonsConnect, MultiMapMultiDimensionSelectConnect as MultiMapDimensionSelectConnect, MultiMapViewConnect, MyMapLocation, OlMapViewConnect, RouterWrapperConnect, SearchControlButtonConnect, SelectedFeaturesDialogConnect, SyncGroupViewerConnect, TimeSliderConnect, componentsLookUp, coreTranslations, defaultBbox, defaultConfigurations, fakeLocationDetailList, fakeLocationList, filterMapPresets, filterServices, filterTimeSeriesServices, getCenterOfLinkedFeature, getLanguageFromLocalStorage, languageLocalStorageKey, locationApiEndpoints, makeLayerInfoPayload, makePrefetchTimeSpan, saveLanguageToLocalStorage, storyUtils, testLayers, useFetchServices, useFitAndHighlightWarningFeature, useGetOpenLayersView, useLocationDetail, useLocationList, usePrefetchTimeSpan, useUpdateTimeSpan, useUpdateTimestep };
11214
+ export { CORE_NAMESPACE, ConfigurableMapConnect, CoreI18nProvider, CoreStoreProvider, CoreThemeProvider, CoreThemeStoreProvider, DemoWrapper, DemoWrapperConnect, HarmonieTempAndPrecipPreset, LanguageSelect, LayerInfoButtonConnect, LayerInfoDialogConnect, LayerManager, BaseLayerRow as LayerManagerBaseLayerRow, LayerManagerConnect, DescriptionRow as LayerManagerDescriptionRow, HeaderOptions as LayerManagerHeaderOptions, LayerContainerRow as LayerManagerLayerContainerRow, LayerManagerMapButtonConnect, LegendConnect, LegendMapButtonConnect, LoadingIndicatorProgressBar, LocationSearch, LocationSearchConnect, MultiDimensionSelectMapButtonsConnect, MultiMapMultiDimensionSelectConnect as MultiMapDimensionSelectConnect, MultiMapViewConnect, MyMapLocation, OlMapViewConnect, RouterWrapperConnect, SearchControlButtonConnect, SelectedFeaturesDialogConnect, SyncGroupViewerConnect, TimeSliderConnect, componentsLookUp, coreTranslations, defaultBbox, defaultConfigurations, fakeLocationDetailList, fakeLocationList, filterMapPresets, filterServices, filterTimeSeriesServices, getCenterOfLinkedFeature, getIsOutdated, getLanguageFromLocalStorage, languageLocalStorageKey, locationApiEndpoints, makeLayerInfoPayload, makePrefetchTimeSpan, saveLanguageToLocalStorage, storyUtils, testLayers, useFetchServices, useFitAndHighlightWarningFeature, useGetOpenLayersView, useLocationDetail, useLocationList, usePrefetchTimeSpan, useUpdateTimeSpan, useUpdateTimestep };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeoweb/core",
3
- "version": "15.1.0",
3
+ "version": "15.2.0",
4
4
  "description": "GeoWeb Core library for the opengeoweb project",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -8,22 +8,22 @@
8
8
  "url": "git@gitlab.com:opengeoweb/opengeoweb.git"
9
9
  },
10
10
  "dependencies": {
11
- "@opengeoweb/shared": "15.1.0",
11
+ "@opengeoweb/shared": "15.2.0",
12
12
  "react-redux": "^9.2.0",
13
- "@opengeoweb/store": "15.1.0",
14
- "@opengeoweb/time-slider": "15.1.0",
13
+ "@opengeoweb/store": "15.2.0",
14
+ "@opengeoweb/time-slider": "15.2.0",
15
15
  "@reduxjs/toolkit": "^2.6.1",
16
- "@opengeoweb/webmap-react": "15.1.0",
17
- "@opengeoweb/webmap": "15.1.0",
18
- "@opengeoweb/theme": "15.1.0",
16
+ "@opengeoweb/webmap-react": "15.2.0",
17
+ "@opengeoweb/webmap": "15.2.0",
18
+ "@opengeoweb/theme": "15.2.0",
19
19
  "axios": "^1.7.7",
20
- "@opengeoweb/layer-select": "15.1.0",
20
+ "@opengeoweb/layer-select": "15.2.0",
21
21
  "lodash": "^4.17.21",
22
22
  "ol": "^10.4.0",
23
23
  "react-sortablejs": "^6.1.4",
24
24
  "sortablejs": "^1.15.1",
25
25
  "@mui/system": "^7.3.2",
26
- "@opengeoweb/snackbar": "15.1.0",
26
+ "@opengeoweb/snackbar": "15.2.0",
27
27
  "react-router-dom": "^6.21.0",
28
28
  "react-draggable": "^4.4.6",
29
29
  "i18next": "^25.0.1",
@@ -31,7 +31,7 @@
31
31
  "dompurify": "^3.0.6",
32
32
  "@mui/material": "^7.0.1",
33
33
  "@tanstack/react-query": "^5.85.5",
34
- "@opengeoweb/api": "15.1.0",
34
+ "@opengeoweb/api": "15.2.0",
35
35
  "@types/geojson": "^7946.0.14",
36
36
  "@turf/turf": "^7.2.0",
37
37
  "proj4": "^2.15.0"
@@ -6,6 +6,7 @@ interface LayerInfoButtonProps {
6
6
  mapId: string;
7
7
  serviceUrl: string;
8
8
  layerName: string;
9
+ layerId: string;
9
10
  source?: uiTypes.Source;
10
11
  }
11
12
  export declare const LayerInfoButtonConnect: React.FC<LayerInfoButtonProps>;
@@ -17,4 +17,6 @@ interface UseFitAndHighlightWarningFeatureOptions {
17
17
  mapId: string;
18
18
  }
19
19
  export declare function useFitAndHighlightWarningFeature({ view, warningDialogFeatures, srs, mapId, }: UseFitAndHighlightWarningFeatureOptions): void;
20
+ /** Compare value with current time and if difference is more than factor times timeStep returns true */
21
+ export declare const getIsOutdated: (compareValue: string, timeStep: number, factor: number) => boolean;
20
22
  export {};
@@ -18,7 +18,9 @@ export declare const multiDimensionLayer: {
18
18
  currentValue: string;
19
19
  values?: undefined;
20
20
  })[];
21
- }, WmdefaultReduxLayerRadarKNMI: WMLayer, defaultReduxLayerRadarKNMI: import("@opengeoweb/webmap").LayerOptions, defaultReduxLayerRadarColor: import("@opengeoweb/webmap").LayerOptions, multiDimensionLayer3: import("@opengeoweb/webmap").LayerFoundation;
21
+ }, WmdefaultReduxLayerRadarKNMI: WMLayer, defaultReduxLayerRadarKNMI: import("@opengeoweb/webmap").LayerOptions, defaultReduxLayerRadarColor: import("@opengeoweb/webmap").LayerOptions, multiDimensionLayer3: import("@opengeoweb/webmap").LayerFoundation, defaultReduxLayerRadarKNMIWithStyles: import("@opengeoweb/webmap").LayerFoundation & {
22
+ styles: import("@opengeoweb/webmap").Style[];
23
+ };
22
24
  export declare const flDimensionLayer: layerTypes.Layer;
23
25
  export declare const layerWithSingleDimensionValue: WMLayer;
24
26
  export declare const WmMultiDimensionLayer: WMLayer;
@@ -1,11 +0,0 @@
1
- import React from 'react';
2
- import type { serviceTypes } from '@opengeoweb/store';
3
- interface WMSLoaderProps {
4
- onClickService?: (serviceURL: string, layerName: string) => void;
5
- onRenderTree?: (service: serviceTypes.InitialService) => React.ReactNode;
6
- highlightedLayers?: [];
7
- preloadedServices?: serviceTypes.InitialService[];
8
- tooltip?: string;
9
- }
10
- declare const WMSLoader: React.FC<WMSLoaderProps>;
11
- export default WMSLoader;
@@ -1 +0,0 @@
1
- export {};
@@ -1,12 +0,0 @@
1
- import type { StoryObj } from '@storybook/react-webpack5';
2
- import React from 'react';
3
- import WMSLoader from './WMSLoader';
4
- declare const _default: {
5
- title: string;
6
- tags: string[];
7
- };
8
- export default _default;
9
- type Story = StoryObj<typeof WMSLoader>;
10
- export declare const DemoWMSLoad: React.FC;
11
- export declare const WMSLoaderLight: Story;
12
- export declare const WMSLoaderDark: Story;
@@ -1,21 +0,0 @@
1
- import React from 'react';
2
- import type { serviceTypes } from '@opengeoweb/store';
3
- import { LayerType } from '@opengeoweb/webmap';
4
- interface WMSLoaderConnectProps {
5
- mapId: string;
6
- preloadedServices?: serviceTypes.InitialService[];
7
- layerType?: LayerType;
8
- tooltip?: string;
9
- }
10
- /**
11
- * A pop-up allowing you to add new WMS sources which can then be displayed on the map.
12
- * A list of preconfigured sources can be given to the component which will always be availble to retrieve layers from
13
- *
14
- * Expects the following props:
15
- * @param {string} mapId mapId: string - Id of the map
16
- * @param {ServiceRefactorMe[]} [preloadedServices] **optional** preloadedServices: array of Service objects - contains an array of Service objects that are to be loaded as preconfigured WMS services
17
- * @example
18
- * ``` <WMSLoaderConnect mapId="mapid_1" preloadedServices = {preloadedServicesList} /> ```
19
- */
20
- declare const WMSLoaderConnect: React.FC<WMSLoaderConnectProps>;
21
- export default WMSLoaderConnect;