@eeacms/volto-arcgis-block 0.1.405 → 0.1.407

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,20 @@ 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.407](https://github.com/eea/volto-arcgis-block/compare/0.1.406...0.1.407) - 19 November 2025
8
+
9
+ #### :hammer_and_wrench: Others
10
+
11
+ - (feat): Rebased develop with this branch [Unai Bolivar - [`dae3e96`](https://github.com/eea/volto-arcgis-block/commit/dae3e96d56bd21d54a348267289932d299ba67b2)]
12
+ - (feat): Linting and prettifying before push [Unai Bolivar - [`455aa13`](https://github.com/eea/volto-arcgis-block/commit/455aa133d4da07949f3751d099c3f9ccddd4d971)]
13
+ - (feat): Error Report widget added user instructions and style changes [Unai Bolivar - [`3e69a69`](https://github.com/eea/volto-arcgis-block/commit/3e69a690467e1a66552a0ff8579b30eaabb5b95e)]
14
+ - (feat): Error Report widget added functionality, fixed bugs in css styles. [Unai Bolivar - [`1c833b2`](https://github.com/eea/volto-arcgis-block/commit/1c833b2b62e279fee1adbac0233f8d1cc5f2f559)]
15
+ - (feat): Error Report widget creation [Unai Bolivar - [`47ad31e`](https://github.com/eea/volto-arcgis-block/commit/47ad31e724279be223f3bdd3d8d619db32c24293)]
16
+ ### [0.1.406](https://github.com/eea/volto-arcgis-block/compare/0.1.405...0.1.406) - 19 November 2025
17
+
18
+ #### :hammer_and_wrench: Others
19
+
20
+ - CLMS-293307+CLMS-289791+CLMS-289790 (bug): Download button creation correction [Urkorue - [`d3684ca`](https://github.com/eea/volto-arcgis-block/commit/d3684ca9cb6ae617fa8c9fd1c1cf286f5fe8910f)]
7
21
  ### [0.1.405](https://github.com/eea/volto-arcgis-block/compare/0.1.404...0.1.405) - 12 November 2025
8
22
 
9
23
  ### [0.1.404](https://github.com/eea/volto-arcgis-block/compare/0.1.403...0.1.404) - 5 November 2025
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-arcgis-block",
3
- "version": "0.1.405",
3
+ "version": "0.1.407",
4
4
  "description": "volto-arcgis-block: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: CodeSyntax",
@@ -290,7 +290,81 @@ class BookmarkWidget extends React.Component {
290
290
  download_button.innerText = '⭳';
291
291
  download_button.bookmarkName = bookmark.innerText;
292
292
  download_button.addEventListener('click', (e) => {
293
- this.downloadBookmark(e.currentTarget.bookmarkName);
293
+ const name = e.currentTarget.bookmarkName;
294
+ let storageKey;
295
+ if (document.querySelector('.fa-user')) {
296
+ storageKey =
297
+ 'user_' +
298
+ document.querySelector('.fa-user').nextSibling
299
+ .textContent;
300
+ } else {
301
+ storageKey = 'user_anonymous';
302
+ }
303
+ let userObj;
304
+ try {
305
+ userObj =
306
+ JSON.parse(localStorage.getItem(storageKey)) || {};
307
+ } catch (e) {
308
+ userObj = {};
309
+ }
310
+ let bookmarks =
311
+ userObj &&
312
+ userObj.bookmarks &&
313
+ typeof userObj.bookmarks === 'object'
314
+ ? userObj.bookmarks
315
+ : null;
316
+ if (!bookmarks) {
317
+ try {
318
+ bookmarks = JSON.parse(
319
+ localStorage.getItem(
320
+ storageKey + '_bookmarks_backup',
321
+ ),
322
+ );
323
+ } catch (e) {
324
+ return;
325
+ }
326
+ }
327
+ if (!bookmarks) return;
328
+ let index = 0;
329
+ for (index; index < bookmarks.items.length; index++) {
330
+ if (bookmarks.items[index].name === name) {
331
+ break;
332
+ }
333
+ }
334
+ let selectedBookmark = {
335
+ items: Array.isArray(bookmarks.items)
336
+ ? bookmarks.items[index]
337
+ : [],
338
+ layers: Array.isArray(bookmarks.layers)
339
+ ? bookmarks.layers[index]
340
+ : [],
341
+ opacity: Array.isArray(bookmarks.opacity)
342
+ ? bookmarks.opacity[index]
343
+ : [],
344
+ visible: Array.isArray(bookmarks.visible)
345
+ ? bookmarks.visible[index]
346
+ : [],
347
+ hotspot: Array.isArray(bookmarks.hotspot)
348
+ ? bookmarks.hotspot[index]
349
+ : [],
350
+ selectedHotspotFilter:
351
+ bookmarks.selectedHotspotFilter != null
352
+ ? bookmarks.selectedHotspotFilter
353
+ : null,
354
+ };
355
+ let filename = 'bookmark_' + selectedBookmark.items.name;
356
+ const blob = new Blob(
357
+ [JSON.stringify(selectedBookmark)],
358
+ {
359
+ type: 'application/json',
360
+ },
361
+ );
362
+ const url = URL.createObjectURL(blob);
363
+ const a = document.createElement('a');
364
+ a.href = url;
365
+ a.download = `${filename}.json`;
366
+ a.click();
367
+ URL.revokeObjectURL(url);
294
368
  });
295
369
  bookmark.insertBefore(tooltip, bookmark.childNodes[2]);
296
370
  }
@@ -0,0 +1,299 @@
1
+ import React, { createRef } from 'react';
2
+ import { loadModules } from 'esri-loader';
3
+
4
+ class ErrorReport extends React.Component {
5
+ constructor(props) {
6
+ super(props);
7
+ this.container = createRef();
8
+ this.state = {
9
+ showMapMenu: false,
10
+ latlong: null,
11
+ selecting: false,
12
+ datasets: [],
13
+ instructionsText: 'First select a pixel in the data viewer',
14
+ };
15
+ this.menuClass =
16
+ 'esri-icon-notice-round esri-widget--button esri-widget esri-interactive';
17
+ this.helpdeskUrl = 'https://land.copernicus.eu/en/contact-service-helpdesk';
18
+ }
19
+
20
+ loader() {
21
+ return loadModules([]).then(() => {});
22
+ }
23
+
24
+ openMenu() {
25
+ if (this.state.showMapMenu) {
26
+ this.props.mapViewer.setActiveWidget();
27
+ this.container.current.querySelector('.right-panel').style.display =
28
+ 'none';
29
+ this.container.current
30
+ .querySelector('.esri-widget--button')
31
+ .classList.remove('active-widget');
32
+ document
33
+ .querySelector('.esri-ui-top-right.esri-ui-corner')
34
+ .classList.remove('show-panel');
35
+ this.setState({ showMapMenu: false });
36
+ this.resetData();
37
+ } else {
38
+ this.props.mapViewer.setActiveWidget(this);
39
+ this.container.current.querySelector('.right-panel').style.display =
40
+ 'flex';
41
+ this.container.current
42
+ .querySelector('.esri-widget--button')
43
+ .classList.add('active-widget');
44
+ document
45
+ .querySelector('.esri-ui-top-right.esri-ui-corner')
46
+ .classList.add('show-panel');
47
+ this.setState({ showMapMenu: true });
48
+ this.startSelection();
49
+ }
50
+ }
51
+
52
+ startSelection() {
53
+ if (this.state.selecting) return;
54
+ var handler = this.props.view.on(
55
+ 'pointer-down',
56
+ function (evt) {
57
+ let pt = this.props.view.toMap({ x: evt.x, y: evt.y });
58
+ let ds = this.getCheckedDatasets();
59
+ let message =
60
+ 'Selected coordinate: Lat ' +
61
+ pt.latitude.toFixed(4) +
62
+ ' Lon ' +
63
+ pt.longitude.toFixed(4) +
64
+ '. Active datasets: ' +
65
+ ds.join(', ');
66
+ try {
67
+ if (
68
+ navigator &&
69
+ navigator.clipboard &&
70
+ navigator.clipboard.writeText
71
+ ) {
72
+ navigator.clipboard.writeText(message);
73
+ } else {
74
+ let ta = document.createElement('textarea');
75
+ ta.value = message;
76
+ ta.setAttribute('readonly', '');
77
+ ta.style.position = 'absolute';
78
+ ta.style.left = '-9999px';
79
+ document.body.appendChild(ta);
80
+ ta.select();
81
+ document.execCommand('copy');
82
+ document.body.removeChild(ta);
83
+ }
84
+ } catch {}
85
+ this.setState({
86
+ latlong: { x: pt.latitude.toFixed(4), y: pt.longitude.toFixed(4) },
87
+ selecting: false,
88
+ datasets: ds,
89
+ instructionsText:
90
+ "The error report data has been added to your clipboard. Click the 'Service Desk' button and paste the clipboard content inside the Helpdesk's message box",
91
+ });
92
+ handler.remove();
93
+ }.bind(this),
94
+ );
95
+ this.setState({ selecting: handler });
96
+ }
97
+
98
+ getCheckedDatasets() {
99
+ try {
100
+ let uid = sessionStorage.getItem('mv_hydrated_for');
101
+ let key = uid ? 'user_' + uid : 'user_anonymous';
102
+ let raw = localStorage.getItem(key);
103
+ if (raw) {
104
+ let obj = JSON.parse(raw);
105
+ let cl = obj && obj.checkedLayers;
106
+ if (typeof cl === 'string') {
107
+ try {
108
+ cl = JSON.parse(cl);
109
+ } catch {}
110
+ }
111
+ if (Array.isArray(cl)) {
112
+ return [...new Set(cl)].filter((v) => v);
113
+ }
114
+ }
115
+ } catch {}
116
+ try {
117
+ let ss = sessionStorage.getItem('checkedLayers');
118
+ if (ss) {
119
+ let cl = ss;
120
+ if (typeof ss === 'string') {
121
+ try {
122
+ cl = JSON.parse(ss);
123
+ } catch {}
124
+ }
125
+ if (Array.isArray(cl)) {
126
+ return [...new Set(cl)].filter((v) => v);
127
+ }
128
+ }
129
+ } catch {}
130
+ let layers = [];
131
+ this.props.view.map.layers.forEach(function (l) {
132
+ if (l.visible) {
133
+ layers.push(l.title || l.id || 'layer');
134
+ }
135
+ });
136
+ return layers;
137
+ }
138
+
139
+ serviceDeskRedirect() {
140
+ if (!this.state.latlong) return;
141
+ let datasets =
142
+ this.state.datasets && this.state.datasets.length > 0
143
+ ? this.state.datasets
144
+ : this.getCheckedDatasets();
145
+ let message =
146
+ 'Selected coordinate: Lat ' +
147
+ this.state.latlong.x +
148
+ ' Lon ' +
149
+ this.state.latlong.y +
150
+ '. Active datasets: ' +
151
+ datasets.join(', ');
152
+ try {
153
+ if (navigator && navigator.clipboard && navigator.clipboard.writeText) {
154
+ navigator.clipboard.writeText(message);
155
+ } else {
156
+ let ta = document.createElement('textarea');
157
+ ta.value = message;
158
+ ta.setAttribute('readonly', '');
159
+ ta.style.position = 'absolute';
160
+ ta.style.left = '-9999px';
161
+ document.body.appendChild(ta);
162
+ ta.select();
163
+ document.execCommand('copy');
164
+ document.body.removeChild(ta);
165
+ }
166
+ } catch {}
167
+ window.open(this.helpdeskUrl, '_blank');
168
+ }
169
+
170
+ resetData() {
171
+ if (this.state.selecting) {
172
+ this.state.selecting.remove();
173
+ }
174
+ this.setState({
175
+ latlong: null,
176
+ selecting: false,
177
+ datasets: [],
178
+ instructionsText: 'First select a pixel in the data viewer',
179
+ });
180
+ }
181
+
182
+ async componentDidMount() {
183
+ await this.loader();
184
+ if (!this.container.current) return;
185
+ this.props.view.when(() => {
186
+ if (!this.container.current) return;
187
+ var group = document.querySelector('.esri-ui-top-right.esri-ui-corner');
188
+ var addSelf = () => {
189
+ this.props.view.ui.add(this.container.current, {
190
+ position: 'top-right',
191
+ // index: 9999,
192
+ });
193
+ };
194
+ if (group && group.children && group.children.length > 0) {
195
+ addSelf();
196
+ } else if (group) {
197
+ var observer = new MutationObserver((m) => {
198
+ if (group.children.length > 0) {
199
+ addSelf();
200
+ observer.disconnect();
201
+ }
202
+ });
203
+ observer.observe(group, { childList: true });
204
+ } else {
205
+ addSelf();
206
+ }
207
+ });
208
+ }
209
+
210
+ render() {
211
+ return (
212
+ <>
213
+ <div ref={this.container} className="error-report-container">
214
+ <div tooltip="Report an issue" direction="left" type="widget">
215
+ <div
216
+ className={this.menuClass}
217
+ id="map_error_report_button"
218
+ aria-label="Report an issue"
219
+ onClick={this.openMenu.bind(this)}
220
+ onKeyDown={(e) => {
221
+ if (
222
+ !e.altKey &&
223
+ e.code !== 'Tab' &&
224
+ !e.ctrlKey &&
225
+ e.code !== 'Delete' &&
226
+ !e.shiftKey &&
227
+ !e.code.startsWith('F')
228
+ ) {
229
+ this.openMenu(this);
230
+ }
231
+ }}
232
+ tabIndex="0"
233
+ role="button"
234
+ ></div>
235
+ </div>
236
+ <div className="right-panel">
237
+ <div className="right-panel-header">
238
+ <span>Report an issue</span>
239
+ <span
240
+ className="map-menu-icon esri-icon-close"
241
+ onClick={this.openMenu.bind(this)}
242
+ onKeyDown={(e) => {
243
+ if (
244
+ !e.altKey &&
245
+ e.code !== 'Tab' &&
246
+ !e.ctrlKey &&
247
+ e.code !== 'Delete' &&
248
+ !e.shiftKey &&
249
+ !e.code.startsWith('F')
250
+ ) {
251
+ this.openMenu(this);
252
+ }
253
+ }}
254
+ tabIndex="0"
255
+ role="button"
256
+ ></span>
257
+ </div>
258
+ <div className="right-panel-content">
259
+ <div className="error-report-panel">
260
+ <div className="error-report-instructions">
261
+ {this.state.instructionsText}
262
+ </div>
263
+ <button
264
+ className="error-report-button"
265
+ disabled={!this.state.latlong}
266
+ onClick={this.serviceDeskRedirect.bind(this)}
267
+ >
268
+ Service desk
269
+ </button>
270
+ {this.state.latlong && (
271
+ <>
272
+ <h3 className="error-report-coords-heading">Coordinates</h3>
273
+ <div className="error-report-coords">
274
+ Lat {this.state.latlong.x} Lon {this.state.latlong.y}
275
+ </div>
276
+ </>
277
+ )}
278
+ {this.state.datasets && this.state.datasets.length > 0 && (
279
+ <>
280
+ <div className="error-report-datasets-title">
281
+ Active datasets
282
+ </div>
283
+ <ul className="error-report-datasets">
284
+ {this.state.datasets.map((d, i) => (
285
+ <li key={i}>{d}</li>
286
+ ))}
287
+ </ul>
288
+ </>
289
+ )}
290
+ </div>
291
+ </div>
292
+ </div>
293
+ </div>
294
+ </>
295
+ );
296
+ }
297
+ }
298
+
299
+ export default ErrorReport;
@@ -30,6 +30,7 @@ import PanWidget from './PanWidget';
30
30
  import BookmarkWidget from './BookmarkWidget';
31
31
  import LoadingSpinner from './LoadingSpinner';
32
32
  import UploadWidget from './UploadWidget';
33
+ import ErrorReportWidget from './ErrorReportWidget';
33
34
  import { injectLazyLibs } from '@plone/volto/helpers/Loadable';
34
35
  import { getTaxonomy } from '@eeacms/volto-taxonomy/actions';
35
36
  import { fetchCatalogApiDates } from '../../actions';
@@ -1016,6 +1017,10 @@ class MapViewer extends React.Component {
1016
1017
  />
1017
1018
  );
1018
1019
  }
1020
+ renderErrorReport() {
1021
+ if (this.view)
1022
+ return <ErrorReportWidget view={this.view} mapViewer={this} />;
1023
+ }
1019
1024
  /**
1020
1025
  * This method renders the map viewer, invoking if necessary the methods
1021
1026
  * to render the other widgets to display
@@ -1048,6 +1053,7 @@ class MapViewer extends React.Component {
1048
1053
  {this.renderLoadingSpinner()}
1049
1054
  <CheckUserID reference={this} />
1050
1055
  {this.renderUploadService()}
1056
+ {this.renderErrorReport()}
1051
1057
  </div>
1052
1058
  </div>
1053
1059
  );
@@ -313,6 +313,34 @@ button.upload-bookmark-button {
313
313
  font-size: 30px !important;
314
314
  }
315
315
 
316
+ /* Error report */
317
+ .error-report-button {
318
+ display: block;
319
+ width: 100%;
320
+ box-sizing: border-box;
321
+ padding: 0.75rem 1rem;
322
+ border: 1px solid #a0b128 !important;
323
+ margin: 1rem 0;
324
+ background-color: white !important;
325
+ color: #a0b128 !important;
326
+ cursor: pointer;
327
+ text-align: center;
328
+ transition: all 0.3s ease-out;
329
+ }
330
+
331
+ .error-report-button:hover {
332
+ border-color: #a0b128 !important;
333
+ background-color: #a0b128 !important;
334
+ color: white !important;
335
+ }
336
+
337
+ .error-report-datasets-title {
338
+ margin-top: 1em;
339
+ margin-bottom: 0.5em;
340
+ font-size: 1.17em;
341
+ font-weight: bold;
342
+ }
343
+
316
344
  body.section-map-viewer
317
345
  #page-document.ui.container
318
346
  .esri-widget__content--empty