@eeacms/volto-arcgis-block 0.1.386 → 0.1.388

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,6 +4,13 @@ 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.388](https://github.com/eea/volto-arcgis-block/compare/0.1.387...0.1.388) - 17 September 2025
8
+
9
+ #### :hammer_and_wrench: Others
10
+
11
+ - (bug): added time slider widget funciotnality for CDSE time series datasets [Unai Bolivar - [`759b719`](https://github.com/eea/volto-arcgis-block/commit/759b7193cbd046985197a6c9514d41b926f127d3)]
12
+ ### [0.1.387](https://github.com/eea/volto-arcgis-block/compare/0.1.386...0.1.387) - 12 September 2025
13
+
7
14
  ### [0.1.386](https://github.com/eea/volto-arcgis-block/compare/0.1.385...0.1.386) - 12 September 2025
8
15
 
9
16
  #### :hammer_and_wrench: Others
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-arcgis-block",
3
- "version": "0.1.386",
3
+ "version": "0.1.388",
4
4
  "description": "volto-arcgis-block: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: CodeSyntax",
@@ -3924,7 +3924,6 @@ class MenuWidget extends React.Component {
3924
3924
 
3925
3925
  async fullExtent(elem) {
3926
3926
  this.url = this.layers[elem.id]?.url;
3927
- // const isCDSE = !!this.url && this.url.toLowerCase().includes('/ogc/');
3928
3927
  const isCDSE =
3929
3928
  !!this.url &&
3930
3929
  ['/ogc/', '/cdse/'].some((s) => this.url.toLowerCase().includes(s));
@@ -4777,6 +4776,10 @@ class MenuWidget extends React.Component {
4777
4776
  const isUserServiceLayer = this.state.wmsUserServiceLayers.some(
4778
4777
  (layer) => layer.LayerId === elem.id,
4779
4778
  );
4779
+ this.url = this.layers[elem.id]?.url;
4780
+ const isCDSE =
4781
+ !!this.url &&
4782
+ ['/ogc/', '/cdse/'].some((s) => this.url.toLowerCase().includes(s));
4780
4783
 
4781
4784
  // Only call findCheckedDataset for non-service layers (this method looks for parent datasets)
4782
4785
  if (!isUserServiceLayer) {
@@ -4828,6 +4831,7 @@ class MenuWidget extends React.Component {
4828
4831
  }
4829
4832
 
4830
4833
  if (
4834
+ !isCDSE &&
4831
4835
  !isUserServiceLayer &&
4832
4836
  this.productId &&
4833
4837
  this.productId.includes('333e4100b79045daa0ff16466ac83b7f')
@@ -84,6 +84,46 @@ class TimesliderWidget extends React.Component {
84
84
  });
85
85
  }
86
86
 
87
+ async getCDSEWFSTemporalData(url, layer) {
88
+ if (!url) return {};
89
+ const match = /\/ogc\/(?:wmts|wms)\/([^/?]+)/i.exec(url);
90
+ const datasetDownloadInformation =
91
+ layer?.DatasetDownloadInformation ||
92
+ layer?.DatasetDownloadInformation ||
93
+ {};
94
+ if (!datasetDownloadInformation) return {};
95
+ const byocCollectionId =
96
+ datasetDownloadInformation?.items[0].byoc_collection || null;
97
+ if (!byocCollectionId) return {};
98
+ if (!match) return {};
99
+ const fetchUrl = `https://sh.dataspace.copernicus.eu/ogc/wfs/${match[1]}?SERVICE=WFS&REQUEST=GetFeature&VERSION=2.0.0&TYPENAMES=byoc-${byocCollectionId}&COUNT=100&BBOX=-21039383,-22375217,21039383,22375217&OUTPUTFORMAT=application/json`;
100
+ try {
101
+ const res = await fetch(fetchUrl);
102
+ const data = await res.json();
103
+ let times = {};
104
+ let layerName = '';
105
+ if (layer?.type === 'feature') {
106
+ layerName = layer?.id;
107
+ } else if (layer?.type === 'wms') {
108
+ layerName = layer?.sublayers?.items?.[0]?.name;
109
+ } else if (layer?.type === 'wmts') {
110
+ layerName = layer?.activeLayer?.id;
111
+ } else {
112
+ layerName = layer?.name || layer?.title || layer?.id || 'layer';
113
+ }
114
+ const features = Array.isArray(data?.features) ? data.features : [];
115
+ const dates = features
116
+ .map((f) => f?.properties?.date || null)
117
+ .filter((v) => v);
118
+ if (dates.length > 0) {
119
+ times[layerName] = {
120
+ array: dates,
121
+ };
122
+ }
123
+ return times;
124
+ } catch (e) {}
125
+ }
126
+
87
127
  parseTimeWMS(xml) {
88
128
  let layers = Array.from(xml.querySelectorAll('Layer')).filter(
89
129
  (v) => v.querySelectorAll('Layer').length === 0,
@@ -287,7 +327,14 @@ class TimesliderWidget extends React.Component {
287
327
 
288
328
  this.props.view
289
329
  .whenLayerView(this.layer, this.TimesliderWidget)
290
- .then((lv) => {
330
+ .then(async (lv) => {
331
+ this.url = lv?.layer?.viewService ?? this.layer?.url ?? null;
332
+ const urlNorm =
333
+ typeof this.url === 'string'
334
+ ? this.url.replace(/%2F/gi, '/').toLowerCase()
335
+ : '';
336
+ const isCDSE =
337
+ urlNorm.includes('/ogc/') || urlNorm.includes('/cdse/');
291
338
  if (this.layer.type === 'feature') {
292
339
  this.TimesliderWidget.fullTimeExtent = this.layer.timeInfo.fullTimeExtent;
293
340
  this.TimesliderWidget.stops = {
@@ -315,79 +362,48 @@ class TimesliderWidget extends React.Component {
315
362
  } else if (this.layer.type === 'wmts') {
316
363
  serviceType = 'wmts';
317
364
  }
365
+ let times = {};
366
+ let periodicity;
367
+ if (isCDSE) {
368
+ times = await this.getCDSEWFSTemporalData(
369
+ this.layer.url,
370
+ this.layer,
371
+ );
372
+ if (times) {
373
+ // Dates array
374
+ this.TimesliderWidget.fullTimeExtent = new TimeExtent({
375
+ start: new Date(
376
+ times[this.layerName].array[
377
+ times[this.layerName].array.length - 1
378
+ ],
379
+ ),
380
+ end: new Date(times[this.layerName].array[0]),
381
+ });
382
+ this.TimesliderWidget.stops = {
383
+ dates: times[this.layerName].array.map((e) => new Date(e)),
384
+ };
318
385
 
319
- this.getCapabilities(this.layer.url, serviceType).then((xml) => {
320
- let times = {};
321
- let periodicity;
322
- if (this.layer.type === 'wms') {
323
- times = this.parseTimeWMS(xml);
324
- } else if (this.layer.type === 'wmts') {
325
- times = this.parseTimeWMTS(xml);
326
- }
327
- // Capabilities have time enabled
328
- if (times[this.layerName].hasOwnProperty('dimension') === false) {
329
- // Start-End-Period
330
- if (times[this.layerName].hasOwnProperty('period')) {
331
- this.TimesliderWidget.fullTimeExtent = new TimeExtent({
332
- start: new Date(times[this.layerName].start),
333
- end: new Date(times[this.layerName].end),
334
- });
335
-
336
- const period = this.parserPeriod(
337
- times[this.layerName].period,
386
+ if (this.layer.type === 'wmts') {
387
+ this.layer.customLayerParameters = {};
388
+ const time = times[this.layerName].array.map(
389
+ (d) => new Date(d),
338
390
  );
339
391
 
340
- this.TimesliderWidget.stops = {
341
- interval: {
342
- value:
343
- period.years * 365 * 24 * 60 +
344
- period.months * 31 * 24 * 60 +
345
- period.weeks * 7 * 24 * 60 +
346
- period.days * 24 * 60 +
347
- period.hours * 60 +
348
- period.minutes +
349
- period.seconds / 60,
350
- unit: 'minutes',
351
- },
352
- };
353
-
354
- periodicity = times[this.layerName].period;
355
- } else if (times[this.layerName].hasOwnProperty('array')) {
356
- // Dates array
357
- this.TimesliderWidget.fullTimeExtent = new TimeExtent({
358
- start: new Date(times[this.layerName].array[0]),
359
- end: new Date(
360
- times[this.layerName].array[
361
- times[this.layerName].array.length - 1
362
- ],
363
- ),
364
- });
365
- this.TimesliderWidget.stops = {
366
- dates: times[this.layerName].array.map((e) => new Date(e)),
367
- };
368
-
369
- if (this.layer.type === 'wmts') {
370
- this.layer.customLayerParameters = {};
371
- const time = times[this.layerName].array.map(
372
- (d) => new Date(d),
373
- );
374
-
375
- for (let i in time) {
376
- timeDict[time[i]] = times[this.layerName].array[i];
377
- }
392
+ for (let i in time) {
393
+ timeDict[time[i]] = times[this.layerName].array[i];
378
394
  }
395
+ }
379
396
 
380
- periodicity = Math.floor(
381
- (Date.parse(times[this.layerName].array[1]) -
382
- Date.parse(times[this.layerName].array[0])) /
383
- 86400000,
384
- );
385
- if (periodicity === 0) {
386
- periodicity =
387
- (new Date(times[this.layerName].array[1]).getHours() -
388
- new Date(times[this.layerName].array[0]).getHours()) /
389
- 24;
390
- }
397
+ periodicity = Math.floor(
398
+ (Date.parse(times[this.layerName].array[1]) -
399
+ Date.parse(times[this.layerName].array[0])) /
400
+ 86400000,
401
+ );
402
+ if (periodicity === 0) {
403
+ periodicity =
404
+ (new Date(times[this.layerName].array[1]).getHours() -
405
+ new Date(times[this.layerName].array[0]).getHours()) /
406
+ 24;
391
407
  }
392
408
 
393
409
  this.setState({ periodicity: periodicity });
@@ -409,16 +425,6 @@ class TimesliderWidget extends React.Component {
409
425
  if (!this.container.current ? true : false) {
410
426
  this.TimesliderWidget.stop();
411
427
  }
412
- /*let start = new Date(timeExtent.start).getTime();
413
- let end = new Date(timeExtent.end).getTime();
414
- this.props.time.elem.setAttribute('time-start', start);
415
- this.props.time.elem.setAttribute('time-end', end);
416
- if (this.props.download) {
417
- this.props.time.dataset.setAttribute('time-start', start);
418
- this.props.time.dataset.setAttribute('time-end', end);
419
- }
420
- this.props.time.dataset.setAttribute('time-start', start);
421
- this.props.time.dataset.setAttribute('time-end', end);*/
422
428
  if (this.layer.type === 'wmts') {
423
429
  this.layer.customLayerParameters = {};
424
430
  this.layer.customLayerParameters['TIME'] =
@@ -448,7 +454,144 @@ class TimesliderWidget extends React.Component {
448
454
  else {
449
455
  this.TimesliderWidget.disabled = true;
450
456
  }
451
- });
457
+ } else {
458
+ //place getCapabilties in here
459
+ this.getCapabilities(this.layer.url, serviceType).then((xml) => {
460
+ if (this.layer.type === 'wms') {
461
+ times = this.parseTimeWMS(xml);
462
+ } else if (this.layer.type === 'wmts') {
463
+ times = this.parseTimeWMTS(xml);
464
+ }
465
+ // Capabilities have time enabled
466
+ if (
467
+ times[this.layerName].hasOwnProperty('dimension') === false
468
+ ) {
469
+ // Start-End-Period
470
+ if (times[this.layerName].hasOwnProperty('period')) {
471
+ this.TimesliderWidget.fullTimeExtent = new TimeExtent({
472
+ start: new Date(times[this.layerName].start),
473
+ end: new Date(times[this.layerName].end),
474
+ });
475
+
476
+ const period = this.parserPeriod(
477
+ times[this.layerName].period,
478
+ );
479
+
480
+ this.TimesliderWidget.stops = {
481
+ interval: {
482
+ value:
483
+ period.years * 365 * 24 * 60 +
484
+ period.months * 31 * 24 * 60 +
485
+ period.weeks * 7 * 24 * 60 +
486
+ period.days * 24 * 60 +
487
+ period.hours * 60 +
488
+ period.minutes +
489
+ period.seconds / 60,
490
+ unit: 'minutes',
491
+ },
492
+ };
493
+
494
+ periodicity = times[this.layerName].period;
495
+ } else if (times[this.layerName].hasOwnProperty('array')) {
496
+ // Dates array
497
+ this.TimesliderWidget.fullTimeExtent = new TimeExtent({
498
+ start: new Date(times[this.layerName].array[0]),
499
+ end: new Date(
500
+ times[this.layerName].array[
501
+ times[this.layerName].array.length - 1
502
+ ],
503
+ ),
504
+ });
505
+ this.TimesliderWidget.stops = {
506
+ dates: times[this.layerName].array.map(
507
+ (e) => new Date(e),
508
+ ),
509
+ };
510
+
511
+ if (this.layer.type === 'wmts') {
512
+ this.layer.customLayerParameters = {};
513
+ const time = times[this.layerName].array.map(
514
+ (d) => new Date(d),
515
+ );
516
+
517
+ for (let i in time) {
518
+ timeDict[time[i]] = times[this.layerName].array[i];
519
+ }
520
+ }
521
+
522
+ periodicity = Math.floor(
523
+ (Date.parse(times[this.layerName].array[1]) -
524
+ Date.parse(times[this.layerName].array[0])) /
525
+ 86400000,
526
+ );
527
+ if (periodicity === 0) {
528
+ periodicity =
529
+ (new Date(times[this.layerName].array[1]).getHours() -
530
+ new Date(times[this.layerName].array[0]).getHours()) /
531
+ 24;
532
+ }
533
+ }
534
+
535
+ this.setState({ periodicity: periodicity });
536
+ if (this.TimesliderWidget.effectiveStops.length === 11) {
537
+ let period =
538
+ (this.TimesliderWidget.fullTimeExtent.end -
539
+ this.TimesliderWidget.fullTimeExtent.start) /
540
+ 590000000;
541
+ if (period > this.TimesliderWidget.stops.interval.value) {
542
+ this.TimesliderWidget.stops = {
543
+ interval: {
544
+ value: period,
545
+ unit: 'minutes',
546
+ },
547
+ };
548
+ }
549
+ }
550
+ this.TimesliderWidget.watch('timeExtent', (timeExtent) => {
551
+ if (!this.container.current ? true : false) {
552
+ this.TimesliderWidget.stop();
553
+ }
554
+ // let start = new Date(timeExtent.start).getTime();
555
+ // let end = new Date(timeExtent.end).getTime();
556
+ // this.props.time.elem.setAttribute('time-start', start);
557
+ // this.props.time.elem.setAttribute('time-end', end);
558
+ // if (this.props.download) {
559
+ // this.props.time.dataset.setAttribute('time-start', start);
560
+ // this.props.time.dataset.setAttribute('time-end', end);
561
+ // }
562
+ // this.props.time.dataset.setAttribute('time-start', start);
563
+ // this.props.time.dataset.setAttribute('time-end', end);
564
+ if (this.layer.type === 'wmts') {
565
+ this.layer.customLayerParameters = {};
566
+ this.layer.customLayerParameters['TIME'] =
567
+ timeDict[this.TimesliderWidget.timeExtent.end];
568
+ } else {
569
+ this.layer.customLayerParameters = {};
570
+ if (times[this.layerName].hasOwnProperty('array')) {
571
+ this.layer.customLayerParameters['TIME'] =
572
+ timeDict[this.TimesliderWidget.timeExtent.end];
573
+ } else {
574
+ const newDateTimeObject = new Date(
575
+ this.TimesliderWidget.timeExtent.start.toISOString(),
576
+ );
577
+ newDateTimeObject.setMinutes(
578
+ this.TimesliderWidget.timeExtent.start.getMinutes() +
579
+ this.TimesliderWidget.stops['interval'].value,
580
+ );
581
+ this.layer.customLayerParameters['TIME'] =
582
+ this.TimesliderWidget.timeExtent.start.toISOString() +
583
+ '/' +
584
+ newDateTimeObject.toISOString(); //OK
585
+ }
586
+ }
587
+ this.layer.refresh();
588
+ });
589
+ } // if there is dimension time
590
+ else {
591
+ this.TimesliderWidget.disabled = true;
592
+ }
593
+ });
594
+ }
452
595
  } // is feature or WMS/WMTS
453
596
  });
454
597
  });