qwc2 2026.8.7 → 2026.8.13

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.
Files changed (46) hide show
  1. package/actions/bookmark.js +0 -15
  2. package/actions/localConfig.js +0 -7
  3. package/components/BookmarkPanel.js +121 -124
  4. package/components/Icon.js +2 -0
  5. package/components/IdentifyViewer.js +62 -35
  6. package/components/StandardApp.js +0 -5
  7. package/components/map3d/Map3D.js +10 -8
  8. package/components/style/BookmarkPanel.css +2 -0
  9. package/components/style/Icon.css +4 -0
  10. package/components/widgets/InputContainer.js +2 -29
  11. package/components/widgets/style/InputContainer.css +2 -1
  12. package/package.json +1 -1
  13. package/plugins/Bookmark.js +25 -19
  14. package/plugins/BottomBar.js +2 -2
  15. package/plugins/Identify.js +113 -23
  16. package/plugins/MapFilter.js +48 -34
  17. package/plugins/VisibilityPreset.js +34 -23
  18. package/reducers/localConfig.js +2 -21
  19. package/scripts/themesConfig.js +4 -0
  20. package/scripts/themesConfig.py +2 -0
  21. package/static/translations/bg-BG.json +11 -6
  22. package/static/translations/ca-ES.json +11 -6
  23. package/static/translations/cs-CZ.json +11 -6
  24. package/static/translations/de-CH.json +11 -6
  25. package/static/translations/de-DE.json +11 -6
  26. package/static/translations/en-US.json +11 -6
  27. package/static/translations/es-ES.json +11 -6
  28. package/static/translations/fi-FI.json +11 -6
  29. package/static/translations/fr-FR.json +11 -6
  30. package/static/translations/hu-HU.json +11 -6
  31. package/static/translations/it-IT.json +11 -6
  32. package/static/translations/ja-JP.json +11 -6
  33. package/static/translations/nl-NL.json +11 -6
  34. package/static/translations/no-NO.json +11 -6
  35. package/static/translations/pl-PL.json +11 -6
  36. package/static/translations/pt-BR.json +11 -6
  37. package/static/translations/pt-PT.json +11 -6
  38. package/static/translations/ro-RO.json +11 -6
  39. package/static/translations/ru-RU.json +11 -6
  40. package/static/translations/sv-SE.json +11 -6
  41. package/static/translations/tr-TR.json +11 -6
  42. package/static/translations/tsconfig.json +11 -6
  43. package/static/translations/uk-UA.json +11 -6
  44. package/utils/LayerUtils.js +18 -5
  45. package/utils/PermaLinkUtils.js +254 -286
  46. package/utils/ServiceLayerUtils.js +2 -0
@@ -1261,14 +1261,16 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
1261
1261
  };
1262
1262
  });
1263
1263
  resolve({
1264
- objects: objects,
1265
- colorLayers: layers,
1266
- baseLayer: ((_this2$state$sceneCon6 = _this2.state.sceneContext.baseLayers.find(function (layer) {
1267
- return layer.visibility === true;
1268
- })) === null || _this2$state$sceneCon6 === void 0 ? void 0 : _this2$state$sceneCon6.name) || "",
1269
- personHeight: (_this2$state$sceneCon7 = _this2.state.sceneContext.scene.view.controls.personHeight) !== null && _this2$state$sceneCon7 !== void 0 ? _this2$state$sceneCon7 : 0,
1270
- camera: [camera.x, camera.y, camera.z],
1271
- target: [target.x, target.y, target.z]
1264
+ state: {
1265
+ objects: objects,
1266
+ colorLayers: layers,
1267
+ baseLayer: ((_this2$state$sceneCon6 = _this2.state.sceneContext.baseLayers.find(function (layer) {
1268
+ return layer.visibility === true;
1269
+ })) === null || _this2$state$sceneCon6 === void 0 ? void 0 : _this2$state$sceneCon6.name) || "",
1270
+ personHeight: (_this2$state$sceneCon7 = _this2.state.sceneContext.scene.view.controls.personHeight) !== null && _this2$state$sceneCon7 !== void 0 ? _this2$state$sceneCon7 : 0,
1271
+ camera: [camera.x, camera.y, camera.z],
1272
+ target: [target.x, target.y, target.z]
1273
+ }
1272
1274
  });
1273
1275
  });
1274
1276
  });
@@ -37,6 +37,8 @@ div.bookmark-list-item {
37
37
  div.bookmark-list-item > div.input-container {
38
38
  flex: 1 1 auto;
39
39
  border: none;
40
+ color: var(--text-color);
41
+ border: 1px solid var(--color-active);
40
42
  }
41
43
 
42
44
  div.bookmark-list-item-empty {
@@ -25,3 +25,7 @@ span.icon_xlarge:before {
25
25
  cursor: default;
26
26
  color: var(--text-color-disabled);
27
27
  }
28
+
29
+ .icon_inactive {
30
+ color: #ccc;
31
+ }
@@ -32,40 +32,19 @@ var InputContainer = /*#__PURE__*/function (_React$Component) {
32
32
  args[_key] = arguments[_key];
33
33
  }
34
34
  _this = _callSuper(this, InputContainer, [].concat(args));
35
- _defineProperty(_this, "state", {
36
- focused: false
37
- });
38
35
  _defineProperty(_this, "findChild", function (role) {
39
36
  return React.Children.toArray(_this.props.children).filter(function (child) {
40
37
  return child.props.role === role;
41
38
  });
42
39
  });
43
- _defineProperty(_this, "onInputBlur", function (ev, origHandler) {
44
- if (origHandler) {
45
- origHandler(ev);
46
- }
47
- _this.setState({
48
- focused: false
49
- });
50
- });
51
- _defineProperty(_this, "onInputFocus", function (ev, origHandler) {
52
- if (origHandler) {
53
- origHandler(ev);
54
- }
55
- _this.setState({
56
- focused: true
57
- });
58
- });
59
40
  return _this;
60
41
  }
61
42
  _inherits(InputContainer, _React$Component);
62
43
  return _createClass(InputContainer, [{
63
44
  key: "render",
64
45
  value: function render() {
65
- var _this2 = this;
66
46
  var containerClasses = classnames(_defineProperty({
67
- "input-container": true,
68
- "input-container-focus": this.state.focused
47
+ "input-container": true
69
48
  }, this.props.className, !!this.props.className));
70
49
  var prefix = this.findChild("prefix").map(function (el) {
71
50
  return /*#__PURE__*/React.cloneElement(el, {
@@ -74,13 +53,7 @@ var InputContainer = /*#__PURE__*/function (_React$Component) {
74
53
  });
75
54
  var input = this.findChild("input").map(function (el) {
76
55
  return /*#__PURE__*/React.cloneElement(el, {
77
- className: "input-container-input " + (el.props.className || ""),
78
- onBlur: function onBlur(ev) {
79
- return _this2.onInputBlur(ev, el.props.onBlur);
80
- },
81
- onFocus: function onFocus(ev) {
82
- return _this2.onInputFocus(ev, el.props.onFocus);
83
- }
56
+ className: "input-container-input " + (el.props.className || "")
84
57
  });
85
58
  });
86
59
  var suffix = this.findChild("suffix").map(function (el) {
@@ -12,7 +12,7 @@ div.input-container div.input-container {
12
12
  height: calc(2em - 2px);
13
13
  }
14
14
 
15
- div.input-container-focus {
15
+ div.input-container:focus-within {
16
16
  outline: var(--focus-outline);
17
17
  }
18
18
 
@@ -33,4 +33,5 @@ div.input-container .input-container-input {
33
33
 
34
34
  div.input-container .input-container-input {
35
35
  height: calc(2em - 2px)!important;
36
+ min-height: calc(2em - 2px)!important;
36
37
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwc2",
3
- "version": "2026.08.07",
3
+ "version": "2026.08.13",
4
4
  "description": "QGIS Web Client",
5
5
  "author": "Sourcepole AG",
6
6
  "license": "BSD-2-Clause",
@@ -15,13 +15,13 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
15
15
  import React from 'react';
16
16
  import { connect } from 'react-redux';
17
17
  import PropTypes from 'prop-types';
18
- import { refreshBookmarks } from '../actions/bookmark';
18
+ import { setBookmarks } from '../actions/bookmark';
19
19
  import { zoomToExtent, zoomToPoint } from "../actions/map";
20
20
  import BookmarkPanel from '../components/BookmarkPanel';
21
21
  import SideBar from '../components/SideBar';
22
22
  import LocaleUtils from "../utils/LocaleUtils";
23
23
  import MapUtils from "../utils/MapUtils";
24
- import { createBookmark, removeBookmark, renameBookmark, resolveBookmark, updateBookmark } from '../utils/PermaLinkUtils';
24
+ import { BookmarksInterface } from '../utils/PermaLinkUtils';
25
25
 
26
26
  /**
27
27
  * Allows managing user bookmarks which are storing the current view, including the location and zoom level.
@@ -39,32 +39,30 @@ var Bookmark = /*#__PURE__*/function (_React$Component) {
39
39
  }
40
40
  _this = _callSuper(this, Bookmark, [].concat(args));
41
41
  _defineProperty(_this, "translations", {
42
- add: LocaleUtils.tr("bookmark.add"),
43
42
  addfailed: LocaleUtils.tr("bookmark.addfailed"),
44
43
  lastUpdate: LocaleUtils.tr("bookmark.lastUpdate"),
45
- manage: LocaleUtils.tr("bookmark.manage"),
46
- newbookmark: LocaleUtils.tr("bookmark.newbookmark"),
47
- nobookmarks: LocaleUtils.tr("bookmark.nobookmarks"),
48
- notloggedin: LocaleUtils.tr("bookmark.notloggedin"),
44
+ title: LocaleUtils.tr("appmenu.items.Bookmark"),
45
+ "new": LocaleUtils.tr("bookmark.newbookmark"),
46
+ noitems: LocaleUtils.tr("bookmark.nobookmarks"),
49
47
  open: LocaleUtils.tr("bookmark.open"),
50
48
  openTab: LocaleUtils.tr("bookmark.openTab"),
51
49
  update: LocaleUtils.tr("bookmark.update"),
52
50
  zoomToExtent: LocaleUtils.tr("bookmark.zoomToExtent"),
53
51
  removefailed: LocaleUtils.tr("bookmark.removefailed"),
54
- savefailed: LocaleUtils.tr("bookmark.savefailed")
52
+ savefailed: LocaleUtils.tr("bookmark.savefailed"),
53
+ togglePublic: LocaleUtils.tr("bookmark.togglePublic"),
54
+ "public": LocaleUtils.tr("bookmark.public"),
55
+ confirmOverwrite: LocaleUtils.tr("bookmark.confirmOverwrite"),
56
+ confirmDelete: LocaleUtils.tr("bookmark.confirmDelete")
55
57
  });
56
58
  _defineProperty(_this, "renderBody", function () {
57
59
  return /*#__PURE__*/React.createElement(BookmarkPanel, {
60
+ bookmarkIface: BookmarksInterface,
58
61
  bookmarks: _this.props.bookmarks,
59
- onAdd: createBookmark,
60
62
  onOpen: _this.onOpen,
61
- onRefresh: _this.props.refreshBookmarks,
62
- onRemove: removeBookmark,
63
- onRename: renameBookmark,
64
- onUpdate: updateBookmark,
65
63
  onZoomToExtent: _this.zoomToBookmarkExtent,
66
64
  openOnClick: _this.props.openOnClick,
67
- showZoomToExtent: _this.props.mapCrs && _this.props.mapScales,
65
+ setList: _this.props.setBookmarks,
68
66
  translations: _this.translations
69
67
  });
70
68
  });
@@ -77,7 +75,7 @@ var Bookmark = /*#__PURE__*/function (_React$Component) {
77
75
  }
78
76
  });
79
77
  _defineProperty(_this, "zoomToBookmarkExtent", function (key) {
80
- resolveBookmark(key, function (params) {
78
+ BookmarksInterface.resolve(key, function (params) {
81
79
  if ('c' in params && 's' in params) {
82
80
  var _params$crs;
83
81
  var scale = parseFloat(params.s);
@@ -99,9 +97,17 @@ var Bookmark = /*#__PURE__*/function (_React$Component) {
99
97
  }
100
98
  _inherits(Bookmark, _React$Component);
101
99
  return _createClass(Bookmark, [{
100
+ key: "componentDidMount",
101
+ value: function componentDidMount() {
102
+ var _this2 = this;
103
+ BookmarksInterface.getList(function (bookmarks) {
104
+ _this2.props.setBookmarks(bookmarks);
105
+ });
106
+ }
107
+ }, {
102
108
  key: "render",
103
109
  value: function render() {
104
- var _this2 = this;
110
+ var _this3 = this;
105
111
  return /*#__PURE__*/React.createElement(SideBar, {
106
112
  icon: "bookmark",
107
113
  id: "Bookmark",
@@ -110,7 +116,7 @@ var Bookmark = /*#__PURE__*/function (_React$Component) {
110
116
  width: "20em"
111
117
  }, function () {
112
118
  return {
113
- body: _this2.renderBody()
119
+ body: _this3.renderBody()
114
120
  };
115
121
  });
116
122
  }
@@ -123,7 +129,7 @@ _defineProperty(Bookmark, "propTypes", {
123
129
  mapScales: PropTypes.array,
124
130
  /** Whether to directly open the bookmark on click / middle click, instead of showing dedicated open buttons. */
125
131
  openOnClick: PropTypes.bool,
126
- refreshBookmarks: PropTypes.func,
132
+ setBookmarks: PropTypes.func,
127
133
  /** The side of the application on which to display the sidebar. */
128
134
  side: PropTypes.string,
129
135
  zoomToExtent: PropTypes.func,
@@ -141,7 +147,7 @@ var selector = function selector(state) {
141
147
  };
142
148
  };
143
149
  export default connect(selector, {
144
- refreshBookmarks: refreshBookmarks,
150
+ setBookmarks: setBookmarks,
145
151
  zoomToExtent: zoomToExtent,
146
152
  zoomToPoint: zoomToPoint
147
153
  })(Bookmark);
@@ -46,7 +46,7 @@ import NumberInput from '../components/widgets/NumberInput';
46
46
  import CoordinatesUtils from '../utils/CoordinatesUtils';
47
47
  import LocaleUtils from '../utils/LocaleUtils';
48
48
  import MapUtils from '../utils/MapUtils';
49
- import { resolveVisibilityPreset } from "../utils/PermaLinkUtils";
49
+ import { VisibilityPresetsInterface } from "../utils/PermaLinkUtils";
50
50
  import './style/BottomBar.css';
51
51
 
52
52
  /**
@@ -97,7 +97,7 @@ var BottomBar = /*#__PURE__*/function (_React$Component) {
97
97
  _defineProperty(_this, "openBookmarkOrPreset", function (prefixedKey) {
98
98
  if (prefixedKey.startsWith("vp:")) {
99
99
  var key = prefixedKey.slice("vp:".length);
100
- resolveVisibilityPreset(key, function (preset) {
100
+ VisibilityPresetsInterface.resolve(key, function (preset) {
101
101
  if (preset) {
102
102
  _this.props.setThemeLayersVisibilityPreset(preset);
103
103
  }
@@ -47,6 +47,7 @@ import NumberInput from '../components/widgets/NumberInput';
47
47
  import ConfigUtils from '../utils/ConfigUtils';
48
48
  import CoordinatesUtils from '../utils/CoordinatesUtils';
49
49
  import IdentifyUtils from '../utils/IdentifyUtils';
50
+ import LayerUtils from '../utils/LayerUtils';
50
51
  import LocaleUtils from '../utils/LocaleUtils';
51
52
  import MeasureUtils from '../utils/MeasureUtils';
52
53
  import VectorLayerUtils from '../utils/VectorLayerUtils';
@@ -76,7 +77,8 @@ var Identify = /*#__PURE__*/function (_React$Component) {
76
77
  radiusUnits: _this.props.initialRadiusUnits,
77
78
  exitTaskOnResultsClose: null,
78
79
  filterGeom: null,
79
- filterGeomModifiers: {}
80
+ filterGeomModifiers: {},
81
+ importErrors: null
80
82
  });
81
83
  _defineProperty(_this, "queryPoint", function (prevProps) {
82
84
  if (_this.props.click.button !== 0 || _this.props.click === prevProps.click || (_this.props.click.features || []).find(function (feature) {
@@ -103,10 +105,6 @@ var Identify = /*#__PURE__*/function (_React$Component) {
103
105
  var identifyResults = _this.props.click.modifiers.ctrl !== true && !appendResultsByDefault ? {} : (_state$identifyResult = state.identifyResults) !== null && _state$identifyResult !== void 0 ? _state$identifyResult : {};
104
106
  var params = _objectSpread({}, _this.props.params);
105
107
  var resultDisplayMode = _this.props.taskEnabled ? (_this$props$taskResul = _this.props.taskResultDisplayMode) !== null && _this$props$taskResul !== void 0 ? _this$props$taskResul : _this.props.resultDisplayMode : _this.props.resultDisplayMode;
106
- if (resultDisplayMode === "table") {
107
- params.with_htmlcontent = false;
108
- params.with_maptip = false;
109
- }
110
108
  var queryableLayers = [];
111
109
  queryableLayers = IdentifyUtils.getQueryLayers(_this.props.layers, _this.props.map);
112
110
  queryableLayers.forEach(function (l) {
@@ -171,10 +169,6 @@ var Identify = /*#__PURE__*/function (_React$Component) {
171
169
  var pendingRequests = 0;
172
170
  var params = _objectSpread({}, _this.props.params);
173
171
  var resultDisplayMode = _this.props.taskEnabled ? (_this$props$taskResul2 = _this.props.taskResultDisplayMode) !== null && _this$props$taskResul2 !== void 0 ? _this$props$taskResul2 : _this.props.resultDisplayMode : _this.props.resultDisplayMode;
174
- if (resultDisplayMode === "table") {
175
- params.with_htmlcontent = false;
176
- params.with_maptip = false;
177
- }
178
172
  if (_this.props.params.region_feature_count) {
179
173
  params.feature_count = _this.props.params.region_feature_count;
180
174
  delete params.region_feature_count;
@@ -254,6 +248,7 @@ var Identify = /*#__PURE__*/function (_React$Component) {
254
248
  identifyResults: identifyResults
255
249
  };
256
250
  });
251
+ return newResults;
257
252
  });
258
253
  _defineProperty(_this, "onShow", function (mode, data) {
259
254
  _this.setState({
@@ -384,10 +379,13 @@ var Identify = /*#__PURE__*/function (_React$Component) {
384
379
  }
385
380
  });
386
381
  _defineProperty(_this, "export", function () {
387
- var data = JSON.stringify(_this.state.identifyResults, null, ' ');
388
- FileSaver.saveAs(new Blob([data], {
389
- type: 'application/json'
390
- }), 'results.json');
382
+ if (_this.viewerRef) {
383
+ var results = _this.viewerRef.serializeResults();
384
+ var data = JSON.stringify(results, null, ' ');
385
+ FileSaver.saveAs(new Blob([data], {
386
+ type: 'application/json'
387
+ }), 'results.json');
388
+ }
391
389
  });
392
390
  _defineProperty(_this, "import", function () {
393
391
  _this.fileinput.click();
@@ -397,27 +395,94 @@ var Identify = /*#__PURE__*/function (_React$Component) {
397
395
  reader.readAsText(ev.target.files[0]);
398
396
  reader.onload = function () {
399
397
  try {
400
- var identifyResults = JSON.parse(reader.result);
401
- _this.setState({
402
- identifyResults: identifyResults,
403
- pendingRequests: 0
404
- });
398
+ var _this$props$taskResul3;
399
+ var resultDisplayMode = _this.props.taskEnabled ? (_this$props$taskResul3 = _this.props.taskResultDisplayMode) !== null && _this$props$taskResul3 !== void 0 ? _this$props$taskResul3 : _this.props.resultDisplayMode : _this.props.resultDisplayMode;
400
+ _this.deserializeResults(JSON.parse(reader.result), resultDisplayMode);
405
401
  } catch (_unused2) {
406
402
  /* eslint-disable-next-line no-alert */
407
403
  alert(LocaleUtils.tr("common.dataloadfailed"));
408
404
  }
409
405
  };
410
406
  });
407
+ _defineProperty(_this, "deserializeResults", function (identifyResults, resultDisplayMode) {
408
+ var pendingRequests = 0;
409
+ var importErrors = {};
410
+ Object.entries(identifyResults).forEach(function (_ref5) {
411
+ var _ref6 = _slicedToArray(_ref5, 2),
412
+ layerid = _ref6[0],
413
+ layerresults = _ref6[1];
414
+ if (layerresults.key && layerresults.values) {
415
+ delete identifyResults[layerid]; // Features will be re-queried
416
+ var _layerid$split = layerid.split("#", 2),
417
+ _layerid$split2 = _slicedToArray(_layerid$split, 2),
418
+ layerUrl = _layerid$split2[0],
419
+ layerName = _layerid$split2[1];
420
+ var match = LayerUtils.searchLayer(_this.props.layers, 'url', layerUrl, 'name', layerName);
421
+ if (match) {
422
+ var values = layerresults.values.map(function (x) {
423
+ return typeof x === "string" ? "\"".concat(x, "\"") : x;
424
+ }).join(" , ");
425
+ var filter = {
426
+ filter: "".concat(layerName, ":\"").concat(layerresults.key, "\" IN ( ").concat(values, " )")
427
+ };
428
+ var request = IdentifyUtils.buildFilterRequest(match.layer, layerName, undefined, _this.props.map, filter);
429
+ ++pendingRequests;
430
+ IdentifyUtils.sendRequest(request, function (response) {
431
+ _this.setState(function (state2) {
432
+ return {
433
+ pendingRequests: state2.pendingRequests - 1
434
+ };
435
+ });
436
+ if (response) {
437
+ var results = _this.parseResult(response, match.layer, request.params.info_format, [0, 0], false);
438
+ var restoredkeys = new Set(results[layerName].map(function (f) {
439
+ return String(f.id);
440
+ }));
441
+ var missing = layerresults.values.filter(function (x) {
442
+ return !restoredkeys.has(String(x));
443
+ });
444
+ if (missing.length > 0) {
445
+ _this.setState(function (state) {
446
+ return {
447
+ importErrors: _objectSpread(_objectSpread({}, state.importErrors), {}, _defineProperty({}, layerid, {
448
+ key: layerresults.key,
449
+ missing: missing
450
+ }))
451
+ };
452
+ });
453
+ }
454
+ } else {
455
+ _this.setState(function (state) {
456
+ return {
457
+ importErrors: _objectSpread(_objectSpread({}, state.importErrors), {}, _defineProperty({}, layerid, true))
458
+ };
459
+ });
460
+ }
461
+ });
462
+ } else {
463
+ importErrors[layerid] = true;
464
+ }
465
+ }
466
+ });
467
+ _this.setState({
468
+ identifyResults: identifyResults,
469
+ pendingRequests: pendingRequests,
470
+ importErrors: importErrors,
471
+ currentResultDisplayMode: resultDisplayMode
472
+ });
473
+ });
411
474
  _this.fileinput = document.createElement("input");
412
475
  _this.fileinput.type = "file";
413
476
  _this.fileinput.accept = "application/json";
414
477
  _this.fileinput.addEventListener("change", _this.fileSelected);
478
+ _this.viewerRef = null;
415
479
  return _this;
416
480
  }
417
481
  _inherits(Identify, _React$Component);
418
482
  return _createClass(Identify, [{
419
483
  key: "componentDidUpdate",
420
484
  value: function componentDidUpdate(prevProps, prevState) {
485
+ var _this2 = this;
421
486
  if (this.props.enabled && this.props.theme && !prevProps.theme) {
422
487
  var startupParams = this.props.startupParams;
423
488
  var haveIc = ["1", "true"].includes((startupParams.ic || "").toLowerCase());
@@ -428,7 +493,7 @@ var Identify = /*#__PURE__*/function (_React$Component) {
428
493
  var mapCrs = this.props.theme.mapCrs;
429
494
  this.identifyPoint(CoordinatesUtils.reproject(c, startupParams.crs || mapCrs, mapCrs));
430
495
  } else if (this.props.startupState.identifyresultstate) {
431
- this.setState(_objectSpread({}, this.props.startupState.identifyresultstate));
496
+ this.deserializeResults(_objectSpread({}, this.props.startupState.identifyresultstate.identifyResults), this.props.startupState.identifyresultstate.currentResultDisplayMode);
432
497
  }
433
498
  } else if (this.props.theme !== prevProps.theme) {
434
499
  this.clearResults();
@@ -482,16 +547,38 @@ var Identify = /*#__PURE__*/function (_React$Component) {
482
547
  if (isEmpty(this.state.identifyResults) && this.props.onlyShowDialogWithResults) {
483
548
  this.clearResults();
484
549
  }
550
+ if (!isEmpty(this.state.importErrors)) {
551
+ var errMsg = Object.entries(this.state.importErrors).map(function (_ref7) {
552
+ var _match$sublayer$title, _match$sublayer;
553
+ var _ref8 = _slicedToArray(_ref7, 2),
554
+ layerid = _ref8[0],
555
+ errors = _ref8[1];
556
+ var _layerid$split3 = layerid.split("#", 2),
557
+ _layerid$split4 = _slicedToArray(_layerid$split3, 2),
558
+ layerUrl = _layerid$split4[0],
559
+ layerName = _layerid$split4[1];
560
+ var match = LayerUtils.searchLayer(_this2.props.layers, 'url', layerUrl, 'name', layerName);
561
+ var layertitle = (_match$sublayer$title = match === null || match === void 0 || (_match$sublayer = match.sublayer) === null || _match$sublayer === void 0 ? void 0 : _match$sublayer.title) !== null && _match$sublayer$title !== void 0 ? _match$sublayer$title : layerName;
562
+ if (errors === true) {
563
+ return "- ".concat(layertitle, ": ").concat(LocaleUtils.tr("identify.missinglayer"));
564
+ } else {
565
+ return "- ".concat(layertitle, ": ").concat(LocaleUtils.tr("identify.featuresmissing", errors.missing.length, "".concat(errors.key, " = {").concat(errors.missing.join(","), "}")));
566
+ }
567
+ }).join("\n");
568
+ // eslint-disable-next-line no-alert
569
+ alert(LocaleUtils.tr("identify.importerrors", errMsg));
570
+ }
485
571
  this.setState({
486
572
  filterGeom: null,
487
- filterGeomModifiers: {}
573
+ filterGeomModifiers: {},
574
+ importErrors: null
488
575
  });
489
576
  }
490
577
  }
491
578
  }, {
492
579
  key: "render",
493
580
  value: function render() {
494
- var _this2 = this;
581
+ var _this3 = this;
495
582
  var resultWindow = null;
496
583
  if (this.props.onlyShowDialogWithResults && isEmpty(this.state.identifyResults)) {
497
584
  // pass
@@ -523,6 +610,9 @@ var Identify = /*#__PURE__*/function (_React$Component) {
523
610
  highlightAllResults: this.props.highlightAllResults,
524
611
  identifyResults: this.state.identifyResults,
525
612
  iframeDialogsInitiallyDocked: this.props.iframeDialogsInitiallyDocked,
613
+ innerRef: function innerRef(el) {
614
+ _this3.viewerRef = el;
615
+ },
526
616
  longAttributesDisplay: this.props.longAttributesDisplay,
527
617
  replaceImageUrls: this.props.replaceImageUrls,
528
618
  resultDisplayMode: this.state.currentResultDisplayMode,
@@ -561,14 +651,14 @@ var Identify = /*#__PURE__*/function (_React$Component) {
561
651
  task: "Identify"
562
652
  }, function () {
563
653
  return {
564
- body: _this2.renderBody()
654
+ body: _this3.renderBody()
565
655
  };
566
656
  }), ["Region", "Rectangle", "Radius", "Circle"].includes(this.state.mode) ? /*#__PURE__*/React.createElement(MapSelection, {
567
657
  active: this.state.mode !== "Radius",
568
658
  geomType: geomTypeMap[this.state.mode],
569
659
  geometry: this.state.filterGeom,
570
660
  geometryChanged: function geometryChanged(geom, mod) {
571
- return _this2.setState({
661
+ return _this3.setState({
572
662
  filterGeom: geom,
573
663
  filterGeomModifiers: mod
574
664
  });
@@ -41,7 +41,6 @@ import isEqual from 'lodash.isequal';
41
41
  import PropTypes from 'prop-types';
42
42
  import { v4 as uuidv4 } from 'uuid';
43
43
  import { LayerRole, setFilter } from '../actions/layers';
44
- import { setPermalinkParameters } from '../actions/localConfig';
45
44
  import { setCurrentTask } from '../actions/task';
46
45
  import Icon from '../components/Icon';
47
46
  import MapButton from '../components/MapButton';
@@ -58,6 +57,7 @@ import DataServiceExprUtils from '../utils/DataServiceExprUtils';
58
57
  import LayerUtils from '../utils/LayerUtils';
59
58
  import LocaleUtils from '../utils/LocaleUtils';
60
59
  import MiscUtils from '../utils/MiscUtils';
60
+ import { registerPermalinkDataStoreHook, unregisterPermalinkDataStoreHook } from '../utils/PermaLinkUtils';
61
61
  import './style/MapFilter.css';
62
62
 
63
63
  /**
@@ -228,37 +228,43 @@ var MapFilter = /*#__PURE__*/function (_React$Component) {
228
228
  });
229
229
  });
230
230
  }
231
- var permalinkState = Object.entries(_this.state.filters).reduce(function (res, _ref5) {
232
- var _ref6 = _slicedToArray(_ref5, 2),
233
- key = _ref6[0],
234
- value = _ref6[1];
235
- if (value.active) {
236
- return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, key, value.values));
237
- } else {
238
- return res;
239
- }
240
- }, {});
241
- if (_this.state.geomFilter.geom) {
242
- permalinkState.__geomfilter = _this.state.geomFilter.geom.coordinates;
243
- }
244
- permalinkState.__custom = Object.values(_this.state.customFilters).map(function (entry) {
245
- if (!entry.active) {
246
- return null;
247
- }
248
- var expr = null;
249
- try {
250
- expr = JSON.parse(entry.expr);
251
- } catch (_unused2) {
252
- return null;
231
+ });
232
+ _defineProperty(_this, "serializeMapFilter", function () {
233
+ return new Promise(function (resolve) {
234
+ var permalinkState = Object.entries(_this.state.filters).reduce(function (res, _ref5) {
235
+ var _ref6 = _slicedToArray(_ref5, 2),
236
+ key = _ref6[0],
237
+ value = _ref6[1];
238
+ if (value.active) {
239
+ return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, key, value.values));
240
+ } else {
241
+ return res;
242
+ }
243
+ }, {});
244
+ if (_this.state.geomFilter.geom) {
245
+ permalinkState.__geomfilter = _this.state.geomFilter.geom.coordinates;
253
246
  }
254
- return {
255
- title: entry.title,
256
- layer: entry.layer,
257
- expr: expr
258
- };
259
- }).filter(Boolean);
260
- _this.props.setPermalinkParameters({
261
- f: JSON.stringify(permalinkState)
247
+ permalinkState.__custom = Object.values(_this.state.customFilters).map(function (entry) {
248
+ if (!entry.active) {
249
+ return null;
250
+ }
251
+ var expr = null;
252
+ try {
253
+ expr = JSON.parse(entry.expr);
254
+ } catch (_unused2) {
255
+ return null;
256
+ }
257
+ return {
258
+ title: entry.title,
259
+ layer: entry.layer,
260
+ expr: expr
261
+ };
262
+ }).filter(Boolean);
263
+ resolve({
264
+ query: {
265
+ f: JSON.stringify(permalinkState)
266
+ }
267
+ });
262
268
  });
263
269
  });
264
270
  _defineProperty(_this, "buildTimeFilter", function (layer, filters, wmsName) {
@@ -672,6 +678,16 @@ var MapFilter = /*#__PURE__*/function (_React$Component) {
672
678
  }
673
679
  _inherits(MapFilter, _React$Component);
674
680
  return _createClass(MapFilter, [{
681
+ key: "componentDidMount",
682
+ value: function componentDidMount() {
683
+ registerPermalinkDataStoreHook("mapfilter", this.serializeMapFilter);
684
+ }
685
+ }, {
686
+ key: "componentWillUnmount",
687
+ value: function componentWillUnmount() {
688
+ unregisterPermalinkDataStoreHook("mapfilter");
689
+ }
690
+ }, {
675
691
  key: "componentDidUpdate",
676
692
  value: function componentDidUpdate(prevProps, prevState) {
677
693
  var _this2 = this;
@@ -829,7 +845,6 @@ _defineProperty(MapFilter, "propTypes", {
829
845
  position: PropTypes.number,
830
846
  setCurrentTask: PropTypes.func,
831
847
  setFilter: PropTypes.func,
832
- setPermalinkParameters: PropTypes.func,
833
848
  /** The side of the application on which to display the sidebar. */
834
849
  side: PropTypes.string,
835
850
  startupParams: PropTypes.object,
@@ -854,6 +869,5 @@ export default connect(function (state) {
854
869
  };
855
870
  }, {
856
871
  setFilter: setFilter,
857
- setCurrentTask: setCurrentTask,
858
- setPermalinkParameters: setPermalinkParameters
872
+ setCurrentTask: setCurrentTask
859
873
  })(MapFilter);