qwc2 2026.5.28 → 2026.6.4

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 (48) hide show
  1. package/components/AttributeForm.js +20 -51
  2. package/components/AutoEditForm.js +12 -1
  3. package/components/QtDesignerForm.js +18 -1
  4. package/components/StandardApp.js +2 -2
  5. package/components/ThemeList.js +6 -1
  6. package/components/map3d/Map3D.js +10 -6
  7. package/components/map3d/utils/FirstPersonControls3D.js +14 -12
  8. package/components/style/App.css +4 -0
  9. package/components/style/SearchBox.css +0 -4
  10. package/components/style/ThemeList.css +8 -0
  11. package/components/widgets/MenuButton.js +5 -1
  12. package/components/widgets/NumberInput.js +1 -1
  13. package/components/widgets/PopupMenu.js +12 -17
  14. package/components/widgets/style/MenuButton.css +5 -1
  15. package/package.json +1 -1
  16. package/plugins/BackgroundSwitcher.js +1 -1
  17. package/plugins/Bookmark.js +7 -2
  18. package/plugins/Editing.js +2 -1
  19. package/plugins/SensorThingsTool.js +68 -8
  20. package/plugins/map3d/BottomBar3D.js +90 -13
  21. package/plugins/map3d/LayerTree3D.js +10 -3
  22. package/plugins/map3d/TopBar3D.js +1 -1
  23. package/plugins/map3d/style/BottomBar3D.css +6 -0
  24. package/plugins/style/OverviewMap.css +3 -0
  25. package/plugins/style/SensorThingsTool.css +17 -3
  26. package/static/translations/bg-BG.json +4 -0
  27. package/static/translations/ca-ES.json +4 -0
  28. package/static/translations/cs-CZ.json +4 -0
  29. package/static/translations/de-CH.json +4 -0
  30. package/static/translations/de-DE.json +4 -0
  31. package/static/translations/en-US.json +4 -0
  32. package/static/translations/es-ES.json +4 -0
  33. package/static/translations/fi-FI.json +4 -0
  34. package/static/translations/fr-FR.json +5 -1
  35. package/static/translations/hu-HU.json +4 -0
  36. package/static/translations/it-IT.json +4 -0
  37. package/static/translations/ja-JP.json +4 -0
  38. package/static/translations/nl-NL.json +4 -0
  39. package/static/translations/no-NO.json +4 -0
  40. package/static/translations/pl-PL.json +4 -0
  41. package/static/translations/pt-BR.json +4 -0
  42. package/static/translations/pt-PT.json +4 -0
  43. package/static/translations/ro-RO.json +4 -0
  44. package/static/translations/ru-RU.json +4 -0
  45. package/static/translations/sv-SE.json +4 -0
  46. package/static/translations/tr-TR.json +4 -0
  47. package/static/translations/tsconfig.json +4 -0
  48. package/static/translations/uk-UA.json +4 -0
@@ -76,7 +76,7 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
76
76
  label: _this.state.formValid ? LocaleUtils.tr("editing.commit") : LocaleUtils.tr("editing.invalidform"),
77
77
  extraClasses: _this.state.formValid ? "button-accept" : "button-warning",
78
78
  type: "submit",
79
- disabled: !_this.state.formValid || captchaPending
79
+ disabled: captchaPending
80
80
  }, {
81
81
  key: 'Discard',
82
82
  icon: 'remove',
@@ -167,11 +167,10 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
167
167
  }, readOnlyMsg) : null, /*#__PURE__*/React.createElement("form", {
168
168
  action: "",
169
169
  className: "attrib-form-parent-form",
170
- onChange: function onChange(ev) {
171
- return _this.formChanged(ev);
172
- },
173
170
  onSubmit: _this.onSubmit,
174
- ref: _this.setupChangedObserver
171
+ ref: function ref(el) {
172
+ _this.form = el;
173
+ }
175
174
  }, editConfig.form ? /*#__PURE__*/React.createElement(QtDesignerForm, {
176
175
  addRelationRecord: _this.addRelationRecord,
177
176
  editConfig: editConfig,
@@ -218,7 +217,6 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
218
217
  feature: newFeature,
219
218
  changed: true
220
219
  });
221
- _this.validateFieldConstraints(newFeature);
222
220
  });
223
221
  _defineProperty(_this, "setRelationTables", function (relationTables) {
224
222
  _this.setState({
@@ -419,8 +417,6 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
419
417
  changed: false
420
418
  });
421
419
  });
422
- // Re-validate feature field constraints
423
- _this.validateFieldConstraints(feature);
424
420
  } else {
425
421
  _this.props.setEditContext(_this.props.editContext.id, {
426
422
  feature: feature,
@@ -443,37 +439,7 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
443
439
  }
444
440
  }
445
441
  });
446
- _defineProperty(_this, "setupChangedObserver", function (form) {
447
- _this.form = form;
448
- if (form) {
449
- form.observer = new MutationObserver(function () {
450
- _this.setState({
451
- formValid: form.checkValidity()
452
- });
453
- });
454
- form.observer.observe(form, {
455
- subtree: true,
456
- childList: true,
457
- attributes: true
458
- });
459
- }
460
- });
461
- _defineProperty(_this, "formChanged", function (ev) {
462
- var _ev$target;
463
- var form = ev.currentTarget;
464
- if ((_ev$target = ev.target) !== null && _ev$target !== void 0 && _ev$target.setCustomValidity) {
465
- ev.target.setCustomValidity("");
466
- }
467
- if (form) {
468
- _this.setState({
469
- formValid: form.checkValidity()
470
- });
471
- _this.props.setEditContext(_this.props.editContext.id, {
472
- changed: true
473
- });
474
- }
475
- });
476
- _defineProperty(_this, "validateFieldConstraints", function (feature) {
442
+ _defineProperty(_this, "validateForm", function (feature) {
477
443
  var validCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
478
444
  var invalidCallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
479
445
  var constraintExpressions = _this.props.editContext.editConfig.fields.reduce(function (res, cur) {
@@ -487,7 +453,7 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
487
453
  return res;
488
454
  }, []);
489
455
  parseExpressionsAsync(constraintExpressions, feature, _this.props.editContext.editConfig, _this.props.iface, _this.props.editContext.mapPrefix, _this.props.map.projection, false).then(function (result) {
490
- var valid = true;
456
+ var valid = _this.form.checkValidity();
491
457
  var reasons = [];
492
458
  Object.entries(result).forEach(function (_ref5) {
493
459
  var _ref6 = _slicedToArray(_ref5, 2),
@@ -508,23 +474,27 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
508
474
  }
509
475
  }
510
476
  });
477
+ Array.from(_this.form.elements).filter(function (el) {
478
+ return el.willValidate && el.required && el.validity.valueMissing;
479
+ }).forEach(function (el) {
480
+ reasons.push("".concat(el.name, ": ").concat(LocaleUtils.tr("editing.emptyvalue")));
481
+ });
511
482
  if (!valid) {
512
483
  _this.setState({
513
484
  formValid: false
514
485
  });
515
- if (invalidCallback) {
516
- invalidCallback(reasons);
517
- }
486
+ invalidCallback === null || invalidCallback === void 0 || invalidCallback(reasons);
518
487
  } else {
519
- if (validCallback) {
520
- validCallback();
521
- }
488
+ _this.setState({
489
+ formValid: true
490
+ });
491
+ validCallback === null || validCallback === void 0 || validCallback();
522
492
  }
523
493
  });
524
494
  });
525
495
  _defineProperty(_this, "onSubmit", function (ev) {
526
496
  ev.preventDefault();
527
- _this.validateFieldConstraints(_this.props.editContext.feature, _this.doSubmit, function (reasons) {
497
+ _this.validateForm(_this.props.editContext.feature, _this.doSubmit, function (reasons) {
528
498
  /* eslint-disable-next-line */
529
499
  alert(LocaleUtils.tr("editing.contraintviolation") + ":\n" + reasons.join("\n"));
530
500
  });
@@ -826,8 +796,6 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
826
796
  changed: false
827
797
  });
828
798
  });
829
- // Re-validate feature field constraints
830
- _this.validateFieldConstraints(result);
831
799
  } else {
832
800
  _this.props.setEditContext(_this.props.editContext.id, {
833
801
  action: 'Pick',
@@ -931,8 +899,9 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
931
899
  feature: newFeature
932
900
  });
933
901
  });
934
- // Re-validate feature field constraints
935
- this.validateFieldConstraints(this.props.editContext.feature);
902
+ }
903
+ if (this.props.editContext.feature !== prevProps.editContext.feature) {
904
+ this.validateForm(this.props.editContext.feature);
936
905
  }
937
906
  }
938
907
  }, {
@@ -1,5 +1,11 @@
1
1
  var _excluded = ["multiline"];
2
2
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
3
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
4
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
5
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
6
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
7
+ function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t["return"] && (u = t["return"](), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
8
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
3
9
  function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
4
10
  function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
5
11
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
@@ -75,12 +81,17 @@ var AutoEditForm = /*#__PURE__*/function (_React$Component) {
75
81
  })), field.name);
76
82
  }
77
83
  } else if (constraints.values || constraints.keyvalrel) {
84
+ var _constraints$keyvalre = constraints.keyvalrel.split('.', 2),
85
+ _constraints$keyvalre2 = _slicedToArray(_constraints$keyvalre, 2),
86
+ mapPrefix = _constraints$keyvalre2[0],
87
+ keyvalrel = _constraints$keyvalre2[1];
78
88
  input = /*#__PURE__*/React.createElement("span", {
79
89
  className: "input-frame"
80
90
  }, /*#__PURE__*/React.createElement(EditComboField, {
81
91
  editIface: _this.props.iface,
82
92
  fieldId: field.id,
83
- keyvalrel: constraints.keyvalrel,
93
+ keyvalrel: keyvalrel,
94
+ mapPrefix: mapPrefix,
84
95
  name: field.id,
85
96
  readOnly: readOnly,
86
97
  required: constraints.required,
@@ -273,7 +273,24 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
273
273
  } else {
274
274
  elname = nametransform(widget.name);
275
275
  }
276
- if (widget["class"] === "QLabel") {
276
+ if (widget.component) {
277
+ return /*#__PURE__*/React.createElement(widget.component, {
278
+ addRelationRecord: _this.props.addRelationRecord,
279
+ editConfigs: _this.props.editConfigs,
280
+ feature: _this.props.feature,
281
+ inputConstraints: inputConstraints,
282
+ mapPrefix: _this.props.mapPrefix,
283
+ name: elname,
284
+ onChange: function onChange(val) {
285
+ return updateField(widget.name, val);
286
+ },
287
+ readOnly: _this.props.readOnly,
288
+ removeRelationRecord: _this.props.removeRelationRecord,
289
+ reorderRelationRecord: _this.props.reorderRelationRecord,
290
+ updateRelationField: _this.props.updateRelationField,
291
+ widget: widget
292
+ });
293
+ } else if (widget["class"] === "QLabel") {
277
294
  if (widget.name.startsWith("img__")) {
278
295
  var _feature$properties$w2, _feature$properties2;
279
296
  value = (_feature$properties$w2 = (_feature$properties2 = feature.properties) === null || _feature$properties2 === void 0 ? void 0 : _feature$properties2[widget.name.split("__")[1]]) !== null && _feature$properties$w2 !== void 0 ? _feature$properties$w2 : widget.property.text;
@@ -265,7 +265,7 @@ var StandardApp = /*#__PURE__*/function (_React$Component2) {
265
265
  return res;
266
266
  }, {});
267
267
  ConfigUtils.loadConfiguration(configParams).then(function (config) {
268
- var _window$QWC2PluginCon, _window$QWC2PluginCon2, _window$QWC2PluginCon3, _ref5, _this2$props$appConfi, _this2$props$appConfi2, _this2$props$appConfi3;
268
+ var _window$QWC2PluginCon, _window$QWC2PluginCon2, _window$QWC2PluginCon3, _ref5, _ref6, _this2$props$appConfi, _this2$props$appConfi2, _this2$props$appConfi3;
269
269
  // Merge common config into mobile/desktop config, merge config from appConfig
270
270
  var renameTaskButtons = function renameTaskButtons(res, entry) {
271
271
  var _entry$cfg$task, _entry$cfg;
@@ -318,7 +318,7 @@ var StandardApp = /*#__PURE__*/function (_React$Component2) {
318
318
  });
319
319
 
320
320
  // Load locale
321
- var lang = (_ref5 = (_this2$props$appConfi = (_this2$props$appConfi2 = (_this2$props$appConfi3 = _this2.props.appConfig).getDefaultLocale) === null || _this2$props$appConfi2 === void 0 ? void 0 : _this2$props$appConfi2.call(_this2$props$appConfi3)) !== null && _this2$props$appConfi !== void 0 ? _this2$props$appConfi : initialParams.lang) !== null && _ref5 !== void 0 ? _ref5 : navigator.language;
321
+ var lang = (_ref5 = (_ref6 = (_this2$props$appConfi = (_this2$props$appConfi2 = (_this2$props$appConfi3 = _this2.props.appConfig).getDefaultLocale) === null || _this2$props$appConfi2 === void 0 ? void 0 : _this2$props$appConfi2.call(_this2$props$appConfi3)) !== null && _this2$props$appConfi !== void 0 ? _this2$props$appConfi : initialParams.lang) !== null && _ref6 !== void 0 ? _ref6 : config.defaultLocale) !== null && _ref5 !== void 0 ? _ref5 : navigator.language;
322
322
  LocaleUtils.loadLocale(lang, _this2.props.appConfig.defaultLocaleData).then(function (localeData) {
323
323
  StandardApp.store.dispatch(changeLocale(localeData, _this2.props.appConfig.defaultLocaleData));
324
324
  _this2.setState({
@@ -216,7 +216,12 @@ var ThemeList = /*#__PURE__*/function (_React$Component) {
216
216
  className: "theme-item-restricted-overlay"
217
217
  }, /*#__PURE__*/React.createElement(Icon, {
218
218
  icon: "lock"
219
- })), isEmpty(matches) ? null : /*#__PURE__*/React.createElement("div", {
219
+ })), item.hasRestrictedContent ? /*#__PURE__*/React.createElement("div", {
220
+ className: "theme-item-restricted-content",
221
+ title: LocaleUtils.tr("themeswitcher.restrictedcontent")
222
+ }, /*#__PURE__*/React.createElement(Icon, {
223
+ icon: "lock"
224
+ })) : null, isEmpty(matches) ? null : /*#__PURE__*/React.createElement("div", {
220
225
  className: "theme-item-filterinfo-overlay"
221
226
  }, matches.map(function (match) {
222
227
  return /*#__PURE__*/React.createElement("div", {
@@ -586,7 +586,9 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
586
586
  objectTree[child] = _objectSpread(_objectSpread({}, objectTree[child]), {}, {
587
587
  visibility: false
588
588
  });
589
- _this2.objectMap[child].visible = false;
589
+ if (_this2.objectMap[child]) {
590
+ _this2.objectMap[child].visible = false;
591
+ }
590
592
  }
591
593
  });
592
594
  }
@@ -625,10 +627,12 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
625
627
  }
626
628
  var child = objectTree[nodeId];
627
629
  var newVisible = visibility && child.visibility && child.opacity > 0;
628
- var changed = newVisible !== _this2.objectMap[child.objectId].visible;
629
- _this2.objectMap[child.objectId].visible = newVisible;
630
- if (changed) {
631
- _this2.instance.notifyChange(_this2.objectMap[child.objectId]);
630
+ if (_this2.objectMap[child.objectId]) {
631
+ var changed = newVisible !== _this2.objectMap[child.objectId].visible;
632
+ _this2.objectMap[child.objectId].visible = newVisible;
633
+ if (changed) {
634
+ _this2.instance.notifyChange(_this2.objectMap[child.objectId]);
635
+ }
632
636
  }
633
637
  }
634
638
  });
@@ -803,7 +807,7 @@ var Map3D = /*#__PURE__*/function (_React$Component2) {
803
807
  // Collect baselayers
804
808
  var externalLayers = {};
805
809
  var baseLayers = ThemeUtils.createThemeBackgroundLayers(_this2.props.theme.map3d.basemaps || [], _this2.props.themes, null, externalLayers);
806
- baseLayers.push({
810
+ baseLayers.unshift({
807
811
  type: "blank",
808
812
  name: "",
809
813
  title: LocaleUtils.tr("bgswitcher.nobg")
@@ -347,19 +347,21 @@ var FirstPersonControls3D = /*#__PURE__*/function (_Controls) {
347
347
  this.target.y += step * dir.y;
348
348
 
349
349
  // Project overstep onto wall
350
- var tangent = new Vector2(-inter.normal.y, inter.normal.x).normalize();
351
- var slidestep = tangent.dot(dir) * overstep;
352
- if (slidestep < 0) {
353
- tangent.negate();
354
- slidestep *= -1;
350
+ if (inter.normal) {
351
+ var tangent = new Vector2(-inter.normal.y, inter.normal.x).normalize();
352
+ var slidestep = tangent.dot(dir) * overstep;
353
+ if (slidestep < 0) {
354
+ tangent.negate();
355
+ slidestep *= -1;
356
+ }
357
+ raycaster.set(this.target, new Vector3(tangent.x, tangent.y, 0));
358
+ var slideInter = raycaster.intersectObjects(this.sceneContext.collisionObjects, true)[0];
359
+ if (slideInter && slideInter.distance - wallBuffer < slidestep) {
360
+ slidestep = slideInter.distance - wallBuffer;
361
+ }
362
+ this.target.x += slidestep * tangent.x;
363
+ this.target.y += slidestep * tangent.y;
355
364
  }
356
- raycaster.set(this.target, new Vector3(tangent.x, tangent.y, 0));
357
- var slideInter = raycaster.intersectObjects(this.sceneContext.collisionObjects, true)[0];
358
- if (slideInter && slideInter.distance - wallBuffer < slidestep) {
359
- slidestep = slideInter.distance - wallBuffer;
360
- }
361
- this.target.x += slidestep * tangent.x;
362
- this.target.y += slidestep * tangent.y;
363
365
  } else {
364
366
  this.target.x += step * dir.x;
365
367
  this.target.y += step * dir.y;
@@ -149,6 +149,10 @@ button.button-reject {
149
149
  background-color: rgb(255,127,127);
150
150
  }
151
151
 
152
+ button.button-warning:not(:disabled):hover {
153
+ background-color: #f5ce74;
154
+ }
155
+
152
156
  button.button-accept:not(:disabled):hover {
153
157
  background-color: rgb(127,225,127);
154
158
  }
@@ -1,10 +1,6 @@
1
1
  div.SearchBox {
2
2
  position: relative;
3
3
  display: flex;
4
- height: 2em;
5
- background-color: var(--input-bg-color);
6
- color: var(--text-color);
7
- border-radius: var(--border-radius);
8
4
  }
9
5
 
10
6
  div.searchbox-field {
@@ -200,3 +200,11 @@ div.ThemeList div.theme-item-restricted-overlay {
200
200
  justify-content: center;
201
201
  font-size: 400%;
202
202
  }
203
+
204
+ div.ThemeList div.theme-item-restricted-content {
205
+ position: absolute;
206
+ right: 0;
207
+ top: 0;
208
+ opacity: .5;
209
+ padding: 0.25em;
210
+ }
@@ -85,7 +85,9 @@ var MenuButton = /*#__PURE__*/function (_React$Component) {
85
85
  buttonContents = [this.props.menuIcon ? /*#__PURE__*/React.createElement(Icon, {
86
86
  icon: this.props.menuIcon,
87
87
  key: "icon"
88
- }) : null, this.props.menuLabel ? /*#__PURE__*/React.createElement("span", null, this.props.menuLabel) : null];
88
+ }) : null, this.props.menuLabel ? /*#__PURE__*/React.createElement("span", {
89
+ key: "label"
90
+ }, this.props.menuLabel) : null];
89
91
  } else {
90
92
  buttonContents = children.filter(function (child) {
91
93
  return child.props.value === _this2.state.selected;
@@ -123,6 +125,7 @@ var MenuButton = /*#__PURE__*/function (_React$Component) {
123
125
  })), this.props.tooltip ? /*#__PURE__*/React.createElement("span", {
124
126
  className: "menubutton-tooltip " + ("menubutton-tooltip-" + this.props.tooltipPos)
125
127
  }, this.props.tooltip) : null), this.el && this.state.popup ? /*#__PURE__*/React.createElement(PopupMenu, {
128
+ align: this.props.menuAlign,
126
129
  anchor: this.el,
127
130
  className: menuClassnames,
128
131
  onClose: function onClose() {
@@ -150,6 +153,7 @@ _defineProperty(MenuButton, "propTypes", {
150
153
  children: PropTypes.array,
151
154
  className: PropTypes.string,
152
155
  disabled: PropTypes.bool,
156
+ menuAlign: PropTypes.string,
153
157
  menuClassName: PropTypes.string,
154
158
  menuIcon: PropTypes.string,
155
159
  menuLabel: PropTypes.string,
@@ -50,7 +50,7 @@ var NumberInput = /*#__PURE__*/function (_React$Component) {
50
50
  });
51
51
  _defineProperty(_this, "currentFloatValue", function () {
52
52
  if (_this.state.value === "") {
53
- return 0;
53
+ return null;
54
54
  }
55
55
  var floatValue = parseFloat(_this.state.value);
56
56
  return isNaN(floatValue) ? null : floatValue;
@@ -156,13 +156,14 @@ var PopupMenu = /*#__PURE__*/function (_React$PureComponent) {
156
156
  }, {
157
157
  key: "render",
158
158
  value: function render() {
159
- var _rect$left,
159
+ var _ref,
160
160
  _rect,
161
- _rect$bottom,
162
161
  _rect2,
163
- _ref,
164
- _rect$width,
162
+ _rect$bottom,
165
163
  _rect3,
164
+ _ref2,
165
+ _rect$width,
166
+ _rect4,
166
167
  _this$props$disabledI,
167
168
  _this2 = this;
168
169
  if (isEmpty(this.props.children)) {
@@ -182,19 +183,12 @@ var PopupMenu = /*#__PURE__*/function (_React$PureComponent) {
182
183
  this.shields[2].style.left = rect.right + "px";
183
184
  this.shields[3].style.top = rect.bottom + "px";
184
185
  }
185
- var x = (_rect$left = (_rect = rect) === null || _rect === void 0 ? void 0 : _rect.left) !== null && _rect$left !== void 0 ? _rect$left : this.props.x;
186
- var y = ((_rect$bottom = (_rect2 = rect) === null || _rect2 === void 0 ? void 0 : _rect2.bottom) !== null && _rect$bottom !== void 0 ? _rect$bottom : this.props.y) - 1;
187
- var minWidth = (_ref = (_rect$width = (_rect3 = rect) === null || _rect3 === void 0 ? void 0 : _rect3.width) !== null && _rect$width !== void 0 ? _rect$width : this.props.width) !== null && _ref !== void 0 ? _ref : 0;
188
- var style = {
189
- position: 'absolute',
190
- left: x + 'px',
191
- top: y + 'px',
192
- minWidth: minWidth + 'px',
193
- maxHeight: window.innerHeight - y - 5 + 'px',
194
- overflowY: 'auto',
195
- zIndex: 1,
196
- pointerEvents: 'initial'
197
- };
186
+ var x = (_ref = this.props.align === 'right' ? (_rect = rect) === null || _rect === void 0 ? void 0 : _rect.right : (_rect2 = rect) === null || _rect2 === void 0 ? void 0 : _rect2.left) !== null && _ref !== void 0 ? _ref : this.props.x;
187
+ var y = ((_rect$bottom = (_rect3 = rect) === null || _rect3 === void 0 ? void 0 : _rect3.bottom) !== null && _rect$bottom !== void 0 ? _rect$bottom : this.props.y) - 1;
188
+ var minWidth = (_ref2 = (_rect$width = (_rect4 = rect) === null || _rect4 === void 0 ? void 0 : _rect4.width) !== null && _rect$width !== void 0 ? _rect$width : this.props.width) !== null && _ref2 !== void 0 ? _ref2 : 0;
189
+ var style = _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty({
190
+ position: 'absolute'
191
+ }, this.props.align === "right" ? "right" : "left", (this.props.align === "right" ? window.innerWidth - x : x) + 'px'), "top", y + 'px'), "minWidth", minWidth + 'px'), "maxHeight", window.innerHeight - y - 5 + 'px'), "overflowY", 'auto'), "zIndex", 1), "pointerEvents", 'initial');
198
192
  if (this.props.setMaxWidth) {
199
193
  style.maxWidth = minWidth + 'px';
200
194
  }
@@ -225,6 +219,7 @@ var PopupMenu = /*#__PURE__*/function (_React$PureComponent) {
225
219
  }]);
226
220
  }(React.PureComponent);
227
221
  _defineProperty(PopupMenu, "propTypes", {
222
+ align: PropTypes.string,
228
223
  anchor: PropTypes.object,
229
224
  children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]),
230
225
  className: PropTypes.string,
@@ -52,6 +52,10 @@ span.menubutton-button-content {
52
52
  align-items: center;
53
53
  }
54
54
 
55
+ span.menubutton-button-content span+span {
56
+ margin-left: 0.5em;
57
+ }
58
+
55
59
  div.menubutton span.menubotton-button-arrow {
56
60
  height: 80%;
57
61
  display: flex;
@@ -104,4 +108,4 @@ span.menubutton-tooltip-bottom {
104
108
 
105
109
  div.menubutton:hover span.menubutton-tooltip {
106
110
  display: inline;
107
- }
111
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwc2",
3
- "version": "2026.05.28",
3
+ "version": "2026.06.04",
4
4
  "description": "QGIS Web Client",
5
5
  "author": "Sourcepole AG",
6
6
  "license": "BSD-2-Clause",
@@ -395,7 +395,7 @@ var selector = function selector(state) {
395
395
  var backgroundLayers = Object.values(state.layers.flat.filter(function (layer) {
396
396
  return layer.role === LayerRole.BACKGROUND;
397
397
  }).reduce(function (res, l) {
398
- return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, l.group || l.name, l.group ? [].concat(_toConsumableArray(res[l.group] || []), [l]) : l));
398
+ return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, "_" + (l.group || l.name), l.group ? [].concat(_toConsumableArray(res["_" + l.group] || []), [l]) : l));
399
399
  }, {}));
400
400
  return {
401
401
  backgroundLayers: backgroundLayers
@@ -76,6 +76,11 @@ var Bookmark = /*#__PURE__*/function (_React$Component) {
76
76
  });
77
77
  }
78
78
  });
79
+ _defineProperty(_this, "bookmarkDoubleClicked", function (ev, bookmark) {
80
+ if (!_this.state.renameBookmark) {
81
+ _this.open(bookmark.key, false);
82
+ }
83
+ });
79
84
  _defineProperty(_this, "updateBookmarkName", function (text) {
80
85
  _this.setState({
81
86
  busy: true
@@ -284,8 +289,8 @@ var Bookmark = /*#__PURE__*/function (_React$Component) {
284
289
  onClick: function onClick(ev) {
285
290
  return _this2.bookmarkClicked(ev, bookmark);
286
291
  },
287
- onDoubleClick: function onDoubleClick() {
288
- return _this2.open(bookmark.key, false);
292
+ onDoubleClick: function onDoubleClick(ev) {
293
+ return _this2.bookmarkDoubleClicked(ev, bookmark);
289
294
  },
290
295
  title: lastUpdateTitle + ": " + bookmark.date
291
296
  }, _this2.state.renameBookmark === bookmark.key ? /*#__PURE__*/React.createElement(InputContainer, null, /*#__PURE__*/React.createElement(TextInput, {
@@ -392,7 +392,8 @@ var Editing = /*#__PURE__*/function (_React$Component) {
392
392
  value = !['0', 'false'].includes(String(value).toLowerCase());
393
393
  } else if (field.type === 'date') {
394
394
  if (typeof value === 'string') {
395
- value = dateParser.fromString(value).toISOString();
395
+ var _dateParser$fromStrin, _dateParser$fromStrin2, _dateParser$fromStrin3;
396
+ value = (_dateParser$fromStrin = (_dateParser$fromStrin2 = dateParser.fromString(value)) === null || _dateParser$fromStrin2 === void 0 || (_dateParser$fromStrin3 = _dateParser$fromStrin2.toISOString) === null || _dateParser$fromStrin3 === void 0 ? void 0 : _dateParser$fromStrin3.call(_dateParser$fromStrin2)) !== null && _dateParser$fromStrin !== void 0 ? _dateParser$fromStrin : null;
396
397
  }
397
398
  } else if (field.type === 'list') {
398
399
  // Not supported
@@ -231,6 +231,8 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
231
231
  * }
232
232
  */
233
233
  currentSensorLocation: null,
234
+ // automatically add all Datastreams of currently selected Location if true
235
+ addCurrentLocationDatastreams: false,
234
236
  // show currently selected Location info window if true
235
237
  showLocationInfoWindow: false,
236
238
  // currently selected Datastreams filter options
@@ -952,12 +954,11 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
952
954
  icon: "remove"
953
955
  }))), /*#__PURE__*/React.createElement("div", {
954
956
  className: "sensor-things-location-select-list"
955
- }, _this.state.locationsAtPoint.map(function (location, idx) {
956
- return /*#__PURE__*/React.createElement("div", {
957
- key: "select-location-" + idx,
958
- onClickCapture: function onClickCapture() {
959
- return _this.addLocation(location);
960
- },
957
+ }, /*#__PURE__*/React.createElement("table", {
958
+ className: "sensor-things-location-select-table"
959
+ }, /*#__PURE__*/React.createElement("tbody", null, _this.state.locationsAtPoint.map(function (location, idx) {
960
+ return /*#__PURE__*/React.createElement("tr", {
961
+ key: "select-location--" + idx,
961
962
  onMouseOut: function onMouseOut() {
962
963
  return _this.setState({
963
964
  highlightedLocation: null
@@ -968,8 +969,31 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
968
969
  highlightedLocation: location
969
970
  });
970
971
  }
971
- }, location.name, ": ", location.description);
972
- })));
972
+ }, /*#__PURE__*/React.createElement("td", {
973
+ onClickCapture: function onClickCapture() {
974
+ return _this.addLocation(location);
975
+ },
976
+ title: "".concat(location.name, ": ").concat(location.description)
977
+ }, location.name, ": ", location.description), /*#__PURE__*/React.createElement("td", null, /*#__PURE__*/React.createElement("div", {
978
+ className: "sensor-things-location-select-buttons"
979
+ }, /*#__PURE__*/React.createElement("button", {
980
+ className: "button",
981
+ onClick: function onClick() {
982
+ return _this.addLocation(location);
983
+ },
984
+ title: LocaleUtils.tr("sensorthingstool.addLocation")
985
+ }, /*#__PURE__*/React.createElement(Icon, {
986
+ icon: "plus"
987
+ })), /*#__PURE__*/React.createElement("button", {
988
+ className: "button",
989
+ onClick: function onClick() {
990
+ return _this.addFullLocation(location);
991
+ },
992
+ title: LocaleUtils.tr("sensorthingstool.addLocationAndDatastreams")
993
+ }, /*#__PURE__*/React.createElement(Icon, {
994
+ icon: "sync"
995
+ })))));
996
+ })))));
973
997
  } else {
974
998
  return null;
975
999
  }
@@ -1008,6 +1032,16 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
1008
1032
  });
1009
1033
  }
1010
1034
  });
1035
+ _defineProperty(_this, "addFullLocation", function (location) {
1036
+ // remove current Datastreams
1037
+ _this.removeAllDatastreams();
1038
+ // add selected Location
1039
+ _this.addLocation(location);
1040
+ // set flag to automatically add all Datastreams of selected Location once ready
1041
+ _this.setState({
1042
+ addCurrentLocationDatastreams: true
1043
+ });
1044
+ });
1011
1045
  _defineProperty(_this, "removeSelectedLocation", function () {
1012
1046
  if (_this.state.currentSensorLocation === null) {
1013
1047
  // skip if currentSensorLocation not yet ready
@@ -1147,6 +1181,12 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
1147
1181
  });
1148
1182
  }
1149
1183
  });
1184
+ _defineProperty(_this, "addDatastreams", function (datastreamIds) {
1185
+ // add multiple Datastreams
1186
+ datastreamIds.forEach(function (datastreamId) {
1187
+ _this.addDatastream(datastreamId);
1188
+ });
1189
+ });
1150
1190
  _defineProperty(_this, "removeDatastream", function (datastreamIndex) {
1151
1191
  _this.setState(function (state) {
1152
1192
  var datastreamInfoWindow = state.datastreamInfoWindow;
@@ -1181,6 +1221,18 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
1181
1221
  };
1182
1222
  });
1183
1223
  });
1224
+ _defineProperty(_this, "removeAllDatastreams", function () {
1225
+ _this.setState(function (state) {
1226
+ return {
1227
+ graph: _objectSpread(_objectSpread({}, state.graph), {}, {
1228
+ datastreams: []
1229
+ }),
1230
+ datastreamInfoWindow: null,
1231
+ datastreamOptions: [],
1232
+ datastreamTableWindow: null
1233
+ };
1234
+ });
1235
+ });
1184
1236
  // NOTE: color as [<r>, <g>, <b>] (0-255)
1185
1237
  _defineProperty(_this, "optionsForThresholdLine", function (axisID, label, thresholdValue, color) {
1186
1238
  var annotationOptions = {
@@ -2963,6 +3015,14 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
2963
3015
  } else if (prevState.currentSensorLocation && !this.state.currentSensorLocation) {
2964
3016
  this.props.removeLayer("sensorThingsSelection");
2965
3017
  }
3018
+ if (this.state.addCurrentLocationDatastreams && this.state.currentSensorLocation && this.state.currentSensorLocation.id === this.state.currentLocationId) {
3019
+ // add all Datastreams of current Location
3020
+ this.addDatastreams(this.state.currentSensorLocation.datastreams);
3021
+ // reset flag
3022
+ this.setState({
3023
+ addCurrentLocationDatastreams: false
3024
+ });
3025
+ }
2966
3026
  if (this.state.currentDatastreamsFilter !== prevState.currentDatastreamsFilter) {
2967
3027
  this.filterLocationDatastreams();
2968
3028
  }