@eeacms/volto-arcgis-block 0.1.434 → 0.1.435

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,12 @@ 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.435](https://github.com/eea/volto-arcgis-block/compare/0.1.434...0.1.435) - 10 March 2026
8
+
9
+ #### :hammer_and_wrench: Others
10
+
11
+ - (bug): Fix Upload widget TOC menu stored services correct loading in 2D and 3D [Unai Bolivar - [`8b9e5fa`](https://github.com/eea/volto-arcgis-block/commit/8b9e5fad5a7d361e8fa4c8f48ae771422ae1c262)]
12
+ - (bug): fix upload widget error report, loading spinner, and TOC menu cleanup in 3D [Unai Bolivar - [`dc2ab0d`](https://github.com/eea/volto-arcgis-block/commit/dc2ab0d5ecafdb1cdc9c417bd8533c7ff0f28446)]
7
13
  ### [0.1.434](https://github.com/eea/volto-arcgis-block/compare/0.1.433...0.1.434) - 10 March 2026
8
14
 
9
15
  #### :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.434",
3
+ "version": "0.1.435",
4
4
  "description": "volto-arcgis-block: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: CodeSyntax",
@@ -1354,7 +1354,7 @@ class BookmarkWidget extends React.Component {
1354
1354
  }}
1355
1355
  type="submit"
1356
1356
  >
1357
- <span class="esri-bookmarks__add-bookmark-icon esri-icon-plus"></span>
1357
+ <span className="esri-bookmarks__add-bookmark-icon esri-icon-plus"></span>
1358
1358
  Upload a bookmark
1359
1359
  </button>
1360
1360
  </div>
@@ -37,11 +37,17 @@ class LoadingSpinner extends React.Component {
37
37
  });
38
38
  const handle3 = this.props.view.on('layerview-create-error', (event) => {
39
39
  if (!this._isMounted) return;
40
- if (event.layer.loadError !== null && this.state.loading === true) {
40
+ if (this.state.loading === true) {
41
41
  this.setState({ loading: false }, this.showLoading);
42
42
  }
43
43
  });
44
- this.arcgisEventHandles.push(handle1, handle2, handle3);
44
+ const handle4 = this.props.view.watch('updating', (isUpdating) => {
45
+ if (!this._isMounted) return;
46
+ if (!isUpdating && this.state.loading === true) {
47
+ this.setState({ loading: false }, this.showLoading);
48
+ }
49
+ });
50
+ this.arcgisEventHandles.push(handle1, handle2, handle3, handle4);
45
51
  }
46
52
 
47
53
  showLoading() {
@@ -386,6 +386,7 @@ class MapViewer extends React.Component {
386
386
  this.isViewModeButtonLoaded = false;
387
387
  this.viewUiOperationState = null;
388
388
  this.shouldClearSessionOnUnmount = true;
389
+ this.uploadErrorTimeoutTask = null;
389
390
  this.scheduleViewModeButtonLoad = this.scheduleViewModeButtonLoad.bind(
390
391
  this,
391
392
  );
@@ -1305,8 +1306,16 @@ class MapViewer extends React.Component {
1305
1306
 
1306
1307
  uploadFileErrorHandler = (errorType = 'uploadError') => {
1307
1308
  this.setState({ uploadError: true, uploadErrorType: errorType });
1308
- setTimeout(() => {
1309
+ if (this.uploadErrorTimeoutTask) {
1310
+ clearTimeout(this.uploadErrorTimeoutTask);
1311
+ this.uploadErrorTimeoutTask = null;
1312
+ }
1313
+ this.uploadErrorTimeoutTask = setTimeout(() => {
1314
+ if (!this.isComponentMounted) {
1315
+ return;
1316
+ }
1309
1317
  this.setState({ uploadError: false, uploadErrorType: 'uploadError' });
1318
+ this.uploadErrorTimeoutTask = null;
1310
1319
  }, 3000);
1311
1320
  };
1312
1321
 
@@ -1518,6 +1527,11 @@ class MapViewer extends React.Component {
1518
1527
  this.viewModeButtonTimeout = null;
1519
1528
  }
1520
1529
 
1530
+ if (this.uploadErrorTimeoutTask) {
1531
+ clearTimeout(this.uploadErrorTimeoutTask);
1532
+ this.uploadErrorTimeoutTask = null;
1533
+ }
1534
+
1521
1535
  window.removeEventListener('beforeunload', this.handlePageUnload);
1522
1536
  window.removeEventListener('pagehide', this.handlePageUnload);
1523
1537
  document.removeEventListener(
@@ -3583,6 +3583,35 @@ class MenuWidget extends React.Component {
3583
3583
  resourceLayer.ViewService = (viewService || '').trim();
3584
3584
  }
3585
3585
 
3586
+ const isSceneUploadValidation =
3587
+ this.view &&
3588
+ this.view.type === '3d' &&
3589
+ (serviceType === 'WMS' || serviceType === 'WMTS');
3590
+
3591
+ if (isSceneUploadValidation) {
3592
+ try {
3593
+ this.map.add(resourceLayer);
3594
+ await this.view.whenLayerView(resourceLayer);
3595
+ } catch (error) {
3596
+ try {
3597
+ if (this.map.findLayerById(resourceLayer.id)) {
3598
+ this.map.remove(resourceLayer);
3599
+ }
3600
+ } catch (e) {}
3601
+ if (this.isSceneTilingError(error)) {
3602
+ this.props.uploadFileErrorHandler('sceneViewTilingError');
3603
+ continue;
3604
+ }
3605
+ throw error;
3606
+ }
3607
+
3608
+ try {
3609
+ if (this.map.findLayerById(resourceLayer.id)) {
3610
+ this.map.remove(resourceLayer);
3611
+ }
3612
+ } catch (e) {}
3613
+ }
3614
+
3586
3615
  const layerSignatureData = `${(
3587
3616
  resourceLayer.ViewService || ''
3588
3617
  ).trim()}::${resourceLayer.LayerId}`;
@@ -3897,6 +3926,14 @@ class MenuWidget extends React.Component {
3897
3926
  const checkedLayers =
3898
3927
  JSON.parse(sessionStorage.getItem('checkedLayers')) || [];
3899
3928
  const isChecked = checkedLayers.includes(layer.LayerId);
3929
+ const serviceType =
3930
+ layer.type === 'wmts'
3931
+ ? 'WMTS'
3932
+ : layer.type === 'wms'
3933
+ ? 'WMS'
3934
+ : layer.type === 'geojson'
3935
+ ? 'WFS'
3936
+ : 'WMS';
3900
3937
 
3901
3938
  // Create a simplified object for storage
3902
3939
  return {
@@ -3918,9 +3955,18 @@ class MenuWidget extends React.Component {
3918
3955
  })),
3919
3956
  ViewService: layer.ViewService,
3920
3957
  LayerId: layer.LayerId,
3958
+ serviceType: serviceType,
3959
+ activeLayer:
3960
+ serviceType === 'WMTS' && layer.activeLayer
3961
+ ? {
3962
+ id: layer.activeLayer.id,
3963
+ title: layer.activeLayer.title,
3964
+ tileMatrixSetId: layer.activeLayer.tileMatrixSetId,
3965
+ }
3966
+ : null,
3921
3967
  visibility: layer.visible !== false,
3922
3968
  opacity: layer.opacity || 1,
3923
- checked: isChecked || layer.checked || false,
3969
+ checked: isChecked,
3924
3970
  };
3925
3971
  });
3926
3972
 
@@ -3941,26 +3987,65 @@ class MenuWidget extends React.Component {
3941
3987
  if (savedServices && Array.isArray(savedServices)) {
3942
3988
  // Process saved services to recreate actual layer objects
3943
3989
  const recreatedLayers = await Promise.all(
3944
- savedServices.map(async (serviceData) => {
3990
+ savedServices.map(async (serviceData, serviceIndex) => {
3945
3991
  try {
3946
- // Create a new WMSLayer with the saved properties
3947
- const newLayer = new WMSLayer(serviceData);
3992
+ const resolveServiceType =
3993
+ serviceData.serviceType ||
3994
+ (typeof serviceData.ViewService === 'string' &&
3995
+ serviceData.ViewService.toLowerCase().includes('wmts')
3996
+ ? 'WMTS'
3997
+ : 'WMS');
3998
+ const resolvedLayerId =
3999
+ serviceData.LayerId ||
4000
+ serviceData.id ||
4001
+ `user_service_${serviceIndex}`;
4002
+ const newLayer =
4003
+ resolveServiceType === 'WMTS'
4004
+ ? new WMTSLayer({
4005
+ id: resolvedLayerId,
4006
+ url: serviceData.url || serviceData.ViewService,
4007
+ title: serviceData.title || '',
4008
+ spatialReference: this.view?.spatialReference,
4009
+ serviceMode: 'KVP',
4010
+ activeLayer: serviceData.activeLayer || undefined,
4011
+ ViewService:
4012
+ serviceData.ViewService || serviceData.url || '',
4013
+ })
4014
+ : new WMSLayer({
4015
+ id: resolvedLayerId,
4016
+ url: serviceData.url || serviceData.ViewService,
4017
+ featureInfoFormat:
4018
+ serviceData.featureInfoFormat || 'text/html',
4019
+ featureInfoUrl:
4020
+ serviceData.featureInfoUrl ||
4021
+ serviceData.url ||
4022
+ serviceData.ViewService,
4023
+ title: serviceData.title || '',
4024
+ legendEnabled: serviceData.legendEnabled,
4025
+ sublayers: serviceData.sublayers,
4026
+ ViewService:
4027
+ serviceData.ViewService || serviceData.url || '',
4028
+ });
3948
4029
 
3949
4030
  // Set visibility property based on saved value
3950
4031
  newLayer.visible = serviceData.visibility !== false;
4032
+ newLayer.LayerId = resolvedLayerId;
4033
+ if (serviceData.description) {
4034
+ newLayer.description = serviceData.description;
4035
+ }
3951
4036
 
3952
4037
  // Remember the original checked state and visibility
3953
4038
  newLayer.checked = serviceData.checked;
3954
4039
 
3955
4040
  // Initialize visibleLayers for this layer
3956
4041
  if (!this.visibleLayers) this.visibleLayers = {};
3957
- this.visibleLayers[serviceData.LayerId] =
4042
+ this.visibleLayers[resolvedLayerId] =
3958
4043
  serviceData.visibility !== false
3959
4044
  ? ['fas', 'eye']
3960
4045
  : ['fas', 'eye-slash'];
3961
4046
 
3962
4047
  // Add to this.layers
3963
- this.layers[serviceData.LayerId] = newLayer;
4048
+ this.layers[resolvedLayerId] = newLayer;
3964
4049
  return newLayer;
3965
4050
  } catch (error) {
3966
4051
  return null;
@@ -3995,9 +4080,11 @@ class MenuWidget extends React.Component {
3995
4080
 
3996
4081
  // Then check the checkbox and call toggleLayer with a flag to preserve visibility
3997
4082
  node.checked = true;
4083
+ node.dataset.preserveCheckedLayerState = 'true';
3998
4084
 
3999
4085
  // Custom addition to toggleLayer to bypass visibility override
4000
4086
  this.toggleLayerWithoutVisibilityReset(node);
4087
+ delete node.dataset.preserveCheckedLayerState;
4001
4088
  }
4002
4089
  }
4003
4090
  });
@@ -4264,6 +4351,8 @@ class MenuWidget extends React.Component {
4264
4351
  this.state.wmsUserServiceLayers.find(
4265
4352
  (layer) => layer.LayerId === elem.id,
4266
4353
  ) || null;
4354
+ const preserveCheckedLayerState =
4355
+ elem.dataset && elem.dataset.preserveCheckedLayerState === 'true';
4267
4356
  if (elem.checked && !userService) {
4268
4357
  this.findCheckedDatasetNoServiceToVisualize(elem);
4269
4358
  }
@@ -4284,7 +4373,9 @@ class MenuWidget extends React.Component {
4284
4373
  if (!canApplyWmtsSettings) {
4285
4374
  elem.checked = false;
4286
4375
  this.layers[elem.id].visible = false;
4287
- this.deleteCheckedLayer(elem.id);
4376
+ if (!preserveCheckedLayerState) {
4377
+ this.deleteCheckedLayer(elem.id);
4378
+ }
4288
4379
  delete this.activeLayersJSON[elem.id];
4289
4380
  if (this.visibleLayers) {
4290
4381
  delete this.visibleLayers[elem.id];
@@ -4303,7 +4394,9 @@ class MenuWidget extends React.Component {
4303
4394
  try {
4304
4395
  await this.layers[elem.id].load();
4305
4396
  } catch (error) {
4306
- this.processUnsupportedWmtsLayer(elem);
4397
+ this.processUnsupportedWmtsLayer(elem, {
4398
+ preserveCheckedLayerState,
4399
+ });
4307
4400
  return;
4308
4401
  }
4309
4402
  }
@@ -4400,7 +4493,9 @@ class MenuWidget extends React.Component {
4400
4493
  try {
4401
4494
  await this.view.whenLayerView(this.layers[elem.id]);
4402
4495
  } catch (error) {
4403
- this.processUnsupportedWmtsLayer(elem);
4496
+ this.processUnsupportedWmtsLayer(elem, {
4497
+ preserveCheckedLayerState,
4498
+ });
4404
4499
  return;
4405
4500
  }
4406
4501
  }
@@ -4539,13 +4634,16 @@ class MenuWidget extends React.Component {
4539
4634
  this.url = null;
4540
4635
  }
4541
4636
 
4542
- processUnsupportedWmtsLayer(elem) {
4637
+ processUnsupportedWmtsLayer(elem, options = {}) {
4638
+ const { preserveCheckedLayerState = false } = options;
4543
4639
  if (!elem || !this.layers || !this.layers[elem.id]) {
4544
4640
  return;
4545
4641
  }
4546
4642
  elem.checked = false;
4547
4643
  this.layers[elem.id].visible = false;
4548
- this.deleteCheckedLayer(elem.id);
4644
+ if (!preserveCheckedLayerState) {
4645
+ this.deleteCheckedLayer(elem.id);
4646
+ }
4549
4647
  const mapLayer = this.map ? this.map.findLayerById(elem.id) : null;
4550
4648
  if (mapLayer) {
4551
4649
  try {
@@ -6906,7 +7004,9 @@ class MenuWidget extends React.Component {
6906
7004
  const node = document.getElementById(layer.LayerId);
6907
7005
  if (node) {
6908
7006
  node.checked = true;
7007
+ node.dataset.preserveCheckedLayerState = 'true';
6909
7008
  this.toggleLayer(node);
7009
+ delete node.dataset.preserveCheckedLayerState;
6910
7010
  }
6911
7011
  }
6912
7012
  });
@@ -7333,6 +7433,9 @@ class MenuWidget extends React.Component {
7333
7433
  for (var i = layers.length - 1; i >= 0; i--) {
7334
7434
  let layer = layers[i];
7335
7435
  let node = document.getElementById(layer);
7436
+ const restoreLayerState = this.state.wmsUserServiceLayers.some(
7437
+ (serviceLayer) => serviceLayer.LayerId === layer,
7438
+ );
7336
7439
 
7337
7440
  if (node) {
7338
7441
  if (!node.checked) {
@@ -7340,7 +7443,13 @@ class MenuWidget extends React.Component {
7340
7443
  // click event fires toggleLayer()
7341
7444
  //node.dispatchEvent(event);
7342
7445
  node.checked = true;
7446
+ if (restoreLayerState) {
7447
+ node.dataset.preserveCheckedLayerState = 'true';
7448
+ }
7343
7449
  this.toggleLayer(node);
7450
+ if (restoreLayerState) {
7451
+ delete node.dataset.preserveCheckedLayerState;
7452
+ }
7344
7453
  }
7345
7454
 
7346
7455
  // set scroll position