@eeacms/volto-arcgis-block 0.1.345 → 0.1.346

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,14 @@ 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.346](https://github.com/eea/volto-arcgis-block/compare/0.1.345...0.1.346) - 1 April 2025
8
+
9
+ #### :hammer_and_wrench: Others
10
+
11
+ - CLMS-286065 (bug): Pan cursor no longer pushes other widget buttons down when loading in view [Unai Bolivar - [`98bb42b`](https://github.com/eea/volto-arcgis-block/commit/98bb42bcf2ef04fae4b2821c2b7290e911c84478)]
12
+ - CLMS-286065 (bug): Fixed bug where deleting a user service does not uncheck the rest of the user services [Unai Bolivar - [`300be08`](https://github.com/eea/volto-arcgis-block/commit/300be0808a3c81ee21581ae64080b1533ac9b784)]
13
+ - CLMS-286081 (bug): Fixed persistence for user services of logged user. [Unai Bolivar - [`43dacf7`](https://github.com/eea/volto-arcgis-block/commit/43dacf79aefaf6925f9cdfdaedacb7fcae9fab63)]
14
+ - CLMS-286042 (bug): Fixed user wms service not loading after being deleted from my services [Unai Bolivar - [`17c8bef`](https://github.com/eea/volto-arcgis-block/commit/17c8bef7ac05c1ea1bedfdf61c54ed3193a27c3d)]
7
15
  ### [0.1.345](https://github.com/eea/volto-arcgis-block/compare/0.1.344...0.1.345) - 28 March 2025
8
16
 
9
17
  #### :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.345",
3
+ "version": "0.1.346",
4
4
  "description": "volto-arcgis-block: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: CodeSyntax",
@@ -855,6 +855,9 @@ class AreaWidget extends React.Component {
855
855
  rectanglehandler(event) {
856
856
  this.clearWidget();
857
857
  window.document.querySelector('.pan-container').style.display = 'flex';
858
+ window.document.querySelector('.pan-container').style.position = 'absolute';
859
+ window.document.querySelector('.pan-container').style.paddingRight =
860
+ '21rem';
858
861
  var fillSymbol = {
859
862
  type: 'simple-fill',
860
863
  color: [255, 255, 255, 0.5],
@@ -61,6 +61,7 @@ class MapViewer extends React.Component {
61
61
  layers: {},
62
62
  uploadedFile: true,
63
63
  wmsServiceUrl: '',
64
+ uploadError: false,
64
65
  };
65
66
  this.activeLayersHandler = this.activeLayersHandler.bind(this);
66
67
  this.activeLayersArray = {};
@@ -169,16 +170,10 @@ class MapViewer extends React.Component {
169
170
  this.setState({ uploadedFile: message });
170
171
  }
171
172
 
172
- uploadFileErrorHandler = (error) => {
173
- this.setState({
174
- showInfoPopup: true,
175
- infoPopupType: 'uploadError',
176
- });
173
+ uploadFileErrorHandler = () => {
174
+ this.setState({ uploadError: true });
177
175
  setTimeout(() => {
178
- this.setState({
179
- showInfoPopup: false,
180
- infoPopupType: '',
181
- });
176
+ this.setState({ uploadError: false });
182
177
  }, 3000);
183
178
  };
184
179
 
@@ -191,7 +186,7 @@ class MapViewer extends React.Component {
191
186
  }
192
187
  };
193
188
 
194
- serviceAddedHandler = () => {
189
+ serviceChangeHandler = () => {
195
190
  // Reset wmsServiceUrl without causing a new update of the children
196
191
  this.setState({ wmsServiceUrl: '' });
197
192
  };
@@ -481,43 +476,43 @@ class MapViewer extends React.Component {
481
476
  );
482
477
  }
483
478
 
484
- renderMenu() {
485
- if (this.view)
486
- return (
487
- <MenuWidget
488
- location={this.location}
489
- view={this.view}
490
- conf={this.props.mapviewer_config.Components}
491
- download={this.props.mapviewer_config.Download}
492
- map={this.map}
493
- mapViewer={this}
494
- updateArea={this.updateArea}
495
- area={this.state.area}
496
- layers={this.state.layers}
497
- activeLayersHandler={this.activeLayersHandler}
498
- urls={this.cfgUrls}
499
- loadingHandler={this.loadingHandler}
500
- hotspotDataHandler={this.hotspotDataHandler}
501
- hotspotData={this.state.hotspotData}
502
- mapLayersHandler={this.mapLayersHandler}
503
- bookmarkData={this.state.bookmarkData}
504
- bookmarkHandler={this.bookmarkHandler}
505
- prepackageChecked={this.state.prepackageChecked}
506
- prepackageHandler={this.prepackageHandler}
507
- uploadedFile={this.state.uploadedFile}
508
- uploadFileHandler={this.uploadFileHandler}
509
- uploadUrlServiceHandler={this.uploadUrlServiceHandler}
510
- wmsServiceUrl={this.state.wmsServiceUrl}
511
- onServiceAdded={this.serviceAddedHandler}
512
- uploadFileErrorHandler={this.uploadFileErrorHandler}
513
- //getTaxonomy={this.getTaxonomy}
514
- />
515
- ); //call conf
516
- }
479
+ // renderMenu() {
480
+ // if (this.view)
481
+ // return (
482
+ // <MenuWidget
483
+ // location={this.location}
484
+ // view={this.view}
485
+ // conf={this.props.mapviewer_config.Components}
486
+ // download={this.props.mapviewer_config.Download}
487
+ // map={this.map}
488
+ // mapViewer={this}
489
+ // updateArea={this.updateArea}
490
+ // area={this.state.area}
491
+ // layers={this.state.layers}
492
+ // activeLayersHandler={this.activeLayersHandler}
493
+ // urls={this.cfgUrls}
494
+ // loadingHandler={this.loadingHandler}
495
+ // hotspotDataHandler={this.hotspotDataHandler}
496
+ // hotspotData={this.state.hotspotData}
497
+ // mapLayersHandler={this.mapLayersHandler}
498
+ // bookmarkData={this.state.bookmarkData}
499
+ // bookmarkHandler={this.bookmarkHandler}
500
+ // prepackageChecked={this.state.prepackageChecked}
501
+ // prepackageHandler={this.prepackageHandler}
502
+ // uploadedFile={this.state.uploadedFile}
503
+ // uploadFileHandler={this.uploadFileHandler}
504
+ // uploadUrlServiceHandler={this.uploadUrlServiceHandler}
505
+ // wmsServiceUrl={this.state.wmsServiceUrl}
506
+ // onServiceChange={this.serviceChangeHandler}
507
+ // uploadFileErrorHandler={this.uploadFileErrorHandler}
508
+ // //getTaxonomy={this.getTaxonomy}
509
+ // />
510
+ // ); //call conf
511
+ // }
517
512
 
518
- renderBookmark() {
519
- if (this.view) return <CheckUserID reference={this} />;
520
- }
513
+ // renderBookmark() {
514
+ // if (this.view) return <CheckUserID reference={this} />;
515
+ // }
521
516
 
522
517
  appLanguage() {
523
518
  return intl && <CheckLanguage />;
@@ -538,8 +533,9 @@ class MapViewer extends React.Component {
538
533
  map={this.map}
539
534
  mapViewer={this}
540
535
  wmsServiceUrl={this.state.wmsServiceUrl}
536
+ showErrorPopup={this.state.uploadError}
541
537
  uploadUrlServiceHandler={this.uploadUrlServiceHandler}
542
- uploadfileErrorHandler={this.uploadFileErrorHandler}
538
+ uploadFileErrorHandler={this.uploadFileErrorHandler}
543
539
  />
544
540
  );
545
541
  }
@@ -572,8 +568,9 @@ class MapViewer extends React.Component {
572
568
  {this.renderScale()}
573
569
  {this.renderInfo()}
574
570
  {this.renderHotspot()}
575
- {this.renderMenu()}
576
- {this.renderBookmark()}
571
+ {/*this.renderMenu()*/}
572
+ {/*this.renderBookmark()*/}
573
+ <CheckUserID reference={this} />
577
574
  {this.renderLoadingSpinner()}
578
575
  {this.renderUploadService()}
579
576
  </div>
@@ -607,20 +604,54 @@ export const CheckLogin = ({ reference }) => {
607
604
  };
608
605
  export const CheckUserID = ({ reference }) => {
609
606
  let { user_id } = useCartState();
607
+
610
608
  return (
611
609
  <>
612
- {
613
- <BookmarkWidget
614
- view={reference.view}
615
- map={reference.map}
616
- layers={reference.state.layers}
617
- mapViewer={reference}
618
- userID={user_id}
619
- hotspotData={reference.state.hotspotData}
620
- bookmarkHandler={reference.bookmarkHandler}
621
- bookmarkData={reference.state.bookmarkData}
622
- />
623
- }
610
+ {reference.view && (
611
+ <>
612
+ {/* BookmarkWidget with user_id */}
613
+ <BookmarkWidget
614
+ view={reference.view}
615
+ map={reference.map}
616
+ layers={reference.state.layers}
617
+ mapViewer={reference}
618
+ userID={user_id}
619
+ hotspotData={reference.state.hotspotData}
620
+ bookmarkHandler={reference.bookmarkHandler}
621
+ bookmarkData={reference.state.bookmarkData}
622
+ />
623
+
624
+ {/* MenuWidget with user_id */}
625
+ <MenuWidget
626
+ location={reference.location}
627
+ view={reference.view}
628
+ conf={reference.props.mapviewer_config.Components}
629
+ download={reference.props.mapviewer_config.Download}
630
+ map={reference.map}
631
+ mapViewer={reference}
632
+ updateArea={reference.updateArea}
633
+ area={reference.state.area}
634
+ layers={reference.state.layers}
635
+ activeLayersHandler={reference.activeLayersHandler}
636
+ urls={reference.cfgUrls}
637
+ loadingHandler={reference.loadingHandler}
638
+ hotspotDataHandler={reference.hotspotDataHandler}
639
+ hotspotData={reference.state.hotspotData}
640
+ mapLayersHandler={reference.mapLayersHandler}
641
+ bookmarkData={reference.state.bookmarkData}
642
+ bookmarkHandler={reference.bookmarkHandler}
643
+ prepackageChecked={reference.state.prepackageChecked}
644
+ prepackageHandler={reference.prepackageHandler}
645
+ uploadedFile={reference.state.uploadedFile}
646
+ uploadFileHandler={reference.uploadFileHandler}
647
+ uploadUrlServiceHandler={reference.uploadUrlServiceHandler}
648
+ wmsServiceUrl={reference.state.wmsServiceUrl}
649
+ onServiceChange={reference.serviceChangeHandler}
650
+ uploadFileErrorHandler={reference.uploadFileErrorHandler}
651
+ userID={user_id}
652
+ />
653
+ </>
654
+ )}
624
655
  </>
625
656
  );
626
657
  };
@@ -7,6 +7,9 @@ import useCartState from '@eeacms/volto-clms-utils/cart/useCartState';
7
7
  import { Modal, Popup } from 'semantic-ui-react';
8
8
  import AreaWidget from './AreaWidget';
9
9
  import TimesliderWidget from './TimesliderWidget';
10
+
11
+ export const USER_SERVICES_KEY = 'user_services_session';
12
+
10
13
  var WMSLayer,
11
14
  WMTSLayer,
12
15
  FeatureLayer,
@@ -404,6 +407,7 @@ class MenuWidget extends React.Component {
404
407
  this.compCfg = this.props.conf;
405
408
  this.map = this.props.map;
406
409
  this.view = this.props.view;
410
+ this.userID = this.props.userID;
407
411
  this.state = {
408
412
  showMapMenu: false,
409
413
  noServiceModal: false,
@@ -927,7 +931,7 @@ class MenuWidget extends React.Component {
927
931
  this.loadVisibility();
928
932
  this.handleRasterVectorLegend();
929
933
  this.map.when(() => {
930
- this.map.layers.on('change', (e) => {
934
+ this.map.layers.on('change', () => {
931
935
  if (!this.props.bookmarkData?.active) return;
932
936
 
933
937
  this.map.layers.removeAll();
@@ -1000,6 +1004,7 @@ class MenuWidget extends React.Component {
1000
1004
  const myServicesContainer = document.createElement('div');
1001
1005
  ReactDOM.render(myServicesComponent, myServicesContainer);
1002
1006
  this.container.current.appendChild(myServicesContainer.firstChild);
1007
+ this.loadUserServicesFromStorage();
1003
1008
  }
1004
1009
 
1005
1010
  setSliderTag(val) {
@@ -1958,10 +1963,18 @@ class MenuWidget extends React.Component {
1958
1963
  }
1959
1964
 
1960
1965
  async handleNewMapServiceLayer(viewService) {
1961
- // Check if the URL is already in state to prevent duplicates
1966
+ // First, properly normalize the URL for comparison
1967
+ const normalizedViewService = viewService.trim();
1968
+
1962
1969
  if (
1963
- this.state.wmsUserServiceLayers.some((layer) => layer.url === viewService)
1970
+ this.state.wmsUserServiceLayers.some(
1971
+ (layer) =>
1972
+ layer.url === normalizedViewService ||
1973
+ layer.ViewService === normalizedViewService,
1974
+ )
1964
1975
  ) {
1976
+ // Call the uploadFileErrorHandler to show the error popup
1977
+ this.props.uploadFileErrorHandler();
1965
1978
  return;
1966
1979
  }
1967
1980
 
@@ -2029,24 +2042,19 @@ class MenuWidget extends React.Component {
2029
2042
  // Create and add the new layer
2030
2043
  this.layers[LayerId] = new WMSLayer(layerObj);
2031
2044
 
2045
+ this.saveCheckedLayer(layerId);
2046
+
2032
2047
  // Update state to include the new layer, which will trigger componentDidUpdate
2033
2048
  this.setState((prevState) => {
2034
- return {
2035
- wmsUserServiceLayers: [
2036
- ...prevState.wmsUserServiceLayers,
2037
- this.layers[LayerId],
2038
- ],
2039
- };
2049
+ const updatedLayers = [
2050
+ ...prevState.wmsUserServiceLayers,
2051
+ this.layers[LayerId],
2052
+ ];
2053
+ this.saveUserServicesToStorage(updatedLayers);
2054
+ return { wmsUserServiceLayers: updatedLayers };
2040
2055
  });
2041
2056
 
2042
- this.props.onServiceAdded();
2043
-
2044
- // Add the layer to the map
2045
- const node = document.getElementById(LayerId);
2046
- if (node) {
2047
- node.checked = true;
2048
- this.toggleLayer(node);
2049
- }
2057
+ this.props.onServiceChange();
2050
2058
  } catch (error) {
2051
2059
  // Set a popup error message in here
2052
2060
  this.props.uploadFileErrorHandler();
@@ -2183,7 +2191,8 @@ class MenuWidget extends React.Component {
2183
2191
  removeLayer = null;
2184
2192
  }
2185
2193
 
2186
- // Update state to trigger componentDidUpdate
2194
+ this.props.onServiceChange();
2195
+
2187
2196
  this.setState((prevState) => {
2188
2197
  const layerExists = prevState.wmsUserServiceLayers.some(
2189
2198
  (layer) => layer.LayerId === elemId,
@@ -2193,16 +2202,95 @@ class MenuWidget extends React.Component {
2193
2202
  const newWmsUserServiceLayers = prevState.wmsUserServiceLayers.filter(
2194
2203
  (layer) => layer.LayerId !== elemId,
2195
2204
  );
2196
- return {
2197
- wmsUserServiceLayers: newWmsUserServiceLayers,
2198
- };
2205
+ this.saveUserServicesToStorage(newWmsUserServiceLayers);
2206
+ return { wmsUserServiceLayers: newWmsUserServiceLayers };
2199
2207
  }
2200
-
2201
- // If layer doesn't exist, return unchanged state to avoid issues
2202
2208
  return null;
2203
2209
  });
2204
2210
  }
2205
2211
 
2212
+ saveUserServicesToStorage(layers) {
2213
+ if (this.userID == null) return;
2214
+
2215
+ try {
2216
+ const layersToSave = layers.map((layer) => {
2217
+ // Create a simplified object for storage
2218
+ return {
2219
+ url: layer.url,
2220
+ featureInfoFormat: layer.featureInfoFormat,
2221
+ featureInfoUrl: layer.featureInfoUrl,
2222
+ title: layer.title,
2223
+ legendEnabled: layer.legendEnabled,
2224
+ sublayers: layer.sublayers?.items?.map((sublayer) => ({
2225
+ index: sublayer.index,
2226
+ name: sublayer.name,
2227
+ title: sublayer.title,
2228
+ popupEnabled: sublayer.popupEnabled,
2229
+ queryable: sublayer.queryable,
2230
+ visible: sublayer.visible,
2231
+ legendEnabled: sublayer.legendEnabled,
2232
+ legendUrl: sublayer.legendUrl,
2233
+ featureInfoUrl: sublayer.featureInfoUrl,
2234
+ })),
2235
+ ViewService: layer.ViewService,
2236
+ LayerId: layer.LayerId,
2237
+ };
2238
+ });
2239
+
2240
+ localStorage.setItem(
2241
+ USER_SERVICES_KEY + '_' + this.userID,
2242
+ JSON.stringify(layersToSave),
2243
+ );
2244
+ } catch (error) {}
2245
+ }
2246
+
2247
+ async loadUserServicesFromStorage() {
2248
+ if (this.userID != null) {
2249
+ try {
2250
+ const savedServices = JSON.parse(
2251
+ localStorage.getItem(USER_SERVICES_KEY + '_' + this.userID),
2252
+ );
2253
+
2254
+ if (savedServices && Array.isArray(savedServices)) {
2255
+ // Process saved services to recreate actual layer objects
2256
+ const recreatedLayers = await Promise.all(
2257
+ savedServices.map(async (serviceData) => {
2258
+ try {
2259
+ // Create a new WMSLayer with the saved properties
2260
+ const newLayer = new WMSLayer(serviceData);
2261
+ // Add to this.layers
2262
+ this.layers[serviceData.LayerId] = newLayer;
2263
+ return newLayer;
2264
+ } catch (error) {
2265
+ return null;
2266
+ }
2267
+ }),
2268
+ );
2269
+
2270
+ // Filter out any null values from failed recreations
2271
+ const validLayers = recreatedLayers.filter((layer) => layer !== null);
2272
+
2273
+ // Update state with recreated layers
2274
+ this.setState({ wmsUserServiceLayers: validLayers });
2275
+ // Get checked layers from session storage
2276
+ const checkedLayers =
2277
+ JSON.parse(sessionStorage.getItem('checkedLayers')) || [];
2278
+
2279
+ // For each valid layer that was previously checked, make it visible
2280
+ validLayers.forEach((layer) => {
2281
+ if (checkedLayers.includes(layer.LayerId)) {
2282
+ const node = document.getElementById(layer.LayerId);
2283
+ if (node) {
2284
+ node.checked = true;
2285
+ this.toggleLayer(node);
2286
+ }
2287
+ }
2288
+ });
2289
+ }
2290
+ } catch (error) {}
2291
+ }
2292
+ }
2293
+
2206
2294
  /**
2207
2295
  * Method to show/hide a layer. Update checkboxes from dataset and products
2208
2296
  * @param {*} elem Is the checkbox
@@ -4093,6 +4181,21 @@ class MenuWidget extends React.Component {
4093
4181
 
4094
4182
  if (prevState.wmsUserServiceLayers !== this.state.wmsUserServiceLayers) {
4095
4183
  this.createUserServices(this.state.wmsUserServiceLayers);
4184
+ setTimeout(() => {
4185
+ const checkedLayers =
4186
+ JSON.parse(sessionStorage.getItem('checkedLayers')) || [];
4187
+
4188
+ // For each valid layer that was previously checked, make it visible
4189
+ this.state.wmsUserServiceLayers.forEach((layer) => {
4190
+ if (checkedLayers.includes(layer.LayerId)) {
4191
+ const node = document.getElementById(layer.LayerId);
4192
+ if (node) {
4193
+ node.checked = true;
4194
+ this.toggleLayer(node);
4195
+ }
4196
+ }
4197
+ });
4198
+ }, 0);
4096
4199
  }
4097
4200
  if (
4098
4201
  this.state.wmsUserServiceLayers.length > 0 &&
@@ -4123,13 +4226,23 @@ class MenuWidget extends React.Component {
4123
4226
  }
4124
4227
  const latestLayer = JSON.parse(sessionStorage.getItem('TMSLayerObj'));
4125
4228
 
4126
- if (latestLayer) {
4229
+ if (latestLayer && BaseTileLayer) {
4127
4230
  this.view.when(() => {
4128
4231
  if (this.view.stationary) {
4129
4232
  const { layer, checkboxId, dataset } = latestLayer;
4130
4233
  this.processTMSLayer(checkboxId, layer, dataset);
4131
4234
  }
4132
4235
  });
4236
+ } else if (latestLayer) {
4237
+ // If we have a layer but BaseTileLayer isn't loaded yet, wait for it
4238
+ this.loader().then(() => {
4239
+ this.view.when(() => {
4240
+ if (this.view.stationary) {
4241
+ const { layer, checkboxId, dataset } = latestLayer;
4242
+ this.processTMSLayer(checkboxId, layer, dataset);
4243
+ }
4244
+ });
4245
+ });
4133
4246
  }
4134
4247
  this.setLegendOpacity();
4135
4248
  }
@@ -27,6 +27,8 @@ class UploadWidget extends React.Component {
27
27
  this.mapviewer_config = this.props.mapviewer_config;
28
28
  this.fileInput = createRef();
29
29
  this.uploadUrlServiceHandler = this.props.uploadUrlServiceHandler;
30
+ this.uploadFileErrorHandler = this.props.uploadFileErrorHandler;
31
+ this.errorPopup = this.errorPopup.bind(this);
30
32
  }
31
33
 
32
34
  loader() {
@@ -139,17 +141,21 @@ class UploadWidget extends React.Component {
139
141
  wmsServiceUrl: '',
140
142
  });
141
143
  } else {
144
+ this.errorPopup();
145
+ }
146
+ };
147
+
148
+ errorPopup = () => {
149
+ this.setState({
150
+ showInfoPopup: true,
151
+ infoPopupType: 'uploadError',
152
+ });
153
+ setTimeout(() => {
142
154
  this.setState({
143
- showInfoPopup: true,
144
- infoPopupType: 'uploadError',
155
+ showInfoPopup: false,
156
+ infoPopupType: '',
145
157
  });
146
- setTimeout(() => {
147
- this.setState({
148
- showInfoPopup: false,
149
- infoPopupType: '',
150
- });
151
- }, 3000);
152
- }
158
+ }, 3000);
153
159
  };
154
160
 
155
161
  /**
@@ -171,6 +177,12 @@ class UploadWidget extends React.Component {
171
177
  });
172
178
  }
173
179
 
180
+ componentDidUpdate(prevProps) {
181
+ if (!prevProps.showErrorPopup && this.props.showErrorPopup) {
182
+ this.errorPopup();
183
+ }
184
+ }
185
+
174
186
  /**
175
187
  * This method renders the component
176
188
  * @returns jsx