@vcmap/ui 6.1.0 → 6.1.2

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 (40) hide show
  1. package/build/bundle.js +3 -3
  2. package/dist/assets/cesium.js +1 -1
  3. package/dist/assets/{core-841b71a4.js → core-168c5f09.js} +1372 -1352
  4. package/dist/assets/core.js +1 -1
  5. package/dist/assets/ol.js +1 -1
  6. package/dist/assets/{ui-2fd6f47d.css → ui-e9b620ea.css} +1 -1
  7. package/dist/assets/{ui-2fd6f47d.js → ui-e9b620ea.js} +5065 -4996
  8. package/dist/assets/ui.js +1 -1
  9. package/dist/assets/vue.js +1 -1
  10. package/dist/assets/{vuetify-4bc77ff7.js → vuetify-43eef70b.js} +1 -1
  11. package/dist/assets/vuetify.js +1 -1
  12. package/index.d.ts +1 -1
  13. package/index.js +1 -0
  14. package/package.json +14 -6
  15. package/plugins/package.json +3 -1
  16. package/src/actions/actionHelper.js +8 -2
  17. package/src/actions/deepPickingAction.js +6 -1
  18. package/src/actions/extentActions.js +20 -6
  19. package/src/actions/flightActions.js +5 -1
  20. package/src/application/VcsApp.vue +30 -21
  21. package/src/callback/activateLayersCallback.js +9 -1
  22. package/src/callback/addModuleCallback.js +2 -1
  23. package/src/components/lists/VcsTreeview.vue +10 -1
  24. package/src/contentTree/layerGroupContentTreeItem.js +11 -1
  25. package/src/contentTree/wmsChildContentTreeItem.d.ts +1 -1
  26. package/src/contentTree/wmsChildContentTreeItem.js +2 -2
  27. package/src/contentTree/wmsGroupContentTreeItem.d.ts +5 -5
  28. package/src/contentTree/wmsGroupContentTreeItem.js +12 -11
  29. package/src/featureInfo/featureInfo.js +3 -1
  30. package/src/legend/legendHelper.d.ts +15 -0
  31. package/src/legend/legendHelper.js +28 -3
  32. package/src/manager/window/windowManager.js +5 -6
  33. package/src/navigation/overviewMap.js +1 -1
  34. package/src/search/ResultsComponent.vue +10 -1
  35. package/src/search/SearchComponent.vue +11 -6
  36. package/src/vcsUiApp.js +7 -1
  37. /package/dist/assets/{cesium-664ad022.js → cesium-7a85f591.js} +0 -0
  38. /package/dist/assets/{ol-2e095c08.js → ol-d8d681a6.js} +0 -0
  39. /package/dist/assets/{vue-71fd14e8.js → vue-139e9a39.js} +0 -0
  40. /package/dist/assets/{vuetify-4bc77ff7.css → vuetify-43eef70b.css} +0 -0
package/dist/assets/ui.js CHANGED
@@ -1 +1 @@
1
- export * from "./ui-2fd6f47d.js";
1
+ export * from "./ui-e9b620ea.js";
@@ -1 +1 @@
1
- export * from "./vue-71fd14e8.js";
1
+ export * from "./vue-139e9a39.js";
@@ -10,7 +10,7 @@ function loadCss(href) {
10
10
  elem.onerror = reject;
11
11
  document.head.appendChild(elem);
12
12
  });
13
- } await loadCss('./assets/vuetify-4bc77ff7.css');import { watch as Q, onScopeDispose as Ze, effectScope as Zl, shallowRef as K, Fragment as ie, reactive as it, computed as b, watchEffect as Fe, toRefs as Yt, capitalize as Nn, isVNode as Rc, Comment as Nc, unref as ot, warn as ja, getCurrentInstance as Hc, ref as j, provide as De, inject as ye, defineComponent as zc, camelize as Ir, h as Gt, toRaw as Be, createVNode as r, mergeProps as O, onBeforeUnmount as Qe, readonly as Ql, onDeactivated as _r, onActivated as Wc, onMounted as Ye, nextTick as we, TransitionGroup as Jl, Transition as jt, isRef as Tn, toRef as $, onBeforeMount as ra, withDirectives as $e, resolveDirective as gt, vShow as Ct, onUpdated as jc, Text as Uc, resolveDynamicComponent as Yc, markRaw as Gc, Teleport as Kc, cloneVNode as qc, createTextVNode as Tt, onUnmounted as Tr, onBeforeUpdate as Xc, withModifiers as Tl, toDisplayString as Zc, vModelText as Qc, resolveComponent as Jc, render as Ar } from "./vue-71fd14e8.js";
13
+ } await loadCss('./assets/vuetify-43eef70b.css');import { watch as Q, onScopeDispose as Ze, effectScope as Zl, shallowRef as K, Fragment as ie, reactive as it, computed as b, watchEffect as Fe, toRefs as Yt, capitalize as Nn, isVNode as Rc, Comment as Nc, unref as ot, warn as ja, getCurrentInstance as Hc, ref as j, provide as De, inject as ye, defineComponent as zc, camelize as Ir, h as Gt, toRaw as Be, createVNode as r, mergeProps as O, onBeforeUnmount as Qe, readonly as Ql, onDeactivated as _r, onActivated as Wc, onMounted as Ye, nextTick as we, TransitionGroup as Jl, Transition as jt, isRef as Tn, toRef as $, onBeforeMount as ra, withDirectives as $e, resolveDirective as gt, vShow as Ct, onUpdated as jc, Text as Uc, resolveDynamicComponent as Yc, markRaw as Gc, Teleport as Kc, cloneVNode as qc, createTextVNode as Tt, onUnmounted as Tr, onBeforeUpdate as Xc, withModifiers as Tl, toDisplayString as Zc, vModelText as Qc, resolveComponent as Jc, render as Ar } from "./vue-139e9a39.js";
14
14
  function rt(e, n) {
15
15
  let t;
16
16
  function a() {
@@ -1 +1 @@
1
- export * from "./vuetify-4bc77ff7.js";
1
+ export * from "./vuetify-43eef70b.js";
package/index.d.ts CHANGED
@@ -345,7 +345,7 @@ export { getProvidedFlightInstance, setupFlightAnchorEditingListener } from "./s
345
345
  export type * from "./src/components/flight/composables.d.ts";
346
346
  export { default as VcsFeatureEditingWindow, EditorTransformationIcons, getAllowedEditorTransformationModes } from "./src/components/vector-properties/VcsFeatureEditingWindow.vue";
347
347
  export type * from "./src/components/vector-properties/VcsFeatureEditingWindow.vue.d.ts";
348
- export { LegendType, StyleRowType, getLegendEntries } from "./src/legend/legendHelper.js";
348
+ export { legendSymbol, LegendType, StyleRowType, getLegendEntries } from "./src/legend/legendHelper.js";
349
349
  export type * from "./src/legend/legendHelper.d.ts";
350
350
 
351
351
  declare module 'vue' {
package/index.js CHANGED
@@ -362,6 +362,7 @@ export * from './src/components/attrsHelpers.js';
362
362
  export * from './src/components/modelHelper.js';
363
363
  export * from './src/components/composables.js';
364
364
  export {
365
+ legendSymbol,
365
366
  LegendType,
366
367
  StyleRowType,
367
368
  getLegendEntries,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcmap/ui",
3
- "version": "6.1.0",
3
+ "version": "6.1.2",
4
4
  "author": "Virtual City Systems",
5
5
  "license": "MIT",
6
6
  "scripts": {
@@ -57,7 +57,7 @@
57
57
  },
58
58
  "peerDependencies": {
59
59
  "@vcmap-cesium/engine": "^11.0.2",
60
- "@vcmap/core": "^6.1.1",
60
+ "@vcmap/core": "^6.1.3",
61
61
  "ol": "^10.4.0",
62
62
  "vue": "~3.4.38",
63
63
  "vuetify": "^3.7.14"
@@ -73,6 +73,7 @@
73
73
  "@vitest/coverage-v8": "^2.1.3",
74
74
  "@vue/test-utils": "^2.4.6",
75
75
  "eslint-import-resolver-alias": "^1.1.2",
76
+ "eslint-plugin-promise": "^7.2.1",
76
77
  "eslint-plugin-vuetify": "^2.4.0",
77
78
  "histoire": "^0.17.17",
78
79
  "jest-canvas-mock": "^2.5.2",
@@ -80,6 +81,7 @@
80
81
  "jsdoc-plugin-intersection": "^1.0.4",
81
82
  "jsdoc-plugin-typescript": "^2.2.1",
82
83
  "jsdom": "^25.0.1",
84
+ "nock": "^14.0.1",
83
85
  "resize-observer-polyfill": "1.5.1",
84
86
  "rollup-plugin-strip-pragma": "^1.0.0",
85
87
  "sass": "^1.80.2",
@@ -88,8 +90,7 @@
88
90
  "vite": "^5.4.9",
89
91
  "vite-plugin-vuetify": "^2.0.4",
90
92
  "vitest": "^2.1.3",
91
- "vue-tsc": "^2.1.6",
92
- "nock": "^14.0.1"
93
+ "vue-tsc": "^2.1.6"
93
94
  },
94
95
  "stylelint": {
95
96
  "extends": "stylelint-config-standard",
@@ -108,7 +109,8 @@
108
109
  "root": true,
109
110
  "extends": [
110
111
  "@vcsuite/eslint-config/vue",
111
- "plugin:vuetify/base"
112
+ "plugin:vuetify/base",
113
+ "plugin:promise/recommended"
112
114
  ],
113
115
  "settings": {
114
116
  "import/resolver": {
@@ -124,7 +126,13 @@
124
126
  },
125
127
  "rules": {
126
128
  "vue/no-v-model-argument": "off",
127
- "jsdoc/check-tag-names": "off"
129
+ "jsdoc/check-tag-names": "off",
130
+ "promise/always-return": [
131
+ "error",
132
+ {
133
+ "ignoreLastCallback": true
134
+ }
135
+ ]
128
136
  }
129
137
  },
130
138
  "eslintIgnore": [
@@ -25,7 +25,9 @@
25
25
  "@vcmap/layer-slider": "^2.0.0",
26
26
  "@vcmap/vcs-solar-balloon": "^2.0.0",
27
27
  "@vcmap/list-view": "^1.0.0",
28
- "@vcmap/pointcloud-settings": "^1.0.0"
28
+ "@vcmap/pointcloud-settings": "^1.0.0",
29
+ "@vcmap/gamepad": "^1.0.0",
30
+ "@vcmap/sensorthings": "^1.0.0"
29
31
  },
30
32
  "optionalDependencies": {
31
33
  "@vcmap/planning": "^6.0.0"
@@ -234,9 +234,15 @@ export function createOverviewMapAction(
234
234
  );
235
235
 
236
236
  const listeners = [
237
- windowManager.added.addEventListener(async ({ id }) => {
237
+ windowManager.added.addEventListener(({ id }) => {
238
238
  if (id === windowComponent.id) {
239
- await overviewMap.activate();
239
+ overviewMap.activate().catch((e) => {
240
+ getLogger('createOverviewMapAction').error(
241
+ 'failed to activate overview map',
242
+ e,
243
+ );
244
+ windowManager.remove(windowComponent.id);
245
+ });
240
246
  }
241
247
  }),
242
248
  windowManager.removed.addEventListener(({ id }) => {
@@ -21,6 +21,7 @@ import { Point, LineString } from 'ol/geom.js';
21
21
  import { Icon } from 'ol/style.js';
22
22
  import { Cartesian3, Ray } from '@vcmap-cesium/engine';
23
23
  import { watch } from 'vue';
24
+ import { getLogger } from '@vcsuite/logger';
24
25
  import { getColorByKey } from '../vuePlugins/vuetify.js';
25
26
  import ClusterFeatureComponent from '../featureInfo/ClusterFeatureComponent.vue';
26
27
  import { WindowSlot } from '../manager/window/windowManager.js';
@@ -54,7 +55,11 @@ export function setupDeepPickingLayer(app) {
54
55
  });
55
56
  markVolatile(layer);
56
57
  app.layers.add(layer);
57
- layer.activate();
58
+ layer.activate().catch(() => {
59
+ getLogger('deepPickingAction').error(
60
+ 'Could not activate deep picking layer',
61
+ );
62
+ });
58
63
 
59
64
  const style = new VectorStyleItem({
60
65
  image: {
@@ -20,6 +20,7 @@ import { fromExtent } from 'ol/geom/Polygon.js';
20
20
  import { createOrUpdateFromCoordinates } from 'ol/extent.js';
21
21
  import { Polygon } from 'ol/geom.js';
22
22
  import { unByKey } from 'ol/Observable.js';
23
+ import { getLogger } from '@vcsuite/logger';
23
24
 
24
25
  /**
25
26
  * @param {import("@src/vcsUiApp.js").default} app
@@ -52,9 +53,12 @@ export function createLayerToggleAction(layer, disabled) {
52
53
  icon: '$vcsEye',
53
54
  active: false,
54
55
  disabled,
55
- async callback() {
56
+ callback() {
56
57
  if (!this.active) {
57
- await layer.activate();
58
+ layer.activate().catch(() => {
59
+ getLogger('extentActions').warn('Failed to activate layer');
60
+ this.title = 'components.extent.show';
61
+ });
58
62
  this.title = 'components.extent.hide';
59
63
  } else {
60
64
  layer.deactivate();
@@ -96,7 +100,11 @@ export function createExtentFeatureAction(
96
100
  callback() {
97
101
  if (!this.active) {
98
102
  this.active = true;
99
- layer.activate();
103
+ layer.activate().catch(() => {
104
+ getLogger('extentActions').warn('Failed to activate layer');
105
+ session?.stop();
106
+ this.active = false;
107
+ });
100
108
  const feature = layer.getFeatureById(featureId);
101
109
  layer.removeFeaturesById([featureId]);
102
110
  session = startCreateFeatureSession(app, layer, GeometryType.BBox);
@@ -176,7 +184,7 @@ function setupTranslateAction(
176
184
  title: 'components.extent.translate',
177
185
  icon: 'mdi-axis-arrow',
178
186
  active: false,
179
- async callback() {
187
+ callback() {
180
188
  if (session) {
181
189
  session.stop();
182
190
  } else {
@@ -189,7 +197,10 @@ function setupTranslateAction(
189
197
  suspendFeatureUpdate.value = false;
190
198
  });
191
199
  });
192
- await layer.activate();
200
+ layer.activate().catch(() => {
201
+ getLogger('extentActions').warn('Failed to activate layer');
202
+ session?.stop();
203
+ });
193
204
  session = startEditFeaturesSession(app, layer);
194
205
  session.stopped.addEventListener(() => {
195
206
  action.active = false;
@@ -246,7 +257,10 @@ function setupVertexAction(
246
257
  suspendFeatureUpdate.value = false;
247
258
  });
248
259
  });
249
- await layer.activate();
260
+ layer.activate().catch(() => {
261
+ getLogger('extentActions').warn('Failed to activate layer');
262
+ session?.stop();
263
+ });
250
264
  session = startEditGeometrySession(app, layer);
251
265
  session.stopped.addEventListener(() => {
252
266
  action.active = false;
@@ -1,5 +1,6 @@
1
1
  import { reactive } from 'vue';
2
2
  import { check, maybe, ofEnum } from '@vcsuite/check';
3
+ import { getLogger } from '@vcsuite/logger';
3
4
  import {
4
5
  createFlightVisualization,
5
6
  exportFlightAsGeoJson,
@@ -378,7 +379,10 @@ export async function createFlightVisualizationAction(
378
379
  if (this.active) {
379
380
  flightVis.deactivate();
380
381
  } else {
381
- await flightVis.activate();
382
+ flightVis.activate().catch(() => {
383
+ getLogger('flightActions').warn('Failed to activate layer');
384
+ this.active = false;
385
+ });
382
386
  }
383
387
  this.active = !this.active;
384
388
  },
@@ -90,7 +90,11 @@
90
90
  isMobileLandscape,
91
91
  } from '../vuePlugins/vuetify.js';
92
92
  import VcsLegend from '../legend/VcsLegend.vue';
93
- import { getLegendEntries } from '../legend/legendHelper.js';
93
+ import {
94
+ getLayerLegend,
95
+ getLegendEntries,
96
+ getStyleLegend,
97
+ } from '../legend/legendHelper.js';
94
98
  import VcsAttributionsFooter from './VcsAttributionsFooter.vue';
95
99
  import VcsObliqueFooter from './VcsObliqueFooter.vue';
96
100
  import VcsTextPageFooter from './VcsTextPageFooter.vue';
@@ -280,9 +284,32 @@
280
284
  );
281
285
  }
282
286
  };
287
+
288
+ /**
289
+ * Handles legend button and window.
290
+ * Adds a button, if legend definitions are available or removes legend otherwise.
291
+ */
292
+ const handleLegend = () => {
293
+ const layersWithLegend = [...app.layers].filter((layer) =>
294
+ getLayerLegend(layer),
295
+ );
296
+ const stylesWithLegend = [...app.styles].filter((style) =>
297
+ getStyleLegend(style),
298
+ );
299
+ if (layersWithLegend < 1 && stylesWithLegend < 1) {
300
+ app.navbarManager.remove(legendComponentId);
301
+ app.windowManager.remove(legendComponentId);
302
+ } else {
303
+ addLegend();
304
+ }
305
+ };
306
+
283
307
  const { xs } = useDisplay();
284
308
  let currentEntryLength = entries.length;
285
309
  const watchEntries = watch(entries, (newValue) => {
310
+ if (newValue.length > currentEntryLength) {
311
+ handleLegend();
312
+ }
286
313
  if (
287
314
  app.uiConfig.config.openLegendOnAdd &&
288
315
  newValue.length > currentEntryLength &&
@@ -309,34 +336,16 @@
309
336
  currentEntryLength = newValue.length;
310
337
  });
311
338
 
312
- /**
313
- * Handles legend button and window.
314
- * Adds a button, if legend definitions are available or removes legend otherwise.
315
- */
316
- const handleLegend = () => {
317
- const layersWithLegend = [...app.layers].filter(
318
- (layer) => layer.style?.properties?.legend ?? layer.properties?.legend,
319
- );
320
- const stylesWithLegend = [...app.styles].filter(
321
- (style) => style?.properties?.legend,
322
- );
323
- if (layersWithLegend < 1 && stylesWithLegend < 1) {
324
- app.navbarManager.remove(legendComponentId);
325
- app.windowManager.remove(legendComponentId);
326
- } else {
327
- addLegend();
328
- }
329
- };
330
339
  handleLegend();
331
340
 
332
341
  const listeners = [
333
342
  app.layers.added.addEventListener((layer) => {
334
- if (layer.style?.properties?.legend ?? layer.properties?.legend) {
343
+ if (getLayerLegend(layer)) {
335
344
  addLegend();
336
345
  }
337
346
  }),
338
347
  app.styles.added.addEventListener((style) => {
339
- if (style?.properties?.legend) {
348
+ if (getStyleLegend(style)) {
340
349
  addLegend();
341
350
  }
342
351
  }),
@@ -1,3 +1,4 @@
1
+ import { getLogger } from '@vcsuite/logger';
1
2
  import VcsCallback, { callbackClassRegistry } from './vcsCallback.js';
2
3
 
3
4
  /**
@@ -34,7 +35,14 @@ class ActivateLayersCallback extends VcsCallback {
34
35
  this._layerNames
35
36
  .map((n) => this._app.layers.getByKey(n))
36
37
  .filter((l) => l)
37
- .forEach((l) => l.activate());
38
+ .forEach((l) =>
39
+ l.activate().catch((e) => {
40
+ getLogger('ActivateLayersCallback').error(
41
+ `Could not activate layer: ${l.name}`,
42
+ e,
43
+ );
44
+ }),
45
+ );
38
46
  }
39
47
 
40
48
  /**
@@ -36,8 +36,9 @@ class AddModuleCallback extends VcsCallback {
36
36
  createModuleFromObjectOrUrl(this._module)
37
37
  .then((module) => {
38
38
  if (module) {
39
- this._app.addModule(module);
39
+ return this._app.addModule(module);
40
40
  }
41
+ return undefined;
41
42
  })
42
43
  .catch((e) => {
43
44
  getLogger('addModuleCallback').error('Error adding module', e);
@@ -33,6 +33,7 @@
33
33
  <script>
34
34
  import { watch } from 'vue';
35
35
  import { useDisplay } from 'vuetify';
36
+ import { getLogger } from '@vcsuite/logger';
36
37
  import {
37
38
  useProxiedAtomicModel,
38
39
  useProxiedComplexModel,
@@ -144,7 +145,15 @@
144
145
  itemClicked(item, event) {
145
146
  if (item?.clickable) {
146
147
  if (item?.clicked && !item?.disabled) {
147
- item.clicked(event);
148
+ const p = item.clicked(event);
149
+ if (p instanceof Promise) {
150
+ p.catch((e) => {
151
+ getLogger('VcsTreeview.vue').error(
152
+ `Tree view item failed to click ${item.name}`,
153
+ e,
154
+ );
155
+ });
156
+ }
148
157
  }
149
158
  } else if (
150
159
  (props.openOnClick ?? false) !== false &&
@@ -1,3 +1,4 @@
1
+ import { getLogger } from '@vcsuite/logger';
1
2
  import { parseBoolean } from '@vcsuite/parsers';
2
3
  import ContentTreeItem, {
3
4
  contentTreeClassRegistry,
@@ -184,7 +185,16 @@ class LayerGroupContentTreeItem extends ContentTreeItem {
184
185
  const layers = this._layers;
185
186
  const activate = layers.some((l) => !(l.active || l.loading));
186
187
  if (activate) {
187
- await Promise.all(layers.map((l) => l.activate()));
188
+ await Promise.all(
189
+ layers.map((l) =>
190
+ l.activate().catch((e) => {
191
+ getLogger('LayerGroupContentTreeItem').error(
192
+ `Could not activate layer ${l.name}`,
193
+ e,
194
+ );
195
+ }),
196
+ ),
197
+ );
188
198
  executeCallbacks(this._app, this._onActivate);
189
199
  } else {
190
200
  layers.forEach((l) => {
@@ -6,7 +6,7 @@ export type WMSChildItemOptions = import("./contentTreeItem.js").ContentTreeItem
6
6
  * @typedef {import("./contentTreeItem.js").ContentTreeItemOptions &
7
7
  * { wmsEntry:import("./wmsGroupContentTreeItem.js").WMSEntry }} WMSChildItemOptions
8
8
  * @property {import("./wmsGroupContentTreeItem.js").WMSEntry} wmsEntry - the wmsEntry
9
- * @property {boolean} showStyleSelector - show the style selector
9
+ * @property {boolean} hideStyleSelector - hides the style selector
10
10
  */
11
11
  /**
12
12
  * A WMS child layer. Toggles this child in the parent WMS layer.
@@ -13,7 +13,7 @@ import { vcsAppSymbol } from '../pluginHelper.js';
13
13
  * @typedef {import("./contentTreeItem.js").ContentTreeItemOptions &
14
14
  * { wmsEntry:import("./wmsGroupContentTreeItem.js").WMSEntry }} WMSChildItemOptions
15
15
  * @property {import("./wmsGroupContentTreeItem.js").WMSEntry} wmsEntry - the wmsEntry
16
- * @property {boolean} showStyleSelector - show the style selector
16
+ * @property {boolean} hideStyleSelector - hides the style selector
17
17
  */
18
18
 
19
19
  /**
@@ -71,7 +71,7 @@ class WmsChildContentTreeItem extends ContentTreeItem {
71
71
  this._destroyStyleAction = () => {};
72
72
 
73
73
  this._setExtentAction(this._wmsEntry.extent);
74
- if (options.showStyleSelector) {
74
+ if (!options.hideStyleSelector) {
75
75
  this._setStyleAction();
76
76
  }
77
77
  }
@@ -2,8 +2,8 @@ export default WMSGroupContentTreeItem;
2
2
  export type WMSGroupContentTreeItemOptions = import('./contentTreeItem.js').ContentTreeItemOptions & {
3
3
  layerName: string;
4
4
  showWhenNotSupported?: boolean;
5
- exclusiveLayers?: boolean;
6
- editableStyle?: boolean;
5
+ setWMSLayersExclusive?: boolean;
6
+ hideStyleSelector?: boolean;
7
7
  allowedWMSLayers?: string[];
8
8
  };
9
9
  export type WMSStyleEntry = {
@@ -21,11 +21,11 @@ export type WMSEntry = {
21
21
  };
22
22
  /**
23
23
  * @typedef {import('./contentTreeItem.js').ContentTreeItemOptions &
24
- * { layerName: string, showWhenNotSupported?: boolean, exclusiveLayers?:boolean, editableStyle?:boolean, allowedWMSLayers?:string[]}} WMSGroupContentTreeItemOptions
24
+ * { layerName: string, showWhenNotSupported?: boolean, setWMSLayersExclusive?:boolean, hideStyleSelector?:boolean, allowedWMSLayers?:string[]}} WMSGroupContentTreeItemOptions
25
25
  * @property {boolean} showWhenNotSupported - optional flag to show the item even if it is not supported by the activeMap.
26
26
  * @property {string} layerName - The name of the WMSLayer to show the children of.
27
27
  * @property {boolean} [setWMSLayersExclusive=false] - Whether the WMSlayers are mutually exclusive.
28
- * @property {boolean} [showStyleSelector=true] - Whether the layer style can be selected. Will add a StyleSelector action to compatible items if the Layer has more than one style.
28
+ * @property {boolean} [hideStyleSelector=false] - Whether the layer style can be selected. Will add a StyleSelector action to compatible items if the Layer has more than one style.
29
29
  * @property {string[]} allowedWMSLayers - The list of layers to be shown, other available layers will not be shown.
30
30
  */
31
31
  /**
@@ -75,7 +75,7 @@ declare class WMSGroupContentTreeItem extends VcsObjectContentTreeItem<import(".
75
75
  * @type {boolean}
76
76
  * @private
77
77
  */
78
- private _showStyleSelector;
78
+ private _hideStyleSelector;
79
79
  /**
80
80
  * @type {boolean}
81
81
  * @private
@@ -8,6 +8,7 @@ import { StateActionState } from '../actions/stateRefAction.js';
8
8
  import { contentTreeClassRegistry } from './contentTreeItem.js';
9
9
  import WmsChildContentTreeItem from './wmsChildContentTreeItem.js';
10
10
  import VcsObjectContentTreeItem from './vcsObjectContentTreeItem.js';
11
+ import { legendSymbol } from '../legend/legendHelper.js';
11
12
 
12
13
  /**
13
14
  * @param {string} rawUrl
@@ -87,21 +88,21 @@ async function getWMSEntries(rawUrl, parameters) {
87
88
  * @param {import("../vcsUiApp.js").default} app
88
89
  * @param {WMSEntry} wmsEntry
89
90
  * @param {string} parentName
90
- * @param {boolean} showStyleSelector
91
+ * @param {boolean} hideStyleSelector
91
92
  * @returns {WmsChildContentTreeItem}
92
93
  */
93
94
  function createWMSChildContentTreeItem(
94
95
  app,
95
96
  wmsEntry,
96
97
  parentName,
97
- showStyleSelector,
98
+ hideStyleSelector,
98
99
  ) {
99
100
  const childItem = new WmsChildContentTreeItem(
100
101
  {
101
102
  name: `${parentName}.${wmsEntry.name.replaceAll('.', '_')}`,
102
103
  wmsEntry,
103
104
  title: wmsEntry.title,
104
- showStyleSelector,
105
+ hideStyleSelector,
105
106
  },
106
107
  app,
107
108
  );
@@ -111,11 +112,11 @@ function createWMSChildContentTreeItem(
111
112
 
112
113
  /**
113
114
  * @typedef {import('./contentTreeItem.js').ContentTreeItemOptions &
114
- * { layerName: string, showWhenNotSupported?: boolean, exclusiveLayers?:boolean, editableStyle?:boolean, allowedWMSLayers?:string[]}} WMSGroupContentTreeItemOptions
115
+ * { layerName: string, showWhenNotSupported?: boolean, setWMSLayersExclusive?:boolean, hideStyleSelector?:boolean, allowedWMSLayers?:string[]}} WMSGroupContentTreeItemOptions
115
116
  * @property {boolean} showWhenNotSupported - optional flag to show the item even if it is not supported by the activeMap.
116
117
  * @property {string} layerName - The name of the WMSLayer to show the children of.
117
118
  * @property {boolean} [setWMSLayersExclusive=false] - Whether the WMSlayers are mutually exclusive.
118
- * @property {boolean} [showStyleSelector=true] - Whether the layer style can be selected. Will add a StyleSelector action to compatible items if the Layer has more than one style.
119
+ * @property {boolean} [hideStyleSelector=false] - Whether the layer style can be selected. Will add a StyleSelector action to compatible items if the Layer has more than one style.
119
120
  * @property {string[]} allowedWMSLayers - The list of layers to be shown, other available layers will not be shown.
120
121
  */
121
122
 
@@ -185,7 +186,7 @@ class WMSGroupContentTreeItem extends VcsObjectContentTreeItem {
185
186
  * @type {boolean}
186
187
  * @private
187
188
  */
188
- this._showStyleSelector = parseBoolean(options.showStyleSelector, true);
189
+ this._hideStyleSelector = parseBoolean(options.hideStyleSelector, false);
189
190
 
190
191
  this.state = this._setWMSLayersExclusive
191
192
  ? StateActionState.NONE
@@ -327,9 +328,9 @@ class WMSGroupContentTreeItem extends VcsObjectContentTreeItem {
327
328
  .flat()
328
329
  .filter((l) => l);
329
330
  if (legend.length > 0) {
330
- this._layer.properties.legend = legend;
331
+ this._layer[legendSymbol] = legend;
331
332
  } else {
332
- this._layer.properties.legend = undefined;
333
+ delete this._layer[legendSymbol];
333
334
  }
334
335
  }
335
336
  this._pauseStateChangedListener = true;
@@ -531,7 +532,7 @@ class WMSGroupContentTreeItem extends VcsObjectContentTreeItem {
531
532
  this._app,
532
533
  wmsEntry,
533
534
  this.name,
534
- this._showStyleSelector,
535
+ this._hideStyleSelector,
535
536
  );
536
537
  });
537
538
  childItems.forEach((childItem) => {
@@ -594,8 +595,8 @@ class WMSGroupContentTreeItem extends VcsObjectContentTreeItem {
594
595
  if (this._setWMSLayersExclusive) {
595
596
  config.setWMSLayersExclusive = this._setWMSLayersExclusive;
596
597
  }
597
- if (!this._showStyleSelector) {
598
- config.showStyleSelector = this._showStyleSelector;
598
+ if (this._hideStyleSelector) {
599
+ config.hideStyleSelector = this._hideStyleSelector;
599
600
  }
600
601
  if (this._allowedWMSLayers?.length > 0) {
601
602
  config.allowedWMSLayers = this._allowedWMSLayers;
@@ -613,7 +613,9 @@ class FeatureInfo extends Collection {
613
613
  });
614
614
  markVolatile(this._scratchLayer);
615
615
  this._app.layers.add(this._scratchLayer);
616
- this._scratchLayer.activate();
616
+ this._scratchLayer.activate().catch((e) => {
617
+ getLogger('FeatureInfo').error('Failed to activate scratch layer', e);
618
+ });
617
619
  }
618
620
  }
619
621
 
@@ -62,6 +62,16 @@ export function getImageSrcFromShape(image: import("ol/style/Image.js").Options)
62
62
  * @property {boolean} [open=true] - panel state of entry
63
63
  * @property {Array<LegendItem>} legend - legend properties
64
64
  */
65
+ /**
66
+ * @param {import("@vcmap/core").StyleItem|undefined} style
67
+ * @returns {Array<LegendItem>|undefined}
68
+ */
69
+ export function getStyleLegend(style: import("@vcmap/core").StyleItem | undefined): Array<LegendItem> | undefined;
70
+ /**
71
+ * @param {import("@vcmap/core").Layer|undefined} layer
72
+ * @returns {Array<LegendItem>|undefined}
73
+ */
74
+ export function getLayerLegend(layer: import("@vcmap/core").Layer | undefined): Array<LegendItem> | undefined;
65
75
  /**
66
76
  *
67
77
  * @param {import("../vcsUiApp.js").default} app
@@ -71,6 +81,11 @@ export function getLegendEntries(app: import("../vcsUiApp.js").default): {
71
81
  entries: import("vue").UnwrapRef<Array<LegendEntry>>;
72
82
  destroy: () => void;
73
83
  };
84
+ /**
85
+ * Symbol set a volatile legend property on a layer or style
86
+ * @type {symbol}
87
+ */
88
+ export const legendSymbol: symbol;
74
89
  /**
75
90
  * *
76
91
  */
@@ -1,6 +1,12 @@
1
1
  import { getShapeFromOptions } from '@vcmap/core';
2
2
  import { reactive } from 'vue';
3
3
 
4
+ /**
5
+ * Symbol set a volatile legend property on a layer or style
6
+ * @type {symbol}
7
+ */
8
+ export const legendSymbol = Symbol('legend');
9
+
4
10
  /**
5
11
  * @enum {string}
6
12
  * @property {string} Image - an image
@@ -109,6 +115,26 @@ export function getImageSrcFromShape(image) {
109
115
  * @property {Array<LegendItem>} legend - legend properties
110
116
  */
111
117
 
118
+ /**
119
+ * @param {import("@vcmap/core").StyleItem|undefined} style
120
+ * @returns {Array<LegendItem>|undefined}
121
+ */
122
+ export function getStyleLegend(style) {
123
+ return style?.[legendSymbol] ?? style?.properties?.legend;
124
+ }
125
+
126
+ /**
127
+ * @param {import("@vcmap/core").Layer|undefined} layer
128
+ * @returns {Array<LegendItem>|undefined}
129
+ */
130
+ export function getLayerLegend(layer) {
131
+ return (
132
+ getStyleLegend(layer?.style) ??
133
+ layer?.[legendSymbol] ??
134
+ layer?.properties?.legend
135
+ );
136
+ }
137
+
112
138
  /**
113
139
  *
114
140
  * @param {import("../vcsUiApp.js").default} app
@@ -149,8 +175,7 @@ export function getLegendEntries(app) {
149
175
  if (layer.active && layer.isSupported(app.maps.activeMap)) {
150
176
  const key = layer.name;
151
177
  const title = layer.properties.title || layer.name;
152
- const legend =
153
- layer.style?.properties?.legend ?? layer.properties?.legend;
178
+ const legend = getLayerLegend(layer);
154
179
  if (legend) {
155
180
  const legendEntry = { key, title, legend, open: true };
156
181
  entries.unshift(legendEntry);
@@ -186,7 +211,7 @@ export function getLegendEntries(app) {
186
211
  const uniqueVectorClusterGroups = [...new Set(vectorClusterGroups)];
187
212
  uniqueVectorClusterGroups.forEach((groupName) => {
188
213
  const group = app.vectorClusterGroups.getByKey(groupName);
189
- if (group?.properties?.legend) {
214
+ if (group?.[legendSymbol] ?? group?.properties?.legend) {
190
215
  const title = group.properties.title || group.name;
191
216
  const { legend } = group.properties;
192
217
  if (!entries.some(({ key }) => key === group.name)) {