qwc2 2026.7.1 → 2026.7.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/actions/theme.js CHANGED
@@ -63,6 +63,16 @@ export function finishThemeSetup(dispatch, theme, themes, layerConfigs, preserve
63
63
  return layer.role === LayerRole.BACKGROUND && layer.visibility === true;
64
64
  })) === null || _prevLayers$find === void 0 ? void 0 : _prevLayers$find.name) !== null && _prevLayers$find$name !== void 0 ? _prevLayers$find$name : null;
65
65
  }
66
+ // Create theme background layers
67
+ var bgLayers = ThemeUtils.createThemeBackgroundLayers(theme.backgroundLayers || [], themes, visibleBgLayer, externalLayers);
68
+ var actuallyVisibleBgLayer = (_bgLayers$find = bgLayers.find(function (entry) {
69
+ return entry.visibility;
70
+ })) === null || _bgLayers$find === void 0 ? void 0 : _bgLayers$find.name;
71
+ if (!prevTheme && visibleBgLayer && actuallyVisibleBgLayer !== visibleBgLayer) {
72
+ dispatch(showNotification("missingbglayer", LocaleUtils.tr("app.missingbg", visibleBgLayer), NotificationType.WARN, true));
73
+ } else if (actuallyVisibleBgLayer !== visibleBgLayer) {
74
+ visibleBgLayer = null;
75
+ }
66
76
 
67
77
  // Remove old layers
68
78
  var preserveUserLayers = preserve && ConfigUtils.getConfigProp("preserveNonThemeLayersOnThemeSwitch", theme) === true;
@@ -101,24 +111,16 @@ export function finishThemeSetup(dispatch, theme, themes, layerConfigs, preserve
101
111
  }
102
112
 
103
113
  // Add background layers for theme
104
- var bgLayers = ThemeUtils.createThemeBackgroundLayers(theme.backgroundLayers || [], themes, visibleBgLayer, externalLayers);
105
- var actuallyVisibleBgLayer = (_bgLayers$find = bgLayers.find(function (entry) {
106
- return entry.visibility;
107
- })) === null || _bgLayers$find === void 0 ? void 0 : _bgLayers$find.name;
108
- if (!prevTheme && visibleBgLayer && actuallyVisibleBgLayer !== visibleBgLayer) {
109
- dispatch(showNotification("missingbglayer", LocaleUtils.tr("app.missingbg", visibleBgLayer), NotificationType.WARN, true));
110
- }
111
114
  var _iterator = _createForOfIteratorHelper(bgLayers.reverse()),
112
115
  _step;
113
116
  try {
114
117
  for (_iterator.s(); !(_step = _iterator.n()).done;) {
115
118
  var bgLayer = _step.value;
116
119
  // If previous visible BG layer kept, insert other BG layers around that layer
117
- if (bgLayer.name === visibleBgLayer && bgLayerKept) {
118
- bgLayerKept = false;
119
- } else {
120
- dispatch(addLayer(bgLayer, bgLayerKept ? 1 : 0));
120
+ if (!(bgLayer.name === visibleBgLayer && bgLayerKept)) {
121
+ dispatch(addLayer(bgLayer, insPos));
121
122
  }
123
+ ++insPos;
122
124
  }
123
125
  } catch (err) {
124
126
  _iterator.e(err);
@@ -133,7 +135,7 @@ export function finishThemeSetup(dispatch, theme, themes, layerConfigs, preserve
133
135
  try {
134
136
  for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
135
137
  var layer = _step2.value;
136
- dispatch(addLayer(layer, insPos));
138
+ dispatch(addLayer(layer));
137
139
  }
138
140
 
139
141
  // Restore external layers
@@ -138,6 +138,7 @@ var AttributeForm = /*#__PURE__*/function (_React$Component) {
138
138
  finished: _this.state.childEdit.finishCallback,
139
139
  iface: _this.props.iface,
140
140
  mapPrefix: _this.props.editContext.mapPrefix,
141
+ parentContextId: _this.props.editContext.id,
141
142
  pickFilter: _this.props.childPickFilter,
142
143
  readOnly: _this.props.readOnly,
143
144
  translations: _this.props.translations
@@ -102,6 +102,7 @@ var EditComboField = /*#__PURE__*/function (_React$Component) {
102
102
  return _this.props.updateField(_this.props.fieldId, value);
103
103
  },
104
104
  placeholder: _this.state.showPlaceholder ? (_this$props$placehold = _this.props.placeholder) !== null && _this$props$placehold !== void 0 ? _this$props$placehold : LocaleUtils.tr("common.select") : undefined,
105
+ readOnly: _this.props.readOnly,
105
106
  required: _this.props.required,
106
107
  style: _this.props.style,
107
108
  value: String(_this.props.value)
@@ -47,10 +47,12 @@ var ExportSelection = /*#__PURE__*/function (_React$Component) {
47
47
  }
48
48
  var startStateX = _this.state.x;
49
49
  var startStateY = _this.state.y;
50
+ var maxWidth = ev.target.parentElement.offsetWidth - _this.state.width;
51
+ var maxHeight = ev.target.parentElement.offsetHeight - _this.state.height;
50
52
  var onMouseMove = function onMouseMove(event) {
51
53
  _this.setState({
52
- x: startStateX + event.clientX - ev.clientX,
53
- y: startStateY + event.clientY - ev.clientY
54
+ x: Math.max(0, Math.min(maxWidth, startStateX + event.clientX - ev.clientX)),
55
+ y: Math.max(0, Math.min(maxHeight, startStateY + event.clientY - ev.clientY))
54
56
  });
55
57
  };
56
58
  ev.view.addEventListener('pointermove', onMouseMove);
@@ -66,6 +68,8 @@ var ExportSelection = /*#__PURE__*/function (_React$Component) {
66
68
  if (ev.ctrlKey) {
67
69
  return;
68
70
  }
71
+ var maxWidth = ev.target.parentElement.parentElement.offsetWidth;
72
+ var maxHeight = ev.target.parentElement.parentElement.offsetHeight;
69
73
  var _this$state = _this.state,
70
74
  x = _this$state.x,
71
75
  y = _this$state.y,
@@ -92,6 +96,10 @@ var ExportSelection = /*#__PURE__*/function (_React$Component) {
92
96
  if (sy === 0) {
93
97
  newy += 0.5 * (height - newheight);
94
98
  }
99
+ if (newx < 0 || newy < 0 || newx + newwidth > maxWidth || newy + newheight > maxHeight) {
100
+ // Don't set new size if it would overflow the container
101
+ return;
102
+ }
95
103
  _this.setState({
96
104
  x: newx,
97
105
  y: newy,
@@ -119,7 +119,8 @@ var LinkFeatureForm = /*#__PURE__*/function (_React$Component) {
119
119
  feature: this.props.feature,
120
120
  geomType: this.props.editConfig.geomType,
121
121
  editConfig: this.props.editConfig,
122
- mapPrefix: this.props.mapPrefix
122
+ mapPrefix: this.props.mapPrefix,
123
+ parentContextId: this.props.parentContextId
123
124
  });
124
125
  } else {
125
126
  this.props.iface.getFeatureById(this.props.editConfig, this.props.featureId, this.props.map.projection, function (result) {
@@ -129,7 +130,8 @@ var LinkFeatureForm = /*#__PURE__*/function (_React$Component) {
129
130
  feature: result,
130
131
  geomType: _this2.props.editConfig.geomType,
131
132
  editConfig: _this2.props.editConfig,
132
- mapPrefix: _this2.props.mapPrefix
133
+ mapPrefix: _this2.props.mapPrefix,
134
+ parentContextId: _this2.props.parentContextId
133
135
  });
134
136
  }
135
137
  });
@@ -145,13 +147,15 @@ var LinkFeatureForm = /*#__PURE__*/function (_React$Component) {
145
147
  geomType: _this2.props.editConfig.geomType,
146
148
  feature: feature,
147
149
  editConfig: _this2.props.editConfig,
148
- mapPrefix: _this2.props.mapPrefix
150
+ mapPrefix: _this2.props.mapPrefix,
151
+ parentContextId: _this2.props.parentContextId
149
152
  });
150
153
  });
151
154
  } else if (this.props.action === 'Pick') {
152
155
  this.props.setEditContext(this.props.editContextId, {
153
156
  editConfig: this.props.editConfig,
154
- mapPrefix: this.props.mapPrefix
157
+ mapPrefix: this.props.mapPrefix,
158
+ parentContextId: this.props.parentContextId
155
159
  });
156
160
  }
157
161
  }
@@ -240,6 +244,7 @@ _defineProperty(LinkFeatureForm, "propTypes", {
240
244
  iface: PropTypes.object,
241
245
  map: PropTypes.object,
242
246
  mapPrefix: PropTypes.string,
247
+ parentContextId: PropTypes.string,
243
248
  pickFilter: PropTypes.func,
244
249
  readOnly: PropTypes.bool,
245
250
  removeLayer: PropTypes.func,
@@ -766,7 +766,7 @@ var QtDesignerForm = /*#__PURE__*/function (_React$Component) {
766
766
  _defineProperty(_this, "renderNRelation", function (widget) {
767
767
  var _widget$property2, _editConfig$fields, _this$props$feature$r;
768
768
  var parts = widget.name.split("__");
769
- if (parts.length < 3) {
769
+ if (parts.length < 3 || !widget.layout) {
770
770
  return null;
771
771
  }
772
772
  var disabled = String((_widget$property2 = widget.property) === null || _widget$property2 === void 0 ? void 0 : _widget$property2.enabled) === "false";
@@ -56,7 +56,7 @@ var OrbitControls3D = /*#__PURE__*/function (_MapControls) {
56
56
  _this.enableDamping = true;
57
57
  _this.dampingFactor = 0.2;
58
58
  _this.keyPanSpeed = 10.0;
59
- _this.maxPolarAngle = Math.PI * 0.5;
59
+ _this.maxPolarAngle = 89 / 180 * Math.PI;
60
60
  _this.mouseButtons = mouseButtons;
61
61
  _this.zoomSpeed = 5;
62
62
  return _this;
@@ -65,10 +65,9 @@ var OrbitControls3D = /*#__PURE__*/function (_MapControls) {
65
65
  return _createClass(OrbitControls3D, [{
66
66
  key: "connect",
67
67
  value: function connect(sceneContext) {
68
- this.domElement = sceneContext.scene.domElement;
69
68
  this.sceneContext = sceneContext;
70
69
  this.enabled = true;
71
- _superPropGet(OrbitControls3D, "connect", this, 3)([]);
70
+ _superPropGet(OrbitControls3D, "connect", this, 3)([sceneContext.scene.domElement]);
72
71
  this.listenToKeyEvents(this.domElement);
73
72
  this.domElement.addEventListener('pointerdown', this.stopAnimations);
74
73
  this.domElement.addEventListener('wheel', this.stopAnimations);
@@ -45,6 +45,22 @@ var LayerCatalogWidget = /*#__PURE__*/function (_React$PureComponent) {
45
45
  filteredCatalog: null,
46
46
  filter: ""
47
47
  });
48
+ _defineProperty(_this, "entryClicked", function (entry, path) {
49
+ if (entry.type || entry.resource) {
50
+ var _entry$resource;
51
+ if (entry.asGroup === true && ((_entry$resource = entry.resource) !== null && _entry$resource !== void 0 ? _entry$resource : entry.type).startsWith("wms")) {
52
+ if (!isEmpty(entry.sublayers) && entry.resource) {
53
+ _this.checkAddGroup(entry);
54
+ } else {
55
+ _this.checkAddServiceLayer(entry, true);
56
+ }
57
+ } else {
58
+ _this.checkAddServiceLayer(entry, false);
59
+ }
60
+ } else {
61
+ _this.toggleLayerListEntry(path);
62
+ }
63
+ });
48
64
  _defineProperty(_this, "toggleLayerListEntry", function (path) {
49
65
  _this.setState(function (state) {
50
66
  var catalogKey = _this.state.filteredCatalog ? "filteredCatalog" : "catalog";
@@ -135,8 +151,50 @@ var LayerCatalogWidget = /*#__PURE__*/function (_React$PureComponent) {
135
151
  _this.addServiceLayer(entry, resource, asGroup);
136
152
  }
137
153
  });
154
+ _defineProperty(_this, "checkAddGroup", function (group) {
155
+ // Collect sublayers
156
+ var sublayers = {};
157
+ var stripQuery = function stripQuery(url) {
158
+ return (url !== null && url !== void 0 ? url : "").split("?")[0];
159
+ };
160
+ var resource = LayerUtils.splitLayerUrlParam(group.resource);
161
+ var groupUrl = stripQuery(resource.url);
162
+ var _collectSublayers = function collectSublayers(entry) {
163
+ var _entry$resource2;
164
+ var entryParams = LayerUtils.splitLayerUrlParam((_entry$resource2 = entry.resource) !== null && _entry$resource2 !== void 0 ? _entry$resource2 : "");
165
+ if (stripQuery(entryParams.url) === groupUrl) {
166
+ sublayers[entryParams.name] = entryParams;
167
+ }
168
+ (entry.sublayers || []).forEach(_collectSublayers);
169
+ };
170
+ _collectSublayers(group);
171
+ // Check if one or more sublayers are already in the map
172
+ var existingSublayers = _this.props.layers.reduce(function (res, layer) {
173
+ if (layer.type === "wms" && stripQuery(layer.url) === stripQuery(groupUrl)) {
174
+ return [].concat(_toConsumableArray(res), _toConsumableArray(LayerUtils.getSublayerNames(layer)), [layer.name]);
175
+ }
176
+ return res;
177
+ }, []);
178
+ var overlappingSublayers = Object.keys(sublayers).filter(function (name) {
179
+ return existingSublayers.includes(name);
180
+ });
181
+ if (!isEmpty(overlappingSublayers)) {
182
+ var text = LocaleUtils.tr("themelayerslist.existinglayers") + ": " + overlappingSublayers.join(", ");
183
+ var actions = [{
184
+ name: LocaleUtils.tr("themelayerslist.addanyway"),
185
+ onClick: function onClick() {
186
+ _this.addServiceLayer(group, resource, true, sublayers);
187
+ return true;
188
+ }
189
+ }];
190
+ _this.props.showNotification("existinglayers", text, NotificationType.INFO, false, actions);
191
+ } else {
192
+ _this.addServiceLayer(group, resource, true, sublayers);
193
+ }
194
+ });
138
195
  _defineProperty(_this, "addServiceLayer", function (entry, resource) {
139
196
  var asGroup = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
197
+ var sublayerSubset = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : null;
140
198
  _this.props.closeWindow("existinglayers");
141
199
  if (resource) {
142
200
  var _entry$title2;
@@ -151,8 +209,21 @@ var LayerCatalogWidget = /*#__PURE__*/function (_React$PureComponent) {
151
209
  });
152
210
  ServiceLayerUtils.findLayers(resource.type, resource.url, [resource], _this.props.mapCrs, function (id, layer) {
153
211
  if (layer) {
154
- if (entry.sublayers === false || !asGroup) {
212
+ if (!asGroup) {
155
213
  layer.sublayers = null;
214
+ } else if (sublayerSubset) {
215
+ var _filterSublayers = function filterSublayers(sublayers) {
216
+ return sublayers.map(function (sublayer) {
217
+ if (sublayer.sublayers) {
218
+ return _filterSublayers(sublayer.sublayers);
219
+ } else if (sublayer.name in sublayerSubset) {
220
+ return _objectSpread(_objectSpread({}, sublayer), sublayerSubset);
221
+ } else {
222
+ return null;
223
+ }
224
+ }).filter(Boolean);
225
+ };
226
+ layer.sublayers = _filterSublayers(layer.sublayers);
156
227
  }
157
228
  LayerUtils.propagateLayerProperty(layer, "opacity", resource.opacity);
158
229
  _this.props.replacePlaceholderLayer(resource.id, layer);
@@ -202,7 +273,9 @@ var LayerCatalogWidget = /*#__PURE__*/function (_React$PureComponent) {
202
273
  }, {
203
274
  key: "renderCatalogEntry",
204
275
  value: function renderCatalogEntry(entry, path) {
205
- var _this2 = this;
276
+ var _this2 = this,
277
+ _ref2,
278
+ _entry$resource3;
206
279
  var level = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0;
207
280
  var idx = arguments.length > 3 ? arguments[3] : undefined;
208
281
  var hasSublayers = !isEmpty(entry.sublayers);
@@ -229,16 +302,16 @@ var LayerCatalogWidget = /*#__PURE__*/function (_React$PureComponent) {
229
302
  }), /*#__PURE__*/React.createElement("span", {
230
303
  className: "layer-catalog-widget-entry-contents",
231
304
  onClick: function onClick() {
232
- return type ? _this2.checkAddServiceLayer(entry, !hasSublayers) : _this2.toggleLayerListEntry(path);
305
+ return _this2.entryClicked(entry, path);
233
306
  },
234
307
  onKeyDown: MiscUtils.checkKeyActivate,
235
308
  tabIndex: 0
236
309
  }, type ? /*#__PURE__*/React.createElement("span", {
237
310
  className: "layer-catalog-widget-entry-service"
238
- }, type) : null, entry.title), hasSublayers && type === "wms" ? /*#__PURE__*/React.createElement(Icon, {
311
+ }, type) : null, entry.title), (hasSublayers && !entry.asGroup || entry.asGroup === "option") && ((_ref2 = (_entry$resource3 = entry.resource) !== null && _entry$resource3 !== void 0 ? _entry$resource3 : entry.type) !== null && _ref2 !== void 0 ? _ref2 : "").startsWith("wms") ? /*#__PURE__*/React.createElement(Icon, {
239
312
  icon: "group",
240
313
  onClick: function onClick() {
241
- return _this2.checkAddServiceLayer(entry, true);
314
+ return hasSublayers && entry.resource ? _this2.checkAddGroup(entry) : _this2.checkAddServiceLayer(entry, true);
242
315
  },
243
316
  title: LocaleUtils.tr("importlayer.asgroup")
244
317
  }) : null, entry.link ? /*#__PURE__*/React.createElement(Icon, {
@@ -248,11 +248,11 @@ var TextInput = /*#__PURE__*/function (_React$Component) {
248
248
  var wrapperClassName = classNames({
249
249
  "TextInput": true,
250
250
  "text-input-wrapper": true,
251
- "text-input-wrapper-multiline": this.props.multiline,
252
251
  "text-input-wrapper-focused": this.state.focus
253
252
  });
254
253
  var preClassName = classNames({
255
254
  "text-input": true,
255
+ "text-input-multiline": this.props.multiline,
256
256
  "text-input-disabled": this.props.disabled,
257
257
  "text-input-readonly": this.props.readOnly || !this.state.curValue,
258
258
  "text-input-invalid": this.props.required && !this.state.curValue
@@ -38,9 +38,11 @@ pre.text-input {
38
38
  flex: 1 1 auto;
39
39
  }
40
40
 
41
-
42
- text-input-wrapper-multiline > pre.text-input {
41
+ pre.text-input.text-input-multiline {
42
+ overflow-x: hidden;
43
43
  white-space: pre-wrap;
44
+ overflow-wrap: break-word;
45
+ word-break: break-word;
44
46
  }
45
47
 
46
48
  pre.text-input[contenteditable="true"] a {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwc2",
3
- "version": "2026.07.01",
3
+ "version": "2026.07.08",
4
4
  "description": "QGIS Web Client",
5
5
  "author": "Sourcepole AG",
6
6
  "license": "BSD-2-Clause",
@@ -389,7 +389,7 @@ var FeatureSearch = /*#__PURE__*/function (_React$Component) {
389
389
  var defaultProvider = '';
390
390
  var providerGroups = {};
391
391
  var searchProviders = (((_this$props$theme = this.props.theme) === null || _this$props$theme === void 0 ? void 0 : _this$props$theme.searchProviders) || []).reduce(function (res, entry) {
392
- if (entry.provider === "qgis" && entry.params) {
392
+ if (entry.provider === "qgis" && entry.params && entry.params.featuresearch !== false) {
393
393
  var providerDef = _objectSpread({}, entry);
394
394
  if (!providerDef.params.fields) {
395
395
  providerDef.params = _objectSpread({}, providerDef.params);
@@ -38,8 +38,11 @@ import './style/LayerCatalog.css';
38
38
  *
39
39
  * Configured through a catalog JSON containing a tree of external layer identifiers.
40
40
  *
41
- * For `wms` layers, `sublayers: false` denotes that the sublayer structure of the added layer should not
42
- * be exposed in the layer tree.
41
+ * For catalog entries containing a `wms` resource, you can specify `"asGroup": <true|false|"option">`, which behaves as follows:
42
+ *
43
+ * * `false`: imports the layer as a flat layer, without sublayer structure. This is the default behaviour for entries without sublayers if `asGroup` is not specified.
44
+ * * `true`: imports the layer as a group, with sublayer structure. If the catalog entry has sublayers, the sublayer structure will be filtered to only include these sublayers.
45
+ * * `"option"`: imports the layer as a flat layer when clicking on the catalog entry, but displays an icon to optionally import the layer as a group layer. This is the default behaviour for entries with sublayers if `asGroup` is not specified.
43
46
  *
44
47
  * Example:
45
48
  * ```json
@@ -48,11 +51,11 @@ import './style/LayerCatalog.css';
48
51
  * {
49
52
  * "title": "Öffentlicher Verkehr swissTLMRegio",
50
53
  * "resource": "wms:http://wms.geo.admin.ch#ch.swisstopo.vec200-transportation-oeffentliche-verkehr",
51
- * "sublayers": false
54
+ * "asGroup": true
52
55
  * },
53
56
  * {
54
57
  * "title": "Gewässerschutz",
55
- * "resource": "wms:https://geo.so.ch/api/wms#ch.so.afu.gewaesserschutz[50]"
58
+ * "resource": "wms:https://geo.so.ch/api/wms#ch.so.afu.gewaesserschutz[50]"
56
59
  * },
57
60
  * {
58
61
  * "title": "Landeskarten",
@@ -66,6 +69,19 @@ import './style/LayerCatalog.css';
66
69
  * "resource": "wms:http://wms.geo.admin.ch#ch.swisstopo.pixelkarte-farbe-pk100.noscale"
67
70
  * }
68
71
  * ]
72
+ * },
73
+ * {
74
+ * "title": "Edit Demo",
75
+ * "resource": "wms:https://demo.qwc.app/ows/qwc_demo#edit_demo",
76
+ * "sublayers": [{
77
+ * "title": "Edit Points",
78
+ * "resource": "wms:https://demo.qwc.app/ows/qwc_demo#edit_points"
79
+ * },
80
+ * {
81
+ * "title": "Edit Lines",
82
+ * "resource": "wms:https://demo.qwc.app/ows/qwc_demo#edit_lines"
83
+ * }],
84
+ * "asGroup": "option"
69
85
  * }
70
86
  * ]
71
87
  * }
@@ -407,6 +407,17 @@ var ThemeBrowser = /*#__PURE__*/function (_React$Component) {
407
407
  });
408
408
  this.props.setCurrentTask(null);
409
409
  }
410
+ var width = this.maxLayerTitleLength + "px";
411
+ if (this.props.fillIfWiderThanPerc && this.maxLayerTitleLength > window.innerWidth * this.props.fillIfWiderThanPerc / 100) {
412
+ width = '100%';
413
+ }
414
+ this.measureCanvas = undefined;
415
+ this.measureContext = undefined;
416
+ if (width !== this.state.width) {
417
+ this.setState({
418
+ width: width
419
+ });
420
+ }
410
421
  }
411
422
  }, {
412
423
  key: "render",
@@ -429,17 +440,6 @@ var ThemeBrowser = /*#__PURE__*/function (_React$Component) {
429
440
  className: "themebrowser-body",
430
441
  role: "body"
431
442
  }, this.renderThemes(this.props.themes)));
432
- var width = this.maxLayerTitleLength + "px";
433
- if (this.props.fillIfWiderThanPerc && this.maxLayerTitleLength > window.innerWidth * this.props.fillIfWiderThanPerc / 100) {
434
- width = '100%';
435
- }
436
- this.measureCanvas = undefined;
437
- this.measureContext = undefined;
438
- if (width !== this.state.width) {
439
- this.setState({
440
- width: width
441
- });
442
- }
443
443
  return result;
444
444
  }
445
445
  }]);
@@ -227,7 +227,7 @@ var TimeManager = /*#__PURE__*/function (_React$Component) {
227
227
  }, LocaleUtils.tr("timemanager.displayfeatures")), /*#__PURE__*/React.createElement("option", {
228
228
  value: "layers"
229
229
  }, LocaleUtils.tr("timemanager.displaylayers"))))) : null)));
230
- var timeSpan = _this.state.endTime !== null ? _this.state.endTime.diff(_this.state.startTime) : dayjs().diff(_this.state.startTime);
230
+ var timeSpan = _this.state.endTime.diff(_this.state.startTime);
231
231
  var Timeline = _this.state.timelineMode === 'infinite' ? InfiniteTimeline : FixedTimeline;
232
232
  var filterActive = !isEmpty(_this.props.filter.filterParams) || !!_this.props.filter.filterGeom;
233
233
  var startdate = _this.state.timeData.values.length > 0 ? _this.state.timeData.values[0].hour(0).minute(0).second(0) : null;
@@ -760,7 +760,7 @@ var TimeManager = /*#__PURE__*/function (_React$Component) {
760
760
  timeData: timeData,
761
761
  currentTimestamp: (_state$currentTimesta = state.currentTimestamp) !== null && _state$currentTimesta !== void 0 ? _state$currentTimesta : timeData.values.length > 0 ? +timeData.values[0] : null,
762
762
  startTime: startdate,
763
- endTime: enddate && enddate.year() !== DUMMY_END_DATE.getFullYear() ? enddate : null
763
+ endTime: enddate && enddate.year() !== DUMMY_END_DATE.getFullYear() ? enddate : dayjs()
764
764
  };
765
765
  });
766
766
  this.updateTimeFeatures(timeData);
@@ -784,7 +784,7 @@ var TimeManager = /*#__PURE__*/function (_React$Component) {
784
784
  }
785
785
  return {
786
786
  startTime: startdate,
787
- endTime: enddate && enddate.year() !== DUMMY_END_DATE.getFullYear() ? enddate : null
787
+ endTime: enddate && enddate.year() !== DUMMY_END_DATE.getFullYear() ? enddate : dayjs()
788
788
  };
789
789
  });
790
790
  }
@@ -96,6 +96,8 @@ var LayerTree3D = /*#__PURE__*/function (_React$Component) {
96
96
  return entry.sublayers.map(function (sublayer, idx) {
97
97
  return _this.renderLayerEntry(layerId, sublayer, entry, _this.updateColorLayer, false, true, [idx]);
98
98
  });
99
+ } else if (entry.role === LayerRole.THEME && showRootEntry && isEmpty(entry.sublayers)) {
100
+ return null;
99
101
  } else {
100
102
  return _this.renderLayerEntry(layerId, entry, null, _this.updateColorLayer, false, true, [], layersHaveSublayers);
101
103
  }
@@ -67,11 +67,12 @@ var MapExport3D = /*#__PURE__*/function (_React$Component) {
67
67
  _defineProperty(_this, "onShow", function () {
68
68
  var _this$props$theme;
69
69
  var rect = _this.props.sceneContext.scene.domElement.getBoundingClientRect();
70
+ var rectHeight = rect.height - _this.props.topbarHeight - _this.props.bottombarHeight;
70
71
  var frame = {
71
72
  x: 0.125 * rect.width,
72
- y: 0.125 * rect.height,
73
+ y: 0.125 * rectHeight,
73
74
  width: 0.75 * rect.width,
74
- height: 0.75 * rect.height
75
+ height: 0.75 * rectHeight
75
76
  };
76
77
  if (!isEmpty((_this$props$theme = _this.props.theme) === null || _this$props$theme === void 0 ? void 0 : _this$props$theme.print)) {
77
78
  var _ref, _this$props$theme$pri, _this$props$theme$pri2, _this$props$theme$pri3;
@@ -571,10 +572,12 @@ var MapExport3D = /*#__PURE__*/function (_React$Component) {
571
572
  }]);
572
573
  }(React.Component);
573
574
  _defineProperty(MapExport3D, "propTypes", {
575
+ bottombarHeight: PropTypes.number,
574
576
  hideAutopopulatedFields: PropTypes.bool,
575
577
  sceneContext: PropTypes.object,
576
578
  setCurrentTask: PropTypes.func,
577
- theme: PropTypes.object
579
+ theme: PropTypes.object,
580
+ topbarHeight: PropTypes.number
578
581
  });
579
582
  _defineProperty(MapExport3D, "defaultState", {
580
583
  minimized: false,
@@ -589,6 +592,8 @@ _defineProperty(MapExport3D, "defaultState", {
589
592
  });
590
593
  export default connect(function (state) {
591
594
  return {
595
+ topbarHeight: state.windows.topbarHeight,
596
+ bottombarHeight: state.windows.bottombarHeight,
592
597
  theme: state.theme.current
593
598
  };
594
599
  }, {
@@ -69,6 +69,18 @@ export default function editing() {
69
69
  contexts: _objectSpread({}, state.contexts),
70
70
  currentContext: state.currentContext === action.contextId ? action.newActiveContextId : state.currentContext
71
71
  };
72
+ var _clearChildContexts = function clearChildContexts(parentId) {
73
+ Object.values(newState.contexts).forEach(function (context) {
74
+ if (context.parentContextId === parentId) {
75
+ _clearChildContexts(context.id);
76
+ delete newState.contexts[context.id];
77
+ if (newState.currentContext === context.id) {
78
+ newState.currentContext = action.newActiveContextId;
79
+ }
80
+ }
81
+ });
82
+ };
83
+ _clearChildContexts(action.contextId);
72
84
  delete newState.contexts[action.contextId];
73
85
  return newState;
74
86
  }
@@ -424,7 +424,7 @@ var EditingInterface = {
424
424
  getKeyValues: function getKeyValues(keyvalues, callback) {
425
425
  var filter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
426
426
  var editServiceUrl = ConfigUtils.getConfigProp("editServiceUrl").replace(/\/$/, '');
427
- var req = editServiceUrl + '/' + "keyvals?tables=" + keyvalues;
427
+ var req = editServiceUrl + "/keyvals?tables=" + keyvalues;
428
428
  var params = {
429
429
  filter: filter ? JSON.stringify(filter) : undefined
430
430
  };