qwc2 2026.5.27 → 2026.6.3

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 (51) hide show
  1. package/actions/theme.js +4 -8
  2. package/components/ImportLayer.js +2 -3
  3. package/components/QtDesignerForm.js +18 -1
  4. package/components/StandardApp.js +3 -10
  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/SearchBox.css +0 -4
  9. package/components/style/ThemeList.css +8 -0
  10. package/package.json +1 -1
  11. package/plugins/BackgroundSwitcher.js +1 -1
  12. package/plugins/Bookmark.js +271 -57
  13. package/plugins/BottomBar.js +5 -49
  14. package/plugins/Editing.js +2 -1
  15. package/plugins/Portal.js +2 -2
  16. package/plugins/Settings.js +48 -27
  17. package/plugins/map3d/BottomBar3D.js +90 -13
  18. package/plugins/map3d/LayerTree3D.js +10 -3
  19. package/plugins/map3d/TopBar3D.js +1 -1
  20. package/plugins/map3d/style/BottomBar3D.css +6 -0
  21. package/plugins/style/OverviewMap.css +3 -0
  22. package/static/translations/bg-BG.json +2 -15
  23. package/static/translations/ca-ES.json +2 -15
  24. package/static/translations/cs-CZ.json +2 -15
  25. package/static/translations/de-CH.json +2 -15
  26. package/static/translations/de-DE.json +2 -15
  27. package/static/translations/en-US.json +2 -15
  28. package/static/translations/es-ES.json +2 -15
  29. package/static/translations/fi-FI.json +2 -15
  30. package/static/translations/fr-FR.json +2 -15
  31. package/static/translations/hu-HU.json +2 -15
  32. package/static/translations/it-IT.json +2 -15
  33. package/static/translations/ja-JP.json +2 -15
  34. package/static/translations/nl-NL.json +2 -15
  35. package/static/translations/no-NO.json +2 -15
  36. package/static/translations/pl-PL.json +2 -15
  37. package/static/translations/pt-BR.json +2 -15
  38. package/static/translations/pt-PT.json +2 -15
  39. package/static/translations/ro-RO.json +2 -15
  40. package/static/translations/ru-RU.json +2 -15
  41. package/static/translations/sv-SE.json +2 -15
  42. package/static/translations/tr-TR.json +2 -15
  43. package/static/translations/tsconfig.json +2 -13
  44. package/static/translations/uk-UA.json +2 -15
  45. package/utils/PermaLinkUtils.js +22 -31
  46. package/actions/bookmark.js +0 -40
  47. package/components/BookmarkPanel.js +0 -307
  48. package/components/widgets/GroupSelect.js +0 -94
  49. package/plugins/VisibilityPreset.js +0 -127
  50. package/reducers/bookmark.js +0 -39
  51. /package/{components/style/BookmarkPanel.css → plugins/style/Bookmark.css} +0 -0
package/actions/theme.js CHANGED
@@ -33,7 +33,7 @@ import MapUtils from '../utils/MapUtils';
33
33
  import { UrlParams } from '../utils/PermaLinkUtils';
34
34
  import ServiceLayerUtils from '../utils/ServiceLayerUtils';
35
35
  import ThemeUtils from '../utils/ThemeUtils';
36
- import { LayerRole, addLayer, removeLayer, removeAllLayers, replacePlaceholderLayer, setSwipe, setThemeLayersVisibilityPreset } from './layers';
36
+ import { LayerRole, addLayer, removeLayer, removeAllLayers, replacePlaceholderLayer, setSwipe } from './layers';
37
37
  import { configureMap } from './map';
38
38
  import { showNotification, NotificationType } from './windows';
39
39
  export var THEMES_LOADED = 'THEMES_LOADED';
@@ -51,7 +51,7 @@ export function setThemeLayersList(theme) {
51
51
  themelist: theme
52
52
  };
53
53
  }
54
- export function finishThemeSetup(dispatch, theme, themes, layerConfigs, insertPos, permalinkLayers, externalLayerRestorer, visibleBgLayer, initialTheme, initialTask, initialVisibilityPreset) {
54
+ export function finishThemeSetup(dispatch, theme, themes, layerConfigs, insertPos, permalinkLayers, externalLayerRestorer, visibleBgLayer, initialTheme, initialTask) {
55
55
  var _theme$config$section, _theme$config, _theme$config2;
56
56
  // Create layer
57
57
  var themeLayer = ThemeUtils.createThemeLayer(theme, themes);
@@ -143,9 +143,6 @@ export function finishThemeSetup(dispatch, theme, themes, layerConfigs, insertPo
143
143
  type: SET_CURRENT_THEME,
144
144
  theme: theme
145
145
  });
146
- if (initialVisibilityPreset) {
147
- dispatch(setThemeLayersVisibilityPreset(initialVisibilityPreset));
148
- }
149
146
  var section = ConfigUtils.isMobile() ? "mobile" : "desktop";
150
147
  var task = initialTask || ((_theme$config$section = theme === null || theme === void 0 || (_theme$config = theme.config) === null || _theme$config === void 0 || (_theme$config = _theme$config[section]) === null || _theme$config === void 0 ? void 0 : _theme$config.startupTask) !== null && _theme$config$section !== void 0 ? _theme$config$section : theme === null || theme === void 0 || (_theme$config2 = theme.config) === null || _theme$config2 === void 0 ? void 0 : _theme$config2.startupTask) || (initialTheme ? ConfigUtils.getConfigProp("startupTask") : null);
151
148
  if (task) {
@@ -162,7 +159,6 @@ export function setCurrentTheme(theme, themes) {
162
159
  var themeLayerRestorer = arguments.length > 7 && arguments[7] !== undefined ? arguments[7] : null;
163
160
  var externalLayerRestorer = arguments.length > 8 && arguments[8] !== undefined ? arguments[8] : null;
164
161
  var initialTask = arguments.length > 9 && arguments[9] !== undefined ? arguments[9] : null;
165
- var initialVisibilityPreset = arguments.length > 10 && arguments[10] !== undefined ? arguments[10] : null;
166
162
  return function (dispatch, getState) {
167
163
  var _getState$layers, _ref, _theme$mapTips;
168
164
  var curLayers = ((_getState$layers = getState().layers) === null || _getState$layers === void 0 ? void 0 : _getState$layers.flat) || [];
@@ -311,13 +307,13 @@ export function setCurrentTheme(theme, themes) {
311
307
  dispatch(showNotification("missinglayers", LocaleUtils.tr("app.missinglayers", diff.join(", ")), NotificationType.WARN, true));
312
308
  }
313
309
  }
314
- finishThemeSetup(dispatch, newTheme, themes, layerConfigs, insertPos, permalinkLayers, externalLayerRestorer, visibleBgLayer, initialTheme, initialTask, initialVisibilityPreset);
310
+ finishThemeSetup(dispatch, newTheme, themes, layerConfigs, insertPos, permalinkLayers, externalLayerRestorer, visibleBgLayer, initialTheme, initialTask);
315
311
  });
316
312
  } else {
317
313
  if (!isEmpty(missingThemeLayers)) {
318
314
  dispatch(showNotification("missinglayers", LocaleUtils.tr("app.missinglayers", Object.keys(missingThemeLayers).join(", ")), NotificationType.WARN, true));
319
315
  }
320
- finishThemeSetup(dispatch, theme, themes, layerConfigs, insertPos, permalinkLayers, externalLayerRestorer, visibleBgLayer, initialTheme, initialTask, initialVisibilityPreset);
316
+ finishThemeSetup(dispatch, theme, themes, layerConfigs, insertPos, permalinkLayers, externalLayerRestorer, visibleBgLayer, initialTheme, initialTask);
321
317
  }
322
318
  };
323
319
  }
@@ -38,7 +38,6 @@ import React from 'react';
38
38
  import { connect } from 'react-redux';
39
39
  import axios from 'axios';
40
40
  import isEmpty from 'lodash.isempty';
41
- import { WorkerMessageHandler } from "pdfjs-dist/build/pdf.worker";
42
41
  import Proj4js from 'proj4';
43
42
  import PropTypes from 'prop-types';
44
43
  import { addLayer, addLayerFeatures } from '../actions/layers';
@@ -439,8 +438,8 @@ var ImportLayer = /*#__PURE__*/function (_React$Component) {
439
438
  var tr = computeCorner(idxTR);
440
439
  var geoextent = [bl.coo[0], bl.coo[1], tr.coo[0], tr.coo[1]];
441
440
  var imgextent = [bl.pixel[0], bl.pixel[1], tr.pixel[0], tr.pixel[1]];
442
- import('pdfjs-dist/build/pdf').then(function (pdfjsLib) {
443
- pdfjsLib.GlobalWorkerOptions.workerSrc = WorkerMessageHandler;
441
+ import('pdfjs-dist').then(function (pdfjsLib) {
442
+ pdfjsLib.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString();
444
443
  pdfjsLib.getDocument(ev.target.result).promise.then(function (pdf) {
445
444
  pdf.getPage(1).then(function (page) {
446
445
  var pageViewport = page.getViewport({
@@ -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;
@@ -40,7 +40,6 @@ import deepmerge from 'deepmerge';
40
40
  import { register as olProj4Register } from 'ol/proj/proj4';
41
41
  import Proj4js from 'proj4';
42
42
  import PropTypes from 'prop-types';
43
- import { refreshBookmarks, refreshVisibilityPresets } from '../actions/bookmark';
44
43
  import { localConfigLoaded, setStartupParameters, setColorScheme } from '../actions/localConfig';
45
44
  import { changeLocale } from '../actions/locale';
46
45
  import { setCurrentTask } from '../actions/task';
@@ -164,7 +163,7 @@ var AppContainerComponent = /*#__PURE__*/function (_React$Component) {
164
163
  layerParams.reverse();
165
164
  }
166
165
  var initialTaskParam = params.task ? JSON.parse(decodeURIComponent(params.task)) : null;
167
- _this.props.setCurrentTheme(theme, themes, false, initialExtent, layerParams, (_params$bl = params.bl) !== null && _params$bl !== void 0 ? _params$bl : null, state.layers, _this.props.appConfig.themeLayerRestorer, _this.props.appConfig.externalLayerRestorer, initialTaskParam, state.visibilityPreset);
166
+ _this.props.setCurrentTheme(theme, themes, false, initialExtent, layerParams, (_params$bl = params.bl) !== null && _params$bl !== void 0 ? _params$bl : null, state.layers, _this.props.appConfig.themeLayerRestorer, _this.props.appConfig.externalLayerRestorer, initialTaskParam);
168
167
  } else if (!ConfigUtils.havePlugin("Portal")) {
169
168
  _this.props.showNotification("missingdefaulttheme", LocaleUtils.tr("app.missingdefaulttheme", params.t), NotificationType.WARN, true);
170
169
  }
@@ -205,7 +204,6 @@ var AppContainerComponent = /*#__PURE__*/function (_React$Component) {
205
204
  }(React.Component);
206
205
  _defineProperty(AppContainerComponent, "propTypes", {
207
206
  appConfig: PropTypes.object,
208
- currentTheme: PropTypes.object,
209
207
  defaultUrlParams: PropTypes.string,
210
208
  haveMapSize: PropTypes.bool,
211
209
  localConfig: PropTypes.object,
@@ -213,7 +211,6 @@ _defineProperty(AppContainerComponent, "propTypes", {
213
211
  setBottombarHeight: PropTypes.func,
214
212
  setCurrentTask: PropTypes.func,
215
213
  setCurrentTheme: PropTypes.func,
216
- setThemeLayersVisibilityPreset: PropTypes.func,
217
214
  setTopbarHeight: PropTypes.func,
218
215
  showNotification: PropTypes.func,
219
216
  startupConfig: PropTypes.object,
@@ -268,7 +265,7 @@ var StandardApp = /*#__PURE__*/function (_React$Component2) {
268
265
  return res;
269
266
  }, {});
270
267
  ConfigUtils.loadConfiguration(configParams).then(function (config) {
271
- 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;
272
269
  // Merge common config into mobile/desktop config, merge config from appConfig
273
270
  var renameTaskButtons = function renameTaskButtons(res, entry) {
274
271
  var _entry$cfg$task, _entry$cfg;
@@ -321,7 +318,7 @@ var StandardApp = /*#__PURE__*/function (_React$Component2) {
321
318
  });
322
319
 
323
320
  // Load locale
324
- 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;
325
322
  LocaleUtils.loadLocale(lang, _this2.props.appConfig.defaultLocaleData).then(function (localeData) {
326
323
  StandardApp.store.dispatch(changeLocale(localeData, _this2.props.appConfig.defaultLocaleData));
327
324
  _this2.setState({
@@ -334,10 +331,6 @@ var StandardApp = /*#__PURE__*/function (_React$Component2) {
334
331
  var colorScheme = initialParams.style || storedColorScheme || ConfigUtils.getConfigProp("defaultColorScheme");
335
332
  StandardApp.store.dispatch(setColorScheme(colorScheme));
336
333
 
337
- // Load all bookmarks & visiblity presets
338
- StandardApp.store.dispatch(refreshBookmarks());
339
- StandardApp.store.dispatch(refreshVisibilityPresets());
340
-
341
334
  // Resolve permalink and restore settings
342
335
  resolvePermaLink(initialParams, function (params, state, success) {
343
336
  StandardApp.store.dispatch(setStartupParameters(params, state));
@@ -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;
@@ -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
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "qwc2",
3
- "version": "2026.05.27",
3
+ "version": "2026.06.03",
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