@eeacms/volto-arcgis-block 0.1.396 → 0.1.397

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/CHANGELOG.md CHANGED
@@ -4,11 +4,19 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ ### [0.1.397](https://github.com/eea/volto-arcgis-block/compare/0.1.396...0.1.397) - 9 October 2025
8
+
9
+ #### :hammer_and_wrench: Others
10
+
11
+ - Merge pull request #1035 from eea/CLMS-292957 [Unai Bolivar - [`830053b`](https://github.com/eea/volto-arcgis-block/commit/830053bb4f035a484b0d1fd8a4d130d7ed38686a)]
12
+ - (feat): temporal data fetched from /@getcalogapi fully implemented into time slider widget [Unai Bolivar - [`c3bff63`](https://github.com/eea/volto-arcgis-block/commit/c3bff63b6b2429f5a8a2a006f27b376e3ae35e1b)]
13
+ - (bug): Time slider opens and fully loads when using the active layers tab button. Working on fixing the time sldier button behavior on the TOC menu [Unai Bolivar - [`1363032`](https://github.com/eea/volto-arcgis-block/commit/1363032c58922c2af623ed4c57bcc1951230a254)]
14
+ - (bug): faulty time slider button behavior that crashed the app fixed. [Unai Bolivar - [`b3227a1`](https://github.com/eea/volto-arcgis-block/commit/b3227a1672bd03534886ac270c568246df58666b)]
15
+ - (bug): Restored the bookmark data functionality that was delete on PR merge [Unai Bolivar - [`f36075a`](https://github.com/eea/volto-arcgis-block/commit/f36075aee1aa900403cc8b5182064bdbfb95c733)]
7
16
  ### [0.1.396](https://github.com/eea/volto-arcgis-block/compare/0.1.395...0.1.396) - 9 October 2025
8
17
 
9
18
  #### :hammer_and_wrench: Others
10
19
 
11
- - Merge pull request #1033 from eea/CLMS-292637-UPDATED [Unai Bolivar - [`ec88d8a`](https://github.com/eea/volto-arcgis-block/commit/ec88d8a0bae01b4b4513dcd6f6efb65e0fb39e99)]
12
20
  - (task): Bookmark thumbnail is saved along with the rest of the bookmark data. [Unai Bolivar - [`c57f925`](https://github.com/eea/volto-arcgis-block/commit/c57f925eb112a455fa2bed7150003a4633984b1a)]
13
21
  - (task): bookmark data persistence managed. [Unai Bolivar - [`10cd300`](https://github.com/eea/volto-arcgis-block/commit/10cd300f6af9d1cfc457f58dadadaf9540890d19)]
14
22
  ### [0.1.395](https://github.com/eea/volto-arcgis-block/compare/0.1.394...0.1.395) - 3 October 2025
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-arcgis-block",
3
- "version": "0.1.396",
3
+ "version": "0.1.397",
4
4
  "description": "volto-arcgis-block: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: CodeSyntax",
@@ -0,0 +1,32 @@
1
+ export const GET_CATALOGAPI_DATES_REQUEST = 'GET_CATALOGAPI_DATES_REQUEST';
2
+ export const GET_CATALOGAPI_DATES_SUCCESS = 'GET_CATALOGAPI_DATES_SUCCESS';
3
+ export const GET_CATALOGAPI_DATES_FAILURE = 'GET_CATALOGAPI_DATES_FAILURE';
4
+
5
+ export function fetchCatalogApiDates(byoc, force_refresh = false) {
6
+ return async (dispatch, getState) => {
7
+ dispatch({ type: GET_CATALOGAPI_DATES_REQUEST, byoc });
8
+ const state = typeof getState === 'function' ? getState() : {};
9
+ const lang =
10
+ (state && state.intl && state.intl.locale) ||
11
+ (state && state.userSession && state.userSession.lang) ||
12
+ 'en';
13
+ const url = `/++api++/${encodeURIComponent(
14
+ lang,
15
+ )}/@get_catalogapi_dates?byoc=${encodeURIComponent(byoc)}&force_refresh=${
16
+ force_refresh ? 'true' : 'false'
17
+ }`;
18
+ try {
19
+ const res = await fetch(url, { headers: { Accept: 'application/json' } });
20
+ const data = await res.json();
21
+ dispatch({ type: GET_CATALOGAPI_DATES_SUCCESS, byoc, payload: data });
22
+ return data;
23
+ } catch (error) {
24
+ dispatch({
25
+ type: GET_CATALOGAPI_DATES_FAILURE,
26
+ byoc,
27
+ error: String(error),
28
+ });
29
+ return null;
30
+ }
31
+ };
32
+ }
@@ -11,3 +11,9 @@
11
11
  * };
12
12
  */
13
13
  export { MAPVIEWER_CONFIG, MapViewerConfig } from './mapviewer/mapviewer';
14
+ export {
15
+ GET_CATALOGAPI_DATES_REQUEST,
16
+ GET_CATALOGAPI_DATES_SUCCESS,
17
+ GET_CATALOGAPI_DATES_FAILURE,
18
+ fetchCatalogApiDates,
19
+ } from './catalogapi';
@@ -709,6 +709,12 @@ class BookmarkWidget extends React.Component {
709
709
  userObj.bookmarks.hotspot = legacyHotspot;
710
710
  userObj.bookmarks.selectedHotspotFilter = selectedHotspotFilter;
711
711
  localStorage.setItem(storageKey, JSON.stringify(userObj));
712
+ try {
713
+ localStorage.setItem(
714
+ storageKey + '_bookmarks_backup',
715
+ JSON.stringify(userObj.bookmarks),
716
+ );
717
+ } catch (e) {}
712
718
  }
713
719
  componentDidUpdate() {
714
720
  if (this.userID !== this.props.userID) {
@@ -794,6 +800,22 @@ class BookmarkWidget extends React.Component {
794
800
  userObj && userObj.bookmarks && typeof userObj.bookmarks === 'object'
795
801
  ? userObj.bookmarks
796
802
  : null;
803
+ if (!bookmarks) {
804
+ let backup = null;
805
+ try {
806
+ backup = JSON.parse(
807
+ localStorage.getItem(storageKey + '_bookmarks_backup'),
808
+ );
809
+ } catch (e) {
810
+ backup = null;
811
+ }
812
+ if (backup && typeof backup === 'object') {
813
+ userObj.bookmarks = backup;
814
+ localStorage.setItem(storageKey, JSON.stringify(userObj));
815
+ bookmarks = backup;
816
+ }
817
+ }
818
+
797
819
  if (!bookmarks) return;
798
820
  const items = Array.isArray(bookmarks.items) ? bookmarks.items : [];
799
821
  const layers = Array.isArray(bookmarks.layers) ? bookmarks.layers : [];
@@ -922,6 +944,12 @@ class BookmarkWidget extends React.Component {
922
944
  userObj.bookmarks.hotspot = hotspot;
923
945
  userObj.bookmarks.selectedHotspotFilter = selectedHotspotFilter;
924
946
  localStorage.setItem(storageKey, JSON.stringify(userObj));
947
+ try {
948
+ localStorage.setItem(
949
+ storageKey + '_bookmarks_backup',
950
+ JSON.stringify(userObj.bookmarks),
951
+ );
952
+ } catch (e) {}
925
953
  }
926
954
  /**
927
955
  * This method renders the component
@@ -32,6 +32,7 @@ import LoadingSpinner from './LoadingSpinner';
32
32
  import UploadWidget from './UploadWidget';
33
33
  import { injectLazyLibs } from '@plone/volto/helpers/Loadable';
34
34
  import { getTaxonomy } from '@eeacms/volto-taxonomy/actions';
35
+ import { fetchCatalogApiDates } from '../../actions';
35
36
 
36
37
  //import "isomorphic-fetch"; <-- Necessary to use fetch?
37
38
  var Map, MapView, Zoom, intl, Basemap, WebTileLayer, Extent;
@@ -1128,6 +1129,8 @@ export const CheckUserID = ({ reference }) => {
1128
1129
  isLoggedIn={isLoggedIn}
1129
1130
  getTaxonomy={reference.getTaxonomy}
1130
1131
  tax={reference.tax}
1132
+ catalogapi={reference.props.catalogapi}
1133
+ fetchCatalogApiDates={reference.props.fetchCatalogApiDates}
1131
1134
  />
1132
1135
  </>
1133
1136
  )}
@@ -1137,6 +1140,8 @@ export const CheckUserID = ({ reference }) => {
1137
1140
 
1138
1141
  const mapDispatchToProps = (dispatch) => ({
1139
1142
  getTaxonomy: (name) => dispatch(getTaxonomy(name)),
1143
+ fetchCatalogApiDates: (byoc, force_refresh) =>
1144
+ dispatch(fetchCatalogApiDates(byoc, force_refresh)),
1140
1145
  });
1141
1146
 
1142
1147
  const MapViewerWithProvider = (props) => {
@@ -1181,6 +1186,7 @@ export default compose(
1181
1186
  connect(
1182
1187
  (state) => ({
1183
1188
  mapviewer_config: state.mapviewer_config.mapviewer_config,
1189
+ catalogapi: state.catalogapi,
1184
1190
  }),
1185
1191
  { MapViewerConfig },
1186
1192
  ),
@@ -2982,20 +2982,49 @@ class MenuWidget extends React.Component {
2982
2982
  if (!userService) this.checkForHotspots(elem, productContainerId);
2983
2983
  // Auto-fit extent once for OGC WMS layers on manual toggle
2984
2984
  try {
2985
- // const isCDSE = !!this.url && this.url.toLowerCase().includes('/ogc/');
2986
2985
  const isCDSE =
2987
2986
  !!this.url &&
2988
2987
  ['/ogc/', '/cdse/'].some((s) => this.url.toLowerCase().includes(s));
2989
2988
  if (isCDSE) {
2990
- const cdseGeometry = await this.getCDSEWFSGeoCoordinates(
2991
- this.url,
2992
- this.layers[elem.id],
2993
- );
2994
- const extent = await this.createExtentFromCoordinates(cdseGeometry);
2995
- this.view.goTo({
2996
- target: extent,
2997
- zoom: 4,
2998
- });
2989
+ const d =
2990
+ this.layers[elem.id]?.DatasetDownloadInformation ||
2991
+ this.layers[elem.id]?.datasetDownloadInformation ||
2992
+ {};
2993
+ const byoc =
2994
+ d && d.items && d.items[0] ? d.items[0].byoc_collection : null;
2995
+ if (byoc && this.props.fetchCatalogApiDates) {
2996
+ let payload =
2997
+ this.props.catalogapi &&
2998
+ this.props.catalogapi.byoc &&
2999
+ this.props.catalogapi.byoc[byoc]
3000
+ ? this.props.catalogapi.byoc[byoc].data
3001
+ : null;
3002
+ if (!payload) {
3003
+ payload = await this.props.fetchCatalogApiDates(byoc, false);
3004
+ }
3005
+ if (payload) {
3006
+ let myExtent = null;
3007
+ if (
3008
+ Array.isArray(payload.extent) &&
3009
+ payload.extent.length === 4
3010
+ ) {
3011
+ myExtent = new Extent({
3012
+ xmin: payload.extent[0],
3013
+ ymin: payload.extent[1],
3014
+ xmax: payload.extent[2],
3015
+ ymax: payload.extent[3],
3016
+ spatialReference: { wkid: 3857 },
3017
+ });
3018
+ } else if (payload.geometry && payload.geometry.coordinates) {
3019
+ myExtent = await this.createExtentFromCoordinates(
3020
+ payload.geometry.coordinates,
3021
+ );
3022
+ }
3023
+ if (myExtent) {
3024
+ this.view.goTo(myExtent);
3025
+ }
3026
+ }
3027
+ }
2999
3028
  }
3000
3029
  } catch (e) {}
3001
3030
  // try {
@@ -3857,6 +3886,25 @@ class MenuWidget extends React.Component {
3857
3886
  return newBBox;
3858
3887
  }
3859
3888
 
3889
+ async datasetFullExtentFromPayload(payload) {
3890
+ if (!payload) return null;
3891
+ if (Array.isArray(payload.extent) && payload.extent.length === 4) {
3892
+ return new Extent({
3893
+ xmin: payload.extent[0],
3894
+ ymin: payload.extent[1],
3895
+ xmax: payload.extent[2],
3896
+ ymax: payload.extent[3],
3897
+ spatialReference: { wkid: 3857 },
3898
+ });
3899
+ }
3900
+ if (payload.geometry && payload.geometry.coordinates) {
3901
+ return await this.createExtentFromCoordinates(
3902
+ payload.geometry.coordinates,
3903
+ );
3904
+ }
3905
+ return null;
3906
+ }
3907
+
3860
3908
  async FullExtentDataset(elem) {
3861
3909
  const serviceLayer = this.state.wmsUserServiceLayers.find(
3862
3910
  (layer) => layer.LayerId === elem.id,
@@ -3871,15 +3919,28 @@ class MenuWidget extends React.Component {
3871
3919
  ['/ogc/', '/cdse/'].some((s) => this.url.toLowerCase().includes(s));
3872
3920
  let BBoxes = {};
3873
3921
  if (isCDSE) {
3874
- const cdseGeometry = await this.getCDSEWFSGeoCoordinates(
3875
- this.url,
3876
- this.layers[elem.id],
3877
- );
3878
- const extent = await this.createExtentFromCoordinates(cdseGeometry);
3879
- this.view.goTo({
3880
- target: extent,
3881
- zoom: 4,
3882
- });
3922
+ const d =
3923
+ this.layers[elem.id]?.DatasetDownloadInformation ||
3924
+ this.layers[elem.id]?.datasetDownloadInformation ||
3925
+ {};
3926
+ const byoc =
3927
+ d && d.items && d.items[0] ? d.items[0].byoc_collection : null;
3928
+ if (byoc && this.props.fetchCatalogApiDates) {
3929
+ let payload =
3930
+ this.props.catalogapi &&
3931
+ this.props.catalogapi.byoc &&
3932
+ this.props.catalogapi.byoc[byoc]
3933
+ ? this.props.catalogapi.byoc[byoc].data
3934
+ : null;
3935
+ if (!payload) {
3936
+ payload = await this.props.fetchCatalogApiDates(byoc, false);
3937
+ }
3938
+ const myExtent = await this.datasetFullExtentFromPayload(payload);
3939
+ if (myExtent) {
3940
+ this.view.goTo(myExtent);
3941
+ return;
3942
+ }
3943
+ }
3883
3944
  return;
3884
3945
  } else if (this.url?.toLowerCase().endsWith('mapserver')) {
3885
3946
  BBoxes = await this.parseBBOXMAPSERVER(this.layers[elem.id]);
@@ -3968,15 +4029,28 @@ class MenuWidget extends React.Component {
3968
4029
  });
3969
4030
  }
3970
4031
  if (isCDSE) {
3971
- const cdseGeometry = await this.getCDSEWFSGeoCoordinates(
3972
- this.url,
3973
- this.layers[elem.id],
3974
- );
3975
- const extent = await this.createExtentFromCoordinates(cdseGeometry);
3976
- this.view.goTo({
3977
- target: extent,
3978
- zoom: 4,
3979
- });
4032
+ const d =
4033
+ this.layers[elem.id]?.DatasetDownloadInformation ||
4034
+ this.layers[elem.id]?.datasetDownloadInformation ||
4035
+ {};
4036
+ const byoc =
4037
+ d && d.items && d.items[0] ? d.items[0].byoc_collection : null;
4038
+ if (byoc && this.props.fetchCatalogApiDates) {
4039
+ let payload =
4040
+ this.props.catalogapi &&
4041
+ this.props.catalogapi.byoc &&
4042
+ this.props.catalogapi.byoc[byoc]
4043
+ ? this.props.catalogapi.byoc[byoc].data
4044
+ : null;
4045
+ if (!payload) {
4046
+ payload = await this.props.fetchCatalogApiDates(byoc, false);
4047
+ }
4048
+ const myExtent = await this.datasetFullExtentFromPayload(payload);
4049
+ if (myExtent) {
4050
+ this.view.goTo(myExtent);
4051
+ return;
4052
+ }
4053
+ }
3980
4054
  return;
3981
4055
  } else if (this.productId?.includes('333e4100b79045daa0ff16466ac83b7f')) {
3982
4056
  //global dynamic landCover
@@ -4381,6 +4455,13 @@ class MenuWidget extends React.Component {
4381
4455
  */
4382
4456
 
4383
4457
  showTimeSlider(elem, fromDownload, hideCalendar) {
4458
+ if (!elem) return;
4459
+ if (!this.timeLayers) this.timeLayers = {};
4460
+ if (!this.visibleLayers) this.visibleLayers = {};
4461
+ if (!this.timeLayers[elem.id]) this.timeLayers[elem.id] = ['far', 'clock'];
4462
+ if (!this.visibleLayers[elem.id]) {
4463
+ this.visibleLayers[elem.id] = ['fas', 'eye'];
4464
+ }
4384
4465
  if (
4385
4466
  sessionStorage.key('timeSliderTag') &&
4386
4467
  sessionStorage.getItem('timeSliderTag') === 'true'
@@ -4393,17 +4474,17 @@ class MenuWidget extends React.Component {
4393
4474
  if (this.timeLayers[elem.id][1] === 'clock') {
4394
4475
  activeLayers.forEach((layer) => {
4395
4476
  let layerId = layer.getAttribute('layer-id');
4396
- let order = this.activeLayersJSON[elem.id].props['layer-order'];
4397
- if (groupLayers.includes(layerId)) {
4477
+ let order = this.activeLayersJSON[elem.id]?.props?.['layer-order'] || 0;
4478
+ if (groupLayers && groupLayers.includes(layerId)) {
4398
4479
  elem = document.getElementById(layerId);
4399
4480
  }
4400
- if (elem.id === layerId) {
4481
+ if (elem && elem.id === layerId) {
4401
4482
  this.timeLayers[elem.id] = ['fas', 'stop'];
4402
4483
  if (
4403
4484
  !this.visibleLayers[elem.id] ||
4404
4485
  this.visibleLayers[elem.id][1] === 'eye-slash'
4405
4486
  ) {
4406
- this.layers[elem.id].visible = true;
4487
+ if (this.layers[elem.id]) this.layers[elem.id].visible = true;
4407
4488
  this.visibleLayers[elem.id] = ['fas', 'eye'];
4408
4489
  }
4409
4490
  document
@@ -4415,9 +4496,13 @@ class MenuWidget extends React.Component {
4415
4496
  .forEach((item) => {
4416
4497
  item.classList.add('locked');
4417
4498
  });
4418
- document.querySelector('#products_label').classList.add('locked');
4419
- document.querySelector('#map_remove_layers').classList.add('locked');
4420
- if (this.props.download)
4499
+ if (document.querySelector('#products_label'))
4500
+ document.querySelector('#products_label').classList.add('locked');
4501
+ if (document.querySelector('#map_remove_layers')) {
4502
+ const mapRemoveBtn = document.querySelector('#map_remove_layers');
4503
+ if (mapRemoveBtn) mapRemoveBtn.classList.add('locked');
4504
+ }
4505
+ if (this.props.download && document.querySelector('#download_label'))
4421
4506
  document.querySelector('#download_label').classList.add('locked');
4422
4507
  this.activeLayersJSON[elem.id] = this.addActiveLayer(
4423
4508
  elem,
@@ -4426,17 +4511,24 @@ class MenuWidget extends React.Component {
4426
4511
  hideCalendar,
4427
4512
  );
4428
4513
  } else {
4514
+ const node = document.getElementById(layerId);
4429
4515
  if (
4430
- document.getElementById(layerId).parentElement.dataset
4431
- .timeseries === 'true'
4516
+ node &&
4517
+ node.parentElement &&
4518
+ node.parentElement.dataset &&
4519
+ node.parentElement.dataset.timeseries === 'true'
4432
4520
  ) {
4521
+ if (!this.visibleLayers[layerId]) {
4522
+ this.visibleLayers[layerId] = ['fas', 'eye'];
4523
+ }
4433
4524
  if (this.visibleLayers[layerId][1] === 'eye') {
4434
- this.layers[layerId].visible = false;
4525
+ if (this.layers[layerId]) this.layers[layerId].visible = false;
4435
4526
  this.visibleLayers[layerId] = ['fas', 'eye-slash'];
4436
4527
  }
4437
- document
4438
- .querySelector('.active-layer[layer-id="' + layerId + '"]')
4439
- .classList.add('locked');
4528
+ const activeNode = document.querySelector(
4529
+ '.active-layer[layer-id="' + layerId + '"]',
4530
+ );
4531
+ if (activeNode) activeNode.classList.add('locked');
4440
4532
  }
4441
4533
  this.activeLayersJSON[layerId] = this.addActiveLayer(
4442
4534
  document.getElementById(layerId),
@@ -4445,17 +4537,18 @@ class MenuWidget extends React.Component {
4445
4537
  );
4446
4538
  }
4447
4539
  });
4448
- if (document.querySelector('.opacity-panel').style.display === 'block') {
4540
+ const op = document.querySelector('.opacity-panel');
4541
+ if (op && op.style.display === 'block') {
4449
4542
  this.closeOpacity();
4450
4543
  }
4451
4544
  } else {
4452
4545
  activeLayers.forEach((layer) => {
4453
4546
  let layerId = layer.getAttribute('layer-id');
4454
- let order = this.activeLayersJSON[elem.id].props['layer-order'];
4455
- if (groupLayers.includes(layerId)) {
4547
+ let order = this.activeLayersJSON[elem.id]?.props?.['layer-order'] || 0;
4548
+ if (groupLayers && groupLayers.includes(layerId)) {
4456
4549
  elem = document.getElementById(layerId);
4457
4550
  }
4458
- if (elem.id === layerId) {
4551
+ if (elem && elem.id === layerId) {
4459
4552
  this.timeLayers[elem.id] = ['far', 'clock'];
4460
4553
  this.activeLayersJSON[elem.id] = this.addActiveLayer(
4461
4554
  elem,
@@ -4471,46 +4564,46 @@ class MenuWidget extends React.Component {
4471
4564
  .forEach((item) => {
4472
4565
  item.classList.remove('locked');
4473
4566
  });
4474
- document.querySelector('#products_label').classList.remove('locked');
4475
- document
4476
- .querySelector('#map_remove_layers')
4477
- .classList.remove('locked');
4567
+ const productsLabel = document.querySelector('#products_label');
4568
+ if (productsLabel) productsLabel.classList.remove('locked');
4569
+ const removeBtn = document.querySelector('#map_remove_layers');
4570
+ if (removeBtn) removeBtn.classList.remove('locked');
4478
4571
  if (this.props.download) {
4479
- document
4480
- .querySelector('#download_label')
4481
- .classList.remove('locked');
4482
- if (
4483
- document.querySelector(
4484
- '.active-layer[layer-id="' +
4485
- elem.id +
4486
- '"] .map-menu-icon.active-layer-time',
4487
- ).dataset.download === 'true'
4488
- ) {
4489
- document.getElementById('download_label').click();
4572
+ const dl = document.querySelector('#download_label');
4573
+ if (dl) dl.classList.remove('locked');
4574
+ const timeIcon = document.querySelector(
4575
+ '.active-layer[layer-id="' +
4576
+ elem.id +
4577
+ '"] .map-menu-icon.active-layer-time',
4578
+ );
4579
+ if (timeIcon && timeIcon.dataset.download === 'true') {
4580
+ const dlBtn = document.getElementById('download_label');
4581
+ if (dlBtn) dlBtn.click();
4490
4582
  }
4491
4583
  } else {
4492
- if (
4493
- document.querySelector(
4494
- '.active-layer[layer-id="' +
4495
- elem.id +
4496
- '"] .map-menu-icon.active-layer-time',
4497
- ).dataset.download === 'true'
4498
- ) {
4499
- document.getElementById('products_label').click();
4584
+ const timeIcon = document.querySelector(
4585
+ '.active-layer[layer-id="' +
4586
+ elem.id +
4587
+ '"] .map-menu-icon.active-layer-time',
4588
+ );
4589
+ if (timeIcon && timeIcon.dataset.download === 'true') {
4590
+ const prBtn = document.getElementById('products_label');
4591
+ if (prBtn) prBtn.click();
4500
4592
  }
4501
4593
  }
4502
- if (
4503
- document.contains(document.querySelector('.timeslider-container'))
4504
- )
4594
+ const ts = document.querySelector('.timeslider-container');
4595
+ if (ts && document.contains(ts))
4505
4596
  ReactDOM.unmountComponentAtNode(
4506
4597
  document.querySelector('.esri-ui-bottom-right'),
4507
4598
  );
4508
- if (document.querySelector('.drawRectanglePopup-block'))
4509
- document.querySelector('.drawRectanglePopup-block').style.display =
4510
- 'block';
4599
+ const warn = document.querySelector('.drawRectanglePopup-block');
4600
+ if (warn) warn.style.display = 'block';
4511
4601
  } else {
4602
+ if (!this.visibleLayers[layerId]) {
4603
+ this.visibleLayers[layerId] = ['fas', 'eye'];
4604
+ }
4512
4605
  if (this.visibleLayers[layerId][1] === 'eye-slash') {
4513
- this.layers[layerId].visible = true;
4606
+ if (this.layers[layerId]) this.layers[layerId].visible = true;
4514
4607
  this.visibleLayers[layerId] = ['fas', 'eye'];
4515
4608
  this.activeLayersJSON[layerId] = this.addActiveLayer(
4516
4609
  document.getElementById(layerId),
@@ -4518,9 +4611,10 @@ class MenuWidget extends React.Component {
4518
4611
  fromDownload,
4519
4612
  );
4520
4613
  }
4521
- document
4522
- .querySelector('.active-layer[layer-id="' + layerId + '"]')
4523
- .classList.remove('locked');
4614
+ const activeNode = document.querySelector(
4615
+ '.active-layer[layer-id="' + layerId + '"]',
4616
+ );
4617
+ if (activeNode) activeNode.classList.remove('locked');
4524
4618
  }
4525
4619
  });
4526
4620
  }
@@ -5452,6 +5546,14 @@ class MenuWidget extends React.Component {
5452
5546
  time.end = parseInt(activeLayer.getAttribute('time-end'));
5453
5547
  }
5454
5548
  let isLoggedIn = document.querySelector('.map-menu-icon-login.logged');
5549
+ let byoc = null;
5550
+ try {
5551
+ const d =
5552
+ layer?.DatasetDownloadInformation ||
5553
+ layer?.datasetDownloadInformation ||
5554
+ {};
5555
+ byoc = d && d.items && d.items[0] ? d.items[0].byoc_collection : null;
5556
+ } catch (e) {}
5455
5557
  ReactDOM.render(
5456
5558
  <TimesliderWidget
5457
5559
  view={this.props.view}
@@ -5464,6 +5566,8 @@ class MenuWidget extends React.Component {
5464
5566
  fromDownload={fromDownload}
5465
5567
  area={this.props.area}
5466
5568
  hideCalendar={hideCalendar}
5569
+ catalogapi={this.props.catalogapi}
5570
+ catalogApiByoc={byoc}
5467
5571
  />,
5468
5572
  document.querySelector('.esri-ui-bottom-right'),
5469
5573
  );
@@ -5478,20 +5582,46 @@ class MenuWidget extends React.Component {
5478
5582
  }
5479
5583
  }
5480
5584
  }
5481
- checkTimeLayer(dataset, checkedLayers) {
5585
+ async checkTimeLayer(dataset, checkedLayers) {
5482
5586
  let id = dataset.DatasetId;
5483
- let checkbox = document
5484
- .querySelector('[datasetid="' + id + '"]')
5485
- .querySelector('.map-dataset-checkbox input');
5587
+ let container = document.querySelector('[datasetid="' + id + '"]');
5588
+ if (!container) return;
5589
+ let checkbox = container.querySelector('.map-dataset-checkbox input');
5590
+ if (!checkbox) return;
5486
5591
  if (!checkbox.checked) {
5487
5592
  checkbox.click();
5488
5593
  }
5594
+ try {
5595
+ const info =
5596
+ dataset?.dataset_download_information ||
5597
+ dataset?.DatasetDownloadInformation ||
5598
+ {};
5599
+ const byoc =
5600
+ info && info.items && info.items[0]
5601
+ ? info.items[0].byoc_collection
5602
+ : null;
5603
+ if (byoc && this.props.fetchCatalogApiDates) {
5604
+ await this.props.fetchCatalogApiDates(byoc, false);
5605
+ }
5606
+ } catch (e) {}
5489
5607
  document.getElementById('active_label').click();
5490
5608
  if (!document.querySelector('.timeslider-container')) {
5491
- let layerId = this.findCheckedLayer(dataset, checkedLayers);
5492
5609
  setTimeout(() => {
5493
- // Display timeslider with no calendar.
5494
- this.showTimeSlider(document.getElementById(layerId), true, true);
5610
+ let layerInputs = container.querySelectorAll(
5611
+ '.map-menu-layers-container input[type="checkbox"]',
5612
+ );
5613
+ let target = null;
5614
+ layerInputs.forEach((inp) => {
5615
+ if (!target && inp.checked) target = inp;
5616
+ });
5617
+ if (!target && layerInputs[0]) {
5618
+ layerInputs[0].checked = true;
5619
+ this.toggleLayer(layerInputs[0]);
5620
+ target = layerInputs[0];
5621
+ }
5622
+ if (target) {
5623
+ this.showTimeSlider(target, true, true);
5624
+ }
5495
5625
  }, 100);
5496
5626
  }
5497
5627
  }
@@ -54,6 +54,7 @@ class TimesliderWidget extends React.Component {
54
54
  document.querySelector('.drawRectanglePopup-block').style.display =
55
55
  'none';
56
56
  }
57
+ this._cdseApplied = false;
57
58
  }
58
59
 
59
60
  loader() {
@@ -268,6 +269,73 @@ class TimesliderWidget extends React.Component {
268
269
  };
269
270
  } // parserPeriod
270
271
 
272
+ applyCDSETemporalData(payload) {
273
+ try {
274
+ const arr = Array.isArray(payload?.dates) ? payload.dates : [];
275
+ if (!arr.length) {
276
+ this.TimesliderWidget.disabled = true;
277
+ return;
278
+ }
279
+ this.TimesliderWidget.fullTimeExtent = new TimeExtent({
280
+ start: new Date(arr[arr.length - 1]),
281
+ end: new Date(arr[0]),
282
+ });
283
+ this.TimesliderWidget.stops = {
284
+ dates: arr.map((e) => new Date(e)),
285
+ };
286
+ const time = arr.map((d) => new Date(d));
287
+ for (let i in time) {
288
+ timeDict[time[i]] = arr[i];
289
+ }
290
+ let periodicity = null;
291
+ if (arr.length > 1) {
292
+ periodicity = Math.floor(
293
+ (Date.parse(arr[1]) - Date.parse(arr[0])) / 86400000,
294
+ );
295
+ if (periodicity === 0) {
296
+ periodicity =
297
+ (new Date(arr[1]).getHours() - new Date(arr[0]).getHours()) / 24;
298
+ }
299
+ }
300
+ this.setState({ periodicity: periodicity });
301
+ if (this.TimesliderWidget.effectiveStops.length === 11) {
302
+ let period =
303
+ (this.TimesliderWidget.fullTimeExtent.end -
304
+ this.TimesliderWidget.fullTimeExtent.start) /
305
+ 590000000;
306
+ if (
307
+ this.TimesliderWidget.stops &&
308
+ this.TimesliderWidget.stops.interval &&
309
+ period > this.TimesliderWidget.stops.interval.value
310
+ ) {
311
+ this.TimesliderWidget.stops = {
312
+ interval: {
313
+ value: period,
314
+ unit: 'minutes',
315
+ },
316
+ };
317
+ }
318
+ }
319
+ this.TimesliderWidget.watch('timeExtent', (timeExtent) => {
320
+ if (!this.container.current ? true : false) {
321
+ this.TimesliderWidget.stop();
322
+ }
323
+ if (this.layer.type === 'wmts') {
324
+ this.layer.customLayerParameters = {
325
+ SHOWLOGO: false,
326
+ };
327
+ this.layer.customLayerParameters['TIME'] =
328
+ timeDict[this.TimesliderWidget.timeExtent.end];
329
+ } else {
330
+ this.layer.customLayerParameters = {};
331
+ this.layer.customLayerParameters['TIME'] =
332
+ timeDict[this.TimesliderWidget.timeExtent.end];
333
+ }
334
+ this.layer.refresh();
335
+ });
336
+ } catch (e) {}
337
+ }
338
+
271
339
  /**
272
340
  * This method is executed after the rener method is executed
273
341
  */
@@ -403,97 +471,18 @@ class TimesliderWidget extends React.Component {
403
471
  let times = {};
404
472
  let periodicity;
405
473
  if (isCDSE) {
406
- times = await this.getCDSEWFSTemporalData(
407
- this.layer.url,
408
- this.layer,
409
- );
410
- if (times) {
411
- // Dates array
412
- this.TimesliderWidget.fullTimeExtent = new TimeExtent({
413
- start: new Date(
414
- times[this.layerName].array[
415
- times[this.layerName].array.length - 1
416
- ],
417
- ),
418
- end: new Date(times[this.layerName].array[0]),
419
- });
420
- this.TimesliderWidget.stops = {
421
- dates: times[this.layerName].array.map((e) => new Date(e)),
422
- };
423
-
424
- if (this.layer.type === 'wmts') {
425
- this.layer.customLayerParameters = {
426
- SHOWLOGO: false,
427
- };
428
- const time = times[this.layerName].array.map(
429
- (d) => new Date(d),
430
- );
431
-
432
- for (let i in time) {
433
- timeDict[time[i]] = times[this.layerName].array[i];
434
- }
435
- }
436
-
437
- periodicity = Math.floor(
438
- (Date.parse(times[this.layerName].array[1]) -
439
- Date.parse(times[this.layerName].array[0])) /
440
- 86400000,
441
- );
442
- if (periodicity === 0) {
443
- periodicity =
444
- (new Date(times[this.layerName].array[1]).getHours() -
445
- new Date(times[this.layerName].array[0]).getHours()) /
446
- 24;
447
- }
448
-
449
- this.setState({ periodicity: periodicity });
450
- if (this.TimesliderWidget.effectiveStops.length === 11) {
451
- let period =
452
- (this.TimesliderWidget.fullTimeExtent.end -
453
- this.TimesliderWidget.fullTimeExtent.start) /
454
- 590000000;
455
- if (period > this.TimesliderWidget.stops.interval.value) {
456
- this.TimesliderWidget.stops = {
457
- interval: {
458
- value: period,
459
- unit: 'minutes',
460
- },
461
- };
462
- }
463
- }
464
- this.TimesliderWidget.watch('timeExtent', (timeExtent) => {
465
- if (!this.container.current ? true : false) {
466
- this.TimesliderWidget.stop();
467
- }
468
- if (this.layer.type === 'wmts') {
469
- this.layer.customLayerParameters = {
470
- SHOWLOGO: false,
471
- };
472
- this.layer.customLayerParameters['TIME'] =
473
- timeDict[this.TimesliderWidget.timeExtent.end];
474
- } else {
475
- this.layer.customLayerParameters = {};
476
- if (times[this.layerName].hasOwnProperty('array')) {
477
- this.layer.customLayerParameters['TIME'] =
478
- timeDict[this.TimesliderWidget.timeExtent.end];
479
- } else {
480
- const newDateTimeObject = new Date(
481
- this.TimesliderWidget.timeExtent.start.toISOString(),
482
- );
483
- newDateTimeObject.setMinutes(
484
- this.TimesliderWidget.timeExtent.start.getMinutes() +
485
- this.TimesliderWidget.stops['interval'].value,
486
- );
487
- this.layer.customLayerParameters['TIME'] =
488
- this.TimesliderWidget.timeExtent.start.toISOString() +
489
- '/' +
490
- newDateTimeObject.toISOString(); //OK
491
- }
492
- }
493
- this.layer.refresh();
494
- });
495
- } // if there is dimension time
496
- else {
474
+ const byoc = this.props.catalogApiByoc;
475
+ const payload =
476
+ this.props.catalogapi &&
477
+ this.props.catalogapi.byoc &&
478
+ byoc &&
479
+ this.props.catalogapi.byoc[byoc]
480
+ ? this.props.catalogapi.byoc[byoc].data
481
+ : null;
482
+ if (payload) {
483
+ this.applyCDSETemporalData(payload);
484
+ this._cdseApplied = true;
485
+ } else {
497
486
  this.TimesliderWidget.disabled = true;
498
487
  }
499
488
  } else {
@@ -639,6 +628,37 @@ class TimesliderWidget extends React.Component {
639
628
  });
640
629
  } //componentDidMount
641
630
 
631
+ componentDidUpdate(prevProps) {
632
+ if (!this.TimesliderWidget) return;
633
+ const url = this.layer?.url || '';
634
+ const urlNorm =
635
+ typeof url === 'string' ? url.replace(/%2F/gi, '/').toLowerCase() : '';
636
+ const isCDSE = urlNorm.includes('/ogc/') || urlNorm.includes('/cdse/');
637
+ if (!isCDSE) return;
638
+ const byoc = this.props.catalogApiByoc;
639
+ const prevData =
640
+ prevProps &&
641
+ prevProps.catalogapi &&
642
+ prevProps.catalogapi.byoc &&
643
+ byoc &&
644
+ prevProps.catalogapi.byoc[byoc]
645
+ ? prevProps.catalogapi.byoc[byoc].data
646
+ : null;
647
+ const currData =
648
+ this.props &&
649
+ this.props.catalogapi &&
650
+ this.props.catalogapi.byoc &&
651
+ byoc &&
652
+ this.props.catalogapi.byoc[byoc]
653
+ ? this.props.catalogapi.byoc[byoc].data
654
+ : null;
655
+ if (!this._cdseApplied && currData && currData !== prevData) {
656
+ this.TimesliderWidget.disabled = false;
657
+ this.applyCDSETemporalData(currData);
658
+ this._cdseApplied = true;
659
+ }
660
+ }
661
+
642
662
  getPeriodicity() {
643
663
  let period = this.state.periodicity;
644
664
  if (period === 1 / 24 || period === 'PT1H') {
@@ -848,7 +868,7 @@ class TimesliderWidget extends React.Component {
848
868
  onClick={() => this.openCalendar()}
849
869
  onKeyDown={() => this.openCalendar()}
850
870
  >
851
- <Icon name={calendarSVG} size={25} />
871
+ <Icon name={calendarSVG} size="25px" />
852
872
  </button>
853
873
  </div>
854
874
  <div className="timeslider-panel"></div>
@@ -0,0 +1,40 @@
1
+ import {
2
+ GET_CATALOGAPI_DATES_REQUEST,
3
+ GET_CATALOGAPI_DATES_SUCCESS,
4
+ GET_CATALOGAPI_DATES_FAILURE,
5
+ } from '../../actions/catalogapi';
6
+
7
+ const initialState = {
8
+ byoc: {},
9
+ };
10
+
11
+ export function catalogapiReducer(state = initialState, action = {}) {
12
+ switch (action.type) {
13
+ case GET_CATALOGAPI_DATES_REQUEST:
14
+ return {
15
+ ...state,
16
+ byoc: {
17
+ ...state.byoc,
18
+ [action.byoc]: { loading: true, error: null, data: null },
19
+ },
20
+ };
21
+ case GET_CATALOGAPI_DATES_SUCCESS:
22
+ return {
23
+ ...state,
24
+ byoc: {
25
+ ...state.byoc,
26
+ [action.byoc]: { loading: false, error: null, data: action.payload },
27
+ },
28
+ };
29
+ case GET_CATALOGAPI_DATES_FAILURE:
30
+ return {
31
+ ...state,
32
+ byoc: {
33
+ ...state.byoc,
34
+ [action.byoc]: { loading: false, error: action.error, data: null },
35
+ },
36
+ };
37
+ default:
38
+ return state;
39
+ }
40
+ }
@@ -5,6 +5,7 @@
5
5
 
6
6
  // import defaultReducers from '@plone/volto/reducers';
7
7
  import { mapViewerConfigReducer } from './mapviewer/mapviewer_reducer';
8
+ import { catalogapiReducer } from './catalogapi/catalogapi_reducer';
8
9
  /**
9
10
  * Root reducer.
10
11
  * @function
@@ -16,6 +17,7 @@ const reducers = {
16
17
  // ...defaultReducers,
17
18
  // Add your reducers here
18
19
  mapviewer_config: mapViewerConfigReducer,
20
+ catalogapi: catalogapiReducer,
19
21
  };
20
22
 
21
23
  export default reducers;