qwc2 2026.6.3 → 2026.6.9

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 (37) hide show
  1. package/components/AttributeForm.js +64 -96
  2. package/components/AutoEditForm.js +12 -1
  3. package/components/QtDesignerForm.js +10 -5
  4. package/components/style/App.css +4 -0
  5. package/components/widgets/MenuButton.js +5 -1
  6. package/components/widgets/NumberInput.js +1 -1
  7. package/components/widgets/PopupMenu.js +12 -17
  8. package/components/widgets/style/MenuButton.css +5 -1
  9. package/package.json +1 -1
  10. package/plugins/SensorThingsTool.js +79 -11
  11. package/plugins/map/LocateSupport.js +16 -2
  12. package/plugins/map3d/Identify3D.js +2 -2
  13. package/plugins/style/SensorThingsTool.css +18 -3
  14. package/static/translations/bg-BG.json +3 -0
  15. package/static/translations/ca-ES.json +3 -0
  16. package/static/translations/cs-CZ.json +3 -0
  17. package/static/translations/de-CH.json +3 -0
  18. package/static/translations/de-DE.json +4 -1
  19. package/static/translations/en-US.json +3 -0
  20. package/static/translations/es-ES.json +3 -0
  21. package/static/translations/fi-FI.json +3 -0
  22. package/static/translations/fr-FR.json +4 -1
  23. package/static/translations/hu-HU.json +3 -0
  24. package/static/translations/it-IT.json +3 -0
  25. package/static/translations/ja-JP.json +3 -0
  26. package/static/translations/nl-NL.json +3 -0
  27. package/static/translations/no-NO.json +3 -0
  28. package/static/translations/pl-PL.json +3 -0
  29. package/static/translations/pt-BR.json +3 -0
  30. package/static/translations/pt-PT.json +3 -0
  31. package/static/translations/ro-RO.json +3 -0
  32. package/static/translations/ru-RU.json +3 -0
  33. package/static/translations/sv-SE.json +3 -0
  34. package/static/translations/tr-TR.json +3 -0
  35. package/static/translations/tsconfig.json +3 -0
  36. package/static/translations/uk-UA.json +3 -0
  37. package/utils/EditingInterface.js +4 -6
@@ -1,14 +1,14 @@
1
1
  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); }
2
+ function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
3
+ 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."); }
4
+ 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; } }
5
+ function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
2
6
  function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); }
3
7
  function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
8
+ 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; } }
4
9
  function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); }
5
10
  function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); }
6
- function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
7
- 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."); }
8
- 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; } }
9
11
  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; }
10
- 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; } }
11
- function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
12
12
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
13
13
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
14
14
  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); }
@@ -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({
@@ -228,30 +226,25 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
228
226
  _defineProperty(_this, "loadRelationValues", function (feature, callback) {
229
227
  if (!isEmpty(_this.state.relationTables)) {
230
228
  if (feature.id) {
231
- var relTables = Object.entries(_this.state.relationTables).map(function (_ref) {
232
- var _ref2 = _slicedToArray(_ref, 2),
233
- name = _ref2[0],
234
- entry = _ref2[1];
235
- if (entry.sortcol) {
236
- return name + ":" + entry.fk + ":" + entry.sortcol;
237
- } else {
238
- return name + ":" + entry.fk;
239
- }
240
- }).join(",");
229
+ // Existing feature, load relations from data service
230
+ var relTables = Object.values(_this.state.relationTables).map(function (entry) {
231
+ return _objectSpread(_objectSpread({}, entry), {}, {
232
+ fkVal: entry.pkField ? feature.properties[entry.pkField] : feature.id
233
+ });
234
+ });
241
235
  var mapEditConfigs = _this.props.editConfigs[_this.props.editContext.mapPrefix];
242
- _this.props.iface.getRelations(_this.props.editContext.editConfig, feature.id, _this.props.map.projection, relTables, mapEditConfigs, function (relationValues) {
236
+ _this.props.iface.getRelations(relTables, _this.props.map.projection, mapEditConfigs, function (relationValues) {
243
237
  var newFeature = _objectSpread(_objectSpread({}, feature), {}, {
244
238
  relationValues: relationValues
245
239
  });
246
240
  callback(newFeature);
247
241
  });
248
242
  } else {
249
- var relationValues = _objectSpread(_objectSpread({}, Object.entries(_this.state.relationTables).reduce(function (res, _ref3) {
250
- var _ref4 = _slicedToArray(_ref3, 2),
251
- name = _ref4[0],
252
- entry = _ref4[1];
253
- return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, name, {
254
- fk: entry.fk,
243
+ // New feature, create relationValues skeleton
244
+ var relationValues = _objectSpread(_objectSpread({}, Object.values(_this.state.relationTables).reduce(function (res, entry) {
245
+ return _objectSpread(_objectSpread({}, res), {}, _defineProperty({}, entry.table, {
246
+ fk: entry.fkField,
247
+ pk: entry.pkField,
255
248
  features: []
256
249
  }));
257
250
  }, {})), feature.relationValues);
@@ -275,7 +268,9 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
275
268
  }
276
269
  // If feature id is known, i.e. not when drawing new feature, set foreign key
277
270
  if (_this.props.editContext.action !== "Draw") {
278
- newRelFeature.properties[_this.state.relationTables[table].fk] = _this.props.editContext.feature.id;
271
+ var relTable = _this.state.relationTables[table];
272
+ var fkVal = relTable.pkField ? _this.props.editContext.feature.properties[relTable.pkField] : _this.props.editContext.feature.id;
273
+ newRelFeature.properties[relTable.fkField] = fkVal;
279
274
  }
280
275
  newRelationValues[table] = _objectSpread({}, newRelationValues[table]);
281
276
  newRelationValues[table].features = newRelationValues[table].features.concat([newRelFeature]);
@@ -380,9 +375,11 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
380
375
  });
381
376
  // If feature id is known, i.e. not when drawing new feature, set foreign key
382
377
  var changed = _this.props.editContext.changed;
378
+ var relTable = _this.state.relationTables[table];
379
+ var fkVal = relTable.pkField ? _this.props.editContext.feature.properties[relTable.pkField] : _this.props.editContext.feature.id;
383
380
  var fk = _this.state.relationTables[table].fk;
384
- if (_this.props.editContext.action !== "Draw" && feature.properties[fk] !== _this.props.editContext.feature.id) {
385
- newRelationValues[table].features[idx].properties[fk] = _this.props.editContext.feature.id;
381
+ if (_this.props.editContext.action !== "Draw" && feature.properties[fk] !== fkVal) {
382
+ newRelationValues[table].features[idx].properties[fk] = fkVal;
386
383
  newRelationValues[table].features[idx].__status__ = "changed";
387
384
  changed = true;
388
385
  }
@@ -419,8 +416,6 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
419
416
  changed: false
420
417
  });
421
418
  });
422
- // Re-validate feature field constraints
423
- _this.validateFieldConstraints(feature);
424
419
  } else {
425
420
  _this.props.setEditContext(_this.props.editContext.id, {
426
421
  feature: feature,
@@ -443,37 +438,7 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
443
438
  }
444
439
  }
445
440
  });
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) {
441
+ _defineProperty(_this, "validateForm", function (feature) {
477
442
  var validCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
478
443
  var invalidCallback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
479
444
  var constraintExpressions = _this.props.editContext.editConfig.fields.reduce(function (res, cur) {
@@ -487,12 +452,12 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
487
452
  return res;
488
453
  }, []);
489
454
  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;
455
+ var valid = _this.form.checkValidity();
491
456
  var reasons = [];
492
- Object.entries(result).forEach(function (_ref5) {
493
- var _ref6 = _slicedToArray(_ref5, 2),
494
- key = _ref6[0],
495
- value = _ref6[1];
457
+ Object.entries(result).forEach(function (_ref) {
458
+ var _ref2 = _slicedToArray(_ref, 2),
459
+ key = _ref2[0],
460
+ value = _ref2[1];
496
461
  var element = _this.form.elements.namedItem(key);
497
462
  if (element) {
498
463
  if (value === false) {
@@ -508,23 +473,27 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
508
473
  }
509
474
  }
510
475
  });
476
+ Array.from(_this.form.elements).filter(function (el) {
477
+ return el.willValidate && el.required && el.validity.valueMissing;
478
+ }).forEach(function (el) {
479
+ reasons.push("".concat(el.name, ": ").concat(LocaleUtils.tr("editing.emptyvalue")));
480
+ });
511
481
  if (!valid) {
512
482
  _this.setState({
513
483
  formValid: false
514
484
  });
515
- if (invalidCallback) {
516
- invalidCallback(reasons);
517
- }
485
+ invalidCallback === null || invalidCallback === void 0 || invalidCallback(reasons);
518
486
  } else {
519
- if (validCallback) {
520
- validCallback();
521
- }
487
+ _this.setState({
488
+ formValid: true
489
+ });
490
+ validCallback === null || validCallback === void 0 || validCallback();
522
491
  }
523
492
  });
524
493
  });
525
494
  _defineProperty(_this, "onSubmit", function (ev) {
526
495
  ev.preventDefault();
527
- _this.validateFieldConstraints(_this.props.editContext.feature, _this.doSubmit, function (reasons) {
496
+ _this.validateForm(_this.props.editContext.feature, _this.doSubmit, function (reasons) {
528
497
  /* eslint-disable-next-line */
529
498
  alert(LocaleUtils.tr("editing.contraintviolation") + ":\n" + reasons.join("\n"));
530
499
  });
@@ -678,10 +647,10 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
678
647
  delete feature.properties[key];
679
648
  }
680
649
  });
681
- Object.entries(relationValues).forEach(function (_ref7) {
682
- var _ref8 = _slicedToArray(_ref7, 2),
683
- dataset = _ref8[0],
684
- entry = _ref8[1];
650
+ Object.entries(relationValues).forEach(function (_ref3) {
651
+ var _ref4 = _slicedToArray(_ref3, 2),
652
+ dataset = _ref4[0],
653
+ entry = _ref4[1];
685
654
  var _dataset$split = dataset.split(".", 2),
686
655
  _dataset$split2 = _slicedToArray(_dataset$split, 2),
687
656
  mapName = _dataset$split2[0],
@@ -712,11 +681,11 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
712
681
  }
713
682
  }
714
683
  });
715
- var sortcol = _this.state.relationTables[relTable].sortcol;
684
+ var sortField = _this.state.relationTables[relTable].sortField;
716
685
  var noreorder = _this.state.relationTables[relTable].noreorder;
717
- if (sortcol && !noreorder) {
718
- newRelFeature.__status__ = feature.__status__ || (newRelFeature.properties[sortcol] !== idx ? "changed" : "");
719
- newRelFeature.properties[sortcol] = idx;
686
+ if (sortField && !noreorder) {
687
+ newRelFeature.__status__ = feature.__status__ || (newRelFeature.properties[sortField] !== idx ? "changed" : "");
688
+ newRelFeature.properties[sortField] = idx;
720
689
  }
721
690
  return newRelFeature;
722
691
  });
@@ -724,16 +693,16 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
724
693
  feature.relationValues = relationValues;
725
694
  var featureData = new FormData();
726
695
  featureData.set('feature', JSON.stringify(feature));
727
- Object.entries(featureUploads).forEach(function (_ref9) {
728
- var _ref0 = _slicedToArray(_ref9, 2),
729
- key = _ref0[0],
730
- value = _ref0[1];
696
+ Object.entries(featureUploads).forEach(function (_ref5) {
697
+ var _ref6 = _slicedToArray(_ref5, 2),
698
+ key = _ref6[0],
699
+ value = _ref6[1];
731
700
  return featureData.set('file:' + key, value);
732
701
  });
733
- Object.entries(relationUploads).forEach(function (_ref1) {
734
- var _ref10 = _slicedToArray(_ref1, 2),
735
- key = _ref10[0],
736
- value = _ref10[1];
702
+ Object.entries(relationUploads).forEach(function (_ref7) {
703
+ var _ref8 = _slicedToArray(_ref7, 2),
704
+ key = _ref8[0],
705
+ value = _ref8[1];
737
706
  return featureData.set('relfile:' + _this.props.editContext.mapPrefix + "." + key, value);
738
707
  });
739
708
  if (_this.state.captchaResponse) {
@@ -826,8 +795,6 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
826
795
  changed: false
827
796
  });
828
797
  });
829
- // Re-validate feature field constraints
830
- _this.validateFieldConstraints(result);
831
798
  } else {
832
799
  _this.props.setEditContext(_this.props.editContext.id, {
833
800
  action: 'Pick',
@@ -931,8 +898,9 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
931
898
  feature: newFeature
932
899
  });
933
900
  });
934
- // Re-validate feature field constraints
935
- this.validateFieldConstraints(this.props.editContext.feature);
901
+ }
902
+ if (this.props.editContext.feature !== prevProps.editContext.feature) {
903
+ this.validateForm(this.props.editContext.feature);
936
904
  }
937
905
  }
938
906
  }, {
@@ -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,
@@ -401,7 +401,7 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
401
401
  })));
402
402
  } else if (widget["class"] === "QTextEdit" || widget["class"] === "QTextBrowser" || widget["class"] === "QPlainTextEdit") {
403
403
  var _feature$properties$w3, _feature$properties3;
404
- if (((_feature$properties$w3 = (_feature$properties3 = feature.properties) === null || _feature$properties3 === void 0 ? void 0 : _feature$properties3[widget.name]) !== null && _feature$properties$w3 !== void 0 ? _feature$properties$w3 : null) === null) {
404
+ if (value === "" && ((_feature$properties$w3 = (_feature$properties3 = feature.properties) === null || _feature$properties3 === void 0 ? void 0 : _feature$properties3[widget.name]) !== null && _feature$properties$w3 !== void 0 ? _feature$properties$w3 : null) === null) {
405
405
  var _ConfigUtils$getConfi;
406
406
  value = (_ConfigUtils$getConfi = ConfigUtils.getConfigProp("editTextNullValue")) !== null && _ConfigUtils$getConfi !== void 0 ? _ConfigUtils$getConfi : "";
407
407
  }
@@ -448,7 +448,7 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
448
448
  var _feature$properties$w4, _feature$properties5;
449
449
  if (fieldConstraints.prec !== undefined && typeof value === 'number') {
450
450
  value = value.toFixed(fieldConstraints.prec);
451
- } else if (((_feature$properties$w4 = (_feature$properties5 = feature.properties) === null || _feature$properties5 === void 0 ? void 0 : _feature$properties5[widget.name]) !== null && _feature$properties$w4 !== void 0 ? _feature$properties$w4 : null) === null) {
451
+ } else if (value === "" && ((_feature$properties$w4 = (_feature$properties5 = feature.properties) === null || _feature$properties5 === void 0 ? void 0 : _feature$properties5[widget.name]) !== null && _feature$properties$w4 !== void 0 ? _feature$properties$w4 : null) === null) {
452
452
  var _ConfigUtils$getConfi2;
453
453
  value = (_ConfigUtils$getConfi2 = ConfigUtils.getConfigProp("editTextNullValue")) !== null && _ConfigUtils$getConfi2 !== void 0 ? _ConfigUtils$getConfi2 : "";
454
454
  }
@@ -1034,10 +1034,15 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
1034
1034
  }
1035
1035
  var parts = widget.name.split("__");
1036
1036
  if (parts.length >= 3 && parts[0] === "nrel") {
1037
+ var _this$props$editConfi2, _this$props$editConfi3;
1037
1038
  relationTables[_this.props.mapPrefix + "." + parts[1]] = {
1038
- fk: parts[2],
1039
- sortcol: parts[3] || null,
1040
- noreorder: parts[4] || false
1039
+ table: _this.props.mapPrefix + "." + parts[1],
1040
+ fkField: parts[2],
1041
+ sortField: parts[3] || null,
1042
+ noreorder: parts[4] || false,
1043
+ pkField: (_this$props$editConfi2 = (_this$props$editConfi3 = _this.props.editConfig.reltables.find(function (entry) {
1044
+ return entry.id === widget.name;
1045
+ })) === null || _this$props$editConfi3 === void 0 ? void 0 : _this$props$editConfi3.referencedField) !== null && _this$props$editConfi2 !== void 0 ? _this$props$editConfi2 : null
1041
1046
  };
1042
1047
  }
1043
1048
  return verticalFill;
@@ -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
  }
@@ -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.06.03",
3
+ "version": "2026.06.09",
4
4
  "description": "QGIS Web Client",
5
5
  "author": "Sourcepole AG",
6
6
  "license": "BSD-2-Clause",
@@ -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 = {
@@ -1661,7 +1713,8 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
1661
1713
  showDatastreamsFilterWindow: false
1662
1714
  });
1663
1715
  },
1664
- title: LocaleUtils.tr("sensorthingstool.datastreamsFilter.title")
1716
+ title: LocaleUtils.tr("sensorthingstool.datastreamsFilter.title"),
1717
+ usePortal: false
1665
1718
  }, /*#__PURE__*/React.createElement("div", {
1666
1719
  className: "sensor-things-dialog-body",
1667
1720
  role: "body"
@@ -2018,6 +2071,7 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
2018
2071
  showWindow: false,
2019
2072
  pickGeom: null
2020
2073
  });
2074
+ _this.props.removeLayer("sensorThingsSelection");
2021
2075
  });
2022
2076
  _defineProperty(_this, "initPeriod", function () {
2023
2077
  if (_this.state.graph.x.min === null) {
@@ -2173,6 +2227,11 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
2173
2227
  }
2174
2228
  var sensor = datastream.Sensor;
2175
2229
  var observedProperty = datastream.ObservedProperty;
2230
+ var unitOfMeasurement = datastream.unitOfMeasurement || {};
2231
+ if (unitOfMeasurement.symbol === undefined || unitOfMeasurement.symbol === null) {
2232
+ // set empty string as dummy symbol if missing
2233
+ unitOfMeasurement.symbol = "";
2234
+ }
2176
2235
  datastreamsLookup[datastreamId] = {
2177
2236
  locationId: location['@iot.id'],
2178
2237
  thing: {
@@ -2193,7 +2252,7 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
2193
2252
  id: datastreamId,
2194
2253
  name: datastream.name,
2195
2254
  description: datastream.description,
2196
- unitOfMeasurement: datastream.unitOfMeasurement,
2255
+ unitOfMeasurement: unitOfMeasurement,
2197
2256
  phenomenonTime: datastream.phenomenonTime,
2198
2257
  period: {
2199
2258
  begin: periodBegin,
@@ -2963,6 +3022,14 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
2963
3022
  } else if (prevState.currentSensorLocation && !this.state.currentSensorLocation) {
2964
3023
  this.props.removeLayer("sensorThingsSelection");
2965
3024
  }
3025
+ if (this.state.addCurrentLocationDatastreams && this.state.currentSensorLocation && this.state.currentSensorLocation.id === this.state.currentLocationId) {
3026
+ // add all Datastreams of current Location
3027
+ this.addDatastreams(this.state.currentSensorLocation.datastreams);
3028
+ // reset flag
3029
+ this.setState({
3030
+ addCurrentLocationDatastreams: false
3031
+ });
3032
+ }
2966
3033
  if (this.state.currentDatastreamsFilter !== prevState.currentDatastreamsFilter) {
2967
3034
  this.filterLocationDatastreams();
2968
3035
  }
@@ -3021,7 +3088,8 @@ var SensorThingsTool = /*#__PURE__*/function (_React$Component) {
3021
3088
  onClose: function onClose() {
3022
3089
  return _this3.props.setCurrentTask(null);
3023
3090
  },
3024
- title: LocaleUtils.tr("sensorthingstool.title")
3091
+ title: LocaleUtils.tr("sensorthingstool.title"),
3092
+ usePortal: false
3025
3093
  }, this.renderBody()), this.renderLocationSelectPopup(), this.renderLocationInfoWindow(), this.renderDatastreamsFilterWindow(), this.renderDatastreamInfoWindow(), this.renderDatastreamTableWindow(), /*#__PURE__*/React.createElement(MapSelection, {
3026
3094
  active: this.state.locationPickingActive,
3027
3095
  cursor: "crosshair",
@@ -29,8 +29,10 @@ import { connect } from 'react-redux';
29
29
  import ol from 'openlayers';
30
30
  import PropTypes from 'prop-types';
31
31
  import { changeLocateState, changeLocatePosition, onLocateError } from '../../actions/locate';
32
+ import { zoomToPoint } from '../../actions/map';
32
33
  import CoordinatesUtils from '../../utils/CoordinatesUtils';
33
34
  import LocaleUtils from '../../utils/LocaleUtils';
35
+ import MapUtils from '../../utils/MapUtils';
34
36
  import './style/LocateSupport.css';
35
37
 
36
38
  /**
@@ -218,6 +220,12 @@ var LocateSupport = /*#__PURE__*/function (_React$Component) {
218
220
  this.requestedMode = "DISABLED";
219
221
  this.stop();
220
222
  }
223
+ if (newState === "FOLLOWING" && oldState !== "FOLLOWING" && this.props.followScale && this.props.scales) {
224
+ var mapPos = this.geolocate.getPosition();
225
+ if (mapPos) {
226
+ this.props.zoomToPoint(mapPos, MapUtils.computeZoom(this.props.scales, this.props.followScale), this.props.projection);
227
+ }
228
+ }
221
229
  }
222
230
  if (this.props.projection !== prevProps.projection) {
223
231
  this.geolocate.setProjection(this.props.projection);
@@ -235,12 +243,15 @@ _defineProperty(LocateSupport, "propTypes", {
235
243
  changeLocateState: PropTypes.func,
236
244
  /** Whether to draw an accuracy circle around the location point. */
237
245
  drawCircle: PropTypes.bool,
246
+ /** Scale denominator to zoom to when entering follow mode. If not set, the map zoom level is not changed. */
247
+ followScale: PropTypes.number,
238
248
  locateState: PropTypes.object,
239
249
  map: PropTypes.object,
240
250
  /** Whether to display the accuracy in meters (`true`) or in feet (`false`). */
241
251
  metric: PropTypes.bool,
242
252
  onLocateError: PropTypes.func,
243
253
  projection: PropTypes.string,
254
+ scales: PropTypes.arrayOf(PropTypes.number),
244
255
  /** Whether to show a popup displaying accuracy information when clicking on the location point. */
245
256
  showPopup: PropTypes.bool,
246
257
  /** The geolocation startup mode. Either `DISABLED`, `ENABLED` or `FOLLOWING`. */
@@ -249,7 +260,8 @@ _defineProperty(LocateSupport, "propTypes", {
249
260
  /** Whether to stop following when the map is dragged. */
250
261
  stopFollowingOnDrag: PropTypes.bool,
251
262
  /** Tracking options, as documented in the [HTML5 Geolocation spec](https://www.w3.org/TR/geolocation-API/#position_options_interface) */
252
- trackingOptions: PropTypes.object
263
+ trackingOptions: PropTypes.object,
264
+ zoomToPoint: PropTypes.func
253
265
  });
254
266
  _defineProperty(LocateSupport, "defaultProps", {
255
267
  drawCircle: true,
@@ -266,10 +278,12 @@ _defineProperty(LocateSupport, "defaultProps", {
266
278
  export default connect(function (state) {
267
279
  return {
268
280
  locateState: state.locate,
281
+ scales: state.map.scales,
269
282
  startupParams: state.localConfig.startupParams
270
283
  };
271
284
  }, {
272
285
  changeLocateState: changeLocateState,
273
286
  changeLocatePosition: changeLocatePosition,
274
- onLocateError: onLocateError
287
+ onLocateError: onLocateError,
288
+ zoomToPoint: zoomToPoint
275
289
  })(LocateSupport);
@@ -93,10 +93,10 @@ var Identify3D = /*#__PURE__*/function (_React$Component) {
93
93
  var picks = [];
94
94
  Object.values(_this.props.sceneContext.objectTree).forEach(function (entry) {
95
95
  var _object$tiles;
96
- if (!entry.objectId || !_this.props.sceneContext.objectIsVisible(entry.objectId)) {
96
+ var object = _this.props.sceneContext.getSceneObject(entry.objectId);
97
+ if (!entry.objectId || !_this.props.sceneContext.objectIsVisible(entry.objectId) || !object) {
97
98
  return;
98
99
  }
99
- var object = _this.props.sceneContext.getSceneObject(entry.objectId);
100
100
  if ((_object$tiles = object.tiles) !== null && _object$tiles !== void 0 && _object$tiles.raycast) {
101
101
  var intersections = [];
102
102
  object.tiles.raycast(raycaster, intersections);
@@ -1,4 +1,5 @@
1
1
  div.sensor-things-dialog-body {
2
+ height: 100%;
2
3
  display: flex;
3
4
  flex-direction: column;
4
5
  }
@@ -163,16 +164,30 @@ div.sensor-things-location-select-header {
163
164
  }
164
165
  div.sensor-things-location-select-list {
165
166
  padding: 0.25em;
167
+ max-width: 500px;
166
168
  max-height: 16em;
167
169
  overflow-y: auto;
168
170
  }
169
- div.sensor-things-location-select-list div {
171
+ table.sensor-things-location-select-table tr:hover {
172
+ background-color: var(--button-bg-color);
173
+ }
174
+ table.sensor-things-location-select-table td {
170
175
  padding-top: 0.25em;
176
+ padding-bottom: 0.25em;
177
+ border-bottom: 1px solid var(--border-color);
171
178
  }
172
- div.sensor-things-location-select-list div:hover {
173
- font-weight: bold;
179
+ table.sensor-things-location-select-table td:nth-child(1) {
180
+ max-width: 430px;
181
+ overflow: hidden;
182
+ white-space: nowrap;
183
+ text-overflow: ellipsis;
174
184
  cursor: pointer;
175
185
  }
186
+ table.sensor-things-location-select-table td div.sensor-things-location-select-buttons {
187
+ display: flex;
188
+ padding-left: 0.25em;
189
+ font-size: 85%;
190
+ }
176
191
 
177
192
  table.sensor-things-location-info td:nth-child(1) {
178
193
  width: 8.5em;
@@ -224,6 +224,7 @@
224
224
  "create": "Създаване на",
225
225
  "discard": "Изхвърляне",
226
226
  "draw": "Начертайте",
227
+ "emptyvalue": "",
227
228
  "feature": "Функции",
228
229
  "geomnonzeroz": "Геометрията съдържа ненулеви стойности на Z и следователно е само за четене.",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "Crear",
225
225
  "discard": "Descartar",
226
226
  "draw": "Traçar",
227
+ "emptyvalue": "",
227
228
  "feature": "Element",
228
229
  "geomnonzeroz": "La geometria conté valors Z diferents de zero, per tant és de només lectura",
229
230
  "geomreadonly": "La geometria és només de lectura.",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "Vytvořit",
225
225
  "discard": "Vyřadit",
226
226
  "draw": "Kreslit",
227
+ "emptyvalue": "",
227
228
  "feature": "Prvek",
228
229
  "geomnonzeroz": "",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "Erstellen",
225
225
  "discard": "Abbrechen",
226
226
  "draw": "Zeichnen",
227
+ "emptyvalue": "Leerer Wert",
227
228
  "feature": "Objekt",
228
229
  "geomnonzeroz": "Die Geometrie enthält Z-Werte ungleich Null und ist daher nicht veränderbar.",
229
230
  "geomreadonly": "Die Geometrie ist nicht veränderbar.",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "Datastream zum Graph hinzufügen",
652
+ "addLocation": "Location hinzufügen",
653
+ "addLocationAndDatastreams": "Location hinzufügen und alle ihre Datastreams im Graph anzeigen",
651
654
  "datastreamInfo": {
652
655
  "calibration": "Kalibrierung",
653
656
  "description": "Beschreibung",
@@ -224,6 +224,7 @@
224
224
  "create": "Erstellen",
225
225
  "discard": "Abbrechen",
226
226
  "draw": "Zeichnen",
227
+ "emptyvalue": "Leerer Wert",
227
228
  "feature": "Objekt",
228
229
  "geomnonzeroz": "Die Geometrie enthält Z-Werte ungleich Null und ist daher nicht veränderbar.",
229
230
  "geomreadonly": "Die Geometrie ist nicht veränderbar",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "Datastream zum Graph hinzufügen",
652
+ "addLocation": "Location hinzufügen",
653
+ "addLocationAndDatastreams": "Location hinzufügen und alle ihre Datastreams im Graph anzeigen",
651
654
  "datastreamInfo": {
652
655
  "calibration": "Kalibrierung",
653
656
  "description": "Beschreibung",
@@ -813,7 +816,7 @@
813
816
  "title": "Titel"
814
817
  },
815
818
  "openintab": "In Tab öffnen",
816
- "restrictedcontent": "",
819
+ "restrictedcontent": "Theme mit Inhalten, die auf authentifizierte Benutzer beschränkt sind",
817
820
  "restrictedthemeinfo": "Sie sind nicht berechtigt oder sind nicht angemeldet"
818
821
  },
819
822
  "timemanager": {
@@ -224,6 +224,7 @@
224
224
  "create": "Create",
225
225
  "discard": "Discard",
226
226
  "draw": "Draw",
227
+ "emptyvalue": "Empty value",
227
228
  "feature": "Feature",
228
229
  "geomnonzeroz": "The geometry contains non-zero Z values and is therefore read only.",
229
230
  "geomreadonly": "The geometry is read only.",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "Add datastream to graph",
652
+ "addLocation": "Add location",
653
+ "addLocationAndDatastreams": "Add location and show all its datastreams in the graph",
651
654
  "datastreamInfo": {
652
655
  "calibration": "Calibration",
653
656
  "description": "Description",
@@ -224,6 +224,7 @@
224
224
  "create": "Crear",
225
225
  "discard": "Descartar",
226
226
  "draw": "Trazar",
227
+ "emptyvalue": "",
227
228
  "feature": "Elemento",
228
229
  "geomnonzeroz": "La geometría contiene valores Z diferentes de cero por lo que es sólo lectura",
229
230
  "geomreadonly": "La geometría es de solo lectura.",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "",
225
225
  "discard": "Discard",
226
226
  "draw": "Draw",
227
+ "emptyvalue": "",
227
228
  "feature": "Feature",
228
229
  "geomnonzeroz": "",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "Créer",
225
225
  "discard": "Rejeter",
226
226
  "draw": "Dessiner",
227
+ "emptyvalue": "Valeur vide",
227
228
  "feature": "Objet",
228
229
  "geomnonzeroz": "La géométrie contient des valeurs Z non nulles et ne peut donc pas être modifiée.",
229
230
  "geomreadonly": "La géométrie e peut pas être modifiée.",
@@ -533,7 +534,7 @@
533
534
  "loading": "Chargement des données..."
534
535
  },
535
536
  "portal": {
536
- "close": "",
537
+ "close": "Fermer le portail",
537
538
  "filter": "Filtrer les thèmes...",
538
539
  "menulabel": "Menu"
539
540
  },
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "Ajouter un flux de données au graphique",
652
+ "addLocation": "Ajouter un lieu",
653
+ "addLocationAndDatastreams": "Ajouter un emplacement et afficher tous ses flux de données dans le graphique",
651
654
  "datastreamInfo": {
652
655
  "calibration": "Calibration",
653
656
  "description": "Description",
@@ -224,6 +224,7 @@
224
224
  "create": "",
225
225
  "discard": "Elvetés",
226
226
  "draw": "Rajzolás",
227
+ "emptyvalue": "",
227
228
  "feature": "",
228
229
  "geomnonzeroz": "",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "Crea",
225
225
  "discard": "Annulla",
226
226
  "draw": "Disegna",
227
+ "emptyvalue": "Valore vuoto",
227
228
  "feature": "Oggetto",
228
229
  "geomnonzeroz": "La geometria contiene valori Z non nulli ed è quindi di sola lettura.",
229
230
  "geomreadonly": "La geometria è di solo lettura.",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "Aggiungi flusso di dati al grafico",
652
+ "addLocation": "Aggiungi una posizione",
653
+ "addLocationAndDatastreams": "Aggiungi una posizione e visualizza tutti i relativi flussi di dati nel grafico",
651
654
  "datastreamInfo": {
652
655
  "calibration": "Calibrazione",
653
656
  "description": "Descrizione",
@@ -224,6 +224,7 @@
224
224
  "create": "作成",
225
225
  "discard": "中止",
226
226
  "draw": "作図",
227
+ "emptyvalue": "",
227
228
  "feature": "地物",
228
229
  "geomnonzeroz": "ジオメトリが 0 でない Z 値を含んでいるため、リード・オンリーです。",
229
230
  "geomreadonly": "ジオメトリがリード・オンリーです。",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "Toevoegen",
225
225
  "discard": "Negeren",
226
226
  "draw": "Tekenen",
227
+ "emptyvalue": "",
227
228
  "feature": "Object",
228
229
  "geomnonzeroz": "De geometrie bevat geen Z-waarden en is daarom read only.",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "",
225
225
  "discard": "Forkast",
226
226
  "draw": "Tegn",
227
+ "emptyvalue": "",
227
228
  "feature": "Objekt",
228
229
  "geomnonzeroz": "",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "",
225
225
  "discard": "Odrzuć",
226
226
  "draw": "Rysuj",
227
+ "emptyvalue": "",
227
228
  "feature": "",
228
229
  "geomnonzeroz": "",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "Criar",
225
225
  "discard": "Descartar",
226
226
  "draw": "Desenhar",
227
+ "emptyvalue": "",
227
228
  "feature": "Feição",
228
229
  "geomnonzeroz": "Geometria somente de leitura",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "Criar",
225
225
  "discard": "Descartar",
226
226
  "draw": "Desenhar",
227
+ "emptyvalue": "",
227
228
  "feature": "Recurso",
228
229
  "geomnonzeroz": "Geometria Apenas para Leitura",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "Creare",
225
225
  "discard": "Renunță",
226
226
  "draw": "Desenare",
227
+ "emptyvalue": "",
227
228
  "feature": "Obiect spațial",
228
229
  "geomnonzeroz": "Geometria include valori Z și, prin urmare, nu poate fi editată",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "",
225
225
  "discard": "Отменить изменения",
226
226
  "draw": "Нарисовать",
227
+ "emptyvalue": "",
227
228
  "feature": "",
228
229
  "geomnonzeroz": "",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "",
225
225
  "discard": "Förkasta",
226
226
  "draw": "Rita",
227
+ "emptyvalue": "",
227
228
  "feature": "Objekt",
228
229
  "geomnonzeroz": "",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -224,6 +224,7 @@
224
224
  "create": "Yeni oluştur",
225
225
  "discard": "İptal",
226
226
  "draw": "Çiz",
227
+ "emptyvalue": "",
227
228
  "feature": "Obje",
228
229
  "geomnonzeroz": "Geometri, sıfır olmayan yükseklik değeri içerdiğinden salt okunur",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -235,6 +235,7 @@
235
235
  "editing.create",
236
236
  "editing.discard",
237
237
  "editing.draw",
238
+ "editing.emptyvalue",
238
239
  "editing.feature",
239
240
  "editing.geomnonzeroz",
240
241
  "editing.geomreadonly",
@@ -563,6 +564,8 @@
563
564
  "search.themes",
564
565
  "search.unknownmore",
565
566
  "sensorthingstool.addDatastream",
567
+ "sensorthingstool.addLocation",
568
+ "sensorthingstool.addLocationAndDatastreams",
566
569
  "sensorthingstool.datastreamInfo.calibration",
567
570
  "sensorthingstool.datastreamInfo.description",
568
571
  "sensorthingstool.datastreamInfo.location",
@@ -224,6 +224,7 @@
224
224
  "create": "",
225
225
  "discard": "Скасувати зміни",
226
226
  "draw": "Намалювати",
227
+ "emptyvalue": "",
227
228
  "feature": "",
228
229
  "geomnonzeroz": "",
229
230
  "geomreadonly": "",
@@ -648,6 +649,8 @@
648
649
  },
649
650
  "sensorthingstool": {
650
651
  "addDatastream": "",
652
+ "addLocation": "",
653
+ "addLocationAndDatastreams": "",
651
654
  "datastreamInfo": {
652
655
  "calibration": "",
653
656
  "description": "",
@@ -371,18 +371,16 @@ var EditingInterface = {
371
371
  },
372
372
  /**
373
373
  * Queries relation values of a feature
374
- * @param editConfig The edit config of the feature dataset
375
- * @param featureId The feature ID
374
+ * @param tables List of the form `[{"table": "<table>", "fkField": "<fk_field_name>", "fkVal": "<fk_val>", "sortCol": "<sort_col>", "pkField": "<pk_field>"}]`
376
375
  * @param mapCrs The CRS of the map, as an EPSG code
377
- * @param tables Comma separated string of relation table references in the form `<table_name>:<fk_name>:<sort_col>`
378
376
  * @param editConfigs The theme editConfig block, containing all theme dataset edit configs
379
377
  * @param callback Callback invoked with the relation values, taking `{<tablename>: {<relation_values>}}` on success and `{}` on failure
380
378
  */
381
- getRelations: function getRelations(editConfig, featureId, mapCrs, tables, editConfigs, callback) {
379
+ getRelations: function getRelations(tables, mapCrs, editConfigs, callback) {
382
380
  var editServiceUrl = ConfigUtils.getConfigProp("editServiceUrl").replace(/\/$/, '');
383
- var req = editServiceUrl + '/' + editConfig.editDataset + '/' + featureId + "/relations";
381
+ var req = editServiceUrl + '/relations';
384
382
  var params = {
385
- tables: tables,
383
+ tables: JSON.stringify(tables),
386
384
  crs: mapCrs
387
385
  };
388
386
  var headers = {