@vcmap/ui 5.0.0-rc.29 → 5.0.0-rc.30

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 (41) hide show
  1. package/config/dev.config.json +4 -0
  2. package/dist/assets/cesium.js +1 -1
  3. package/dist/assets/{core.74da2a.js → core.b16511.js} +2 -2
  4. package/dist/assets/core.js +1 -1
  5. package/dist/assets/index-c115e3a1.js +1 -0
  6. package/dist/assets/ol.js +1 -1
  7. package/dist/assets/{ui.d3054c.css → ui.ab815e.css} +2 -2
  8. package/dist/assets/{ui.d3054c.js → ui.ab815e.js} +4081 -3460
  9. package/dist/assets/ui.js +1 -1
  10. package/dist/assets/vue.js +2 -2
  11. package/dist/assets/{vuetify.946bd8.js → vuetify.ea3fa8.js} +1 -1
  12. package/dist/assets/vuetify.js +2 -2
  13. package/dist/index.html +1 -1
  14. package/index.js +6 -0
  15. package/package.json +1 -1
  16. package/plugins/@vcmap/search-nominatim/SearchNominatimEditor.vue +90 -0
  17. package/plugins/@vcmap/search-nominatim/index.js +37 -0
  18. package/plugins/@vcmap-show-case/form-inputs-example/FormInputsExample.vue +37 -1
  19. package/plugins/@vcmap-show-case/form-inputs-example/index.js +3 -0
  20. package/plugins/@vcmap-show-case/form-inputs-example/validation.js +11 -0
  21. package/plugins/@vcmap-show-case/style-input-example/styleExample.vue +0 -1
  22. package/plugins/@vcmap-show-case/vector-properties-example/index.js +40 -0
  23. package/plugins/@vcmap-show-case/vector-properties-example/package.json +5 -0
  24. package/plugins/@vcmap-show-case/vector-properties-example/vectorPropertiesExample.vue +109 -0
  25. package/src/components/form-inputs-controls/VcsChipArrayInput.vue +282 -0
  26. package/src/components/form-inputs-controls/VcsTextField.vue +9 -3
  27. package/src/components/plugins/AbstractConfigEditor.vue +84 -0
  28. package/src/components/style/VcsImageSelector.vue +6 -5
  29. package/src/components/style/VcsTextSelector.vue +1 -1
  30. package/src/components/vector-properties/VcsVectorPropertiesComponent.vue +737 -0
  31. package/src/components/vector-properties/composables.js +93 -0
  32. package/src/i18n/de.js +40 -9
  33. package/src/i18n/en.js +38 -7
  34. package/src/manager/collectionManager/collectionComponent.js +1 -1
  35. package/src/pluginHelper.js +57 -17
  36. package/src/vcsUiApp.js +17 -27
  37. package/dist/assets/index-cb070eff.js +0 -1
  38. /package/dist/assets/{cesium.16590b.js → cesium.eaf7cc.js} +0 -0
  39. /package/dist/assets/{ol.50a512.js → ol.4bbf0f.js} +0 -0
  40. /package/dist/assets/{vue.30740e.js → vue.67e80f.js} +0 -0
  41. /package/dist/assets/{vuetify.946bd8.css → vuetify.ea3fa8.css} +0 -0
@@ -0,0 +1,93 @@
1
+ import { computed } from 'vue';
2
+
3
+ /**
4
+ * Creates a computed property with a getter and a setter for a specific primitive object property/key of the modelled object. This composable allows to pass the computed to an v-model of a sub component. The getter returns the value of the key. The setter merges the passed value with the other object properties of the modelled object and emits the whole object as a input event, and only the changed props as an change event.
5
+ * @param {function():Object} modelObject Getter for the property that is modelled by the component and should be updated with input event, usually this is the 'value' prop.
6
+ * @param {string} key The key of the modelObject that should be returned on get and updated on set.
7
+ * @param {function(event: string, ...args: any[]):void} emit The emit function of the component context that is using this composable.
8
+ * @returns {import('vue').WriteableComputedRef} A computed with a getter and a setter.
9
+ */
10
+ export function usePrimitiveProperty(modelObject, key, emit) {
11
+ return computed({
12
+ get() {
13
+ return modelObject()[key];
14
+ },
15
+ set(value) {
16
+ if (modelObject()[key] !== value) {
17
+ const newParams = structuredClone(modelObject());
18
+ const changedParams = { [key]: value || undefined }; // XXX boolean values need to be handled differently
19
+ emit('input', Object.assign(newParams, changedParams));
20
+ emit('propertyChange', changedParams);
21
+ }
22
+ },
23
+ });
24
+ }
25
+
26
+ /**
27
+ * Creates an object with the entries of the input array as keys and computed properties as values. These have a getter and a setter for a specific entry of the array, that is an object property/key of the modelled object. This composable allows to pass the computeds to an v-model of a sub component. The getter returns the value of the array entry. The setter first merges the passed value with the other array entries, and then with the other object properties of the modelled object and emits the whole object as a input event, and only the changed props as an change event.
28
+ * @param {function():Object} modelObject Getter for the property that is modelled by the component and should be updated with input event, usually this is the 'value' prop.
29
+ * @param {string} key The key of the modelObject that should be returned on get and updated on set.
30
+ * @param {function(event: string, ...args: any[]):void} emit The emit function of the component context that is using this composable.
31
+ * @param {number} arrayLength The length of the array property.
32
+ * @returns {Object<string, import('vue').WriteableComputedRef>} An object with the provided names as keys and the corresponding computed properties with a getter and a setter.
33
+ */
34
+ export function useArrayProperty(modelObject, key, emit, arrayLength) {
35
+ return Array(arrayLength)
36
+ .fill()
37
+ .map((entry, index) => {
38
+ return computed({
39
+ get() {
40
+ if (modelObject()?.[key]) {
41
+ return modelObject()[key][index];
42
+ } else {
43
+ return undefined;
44
+ }
45
+ },
46
+ set(value) {
47
+ const newParams = structuredClone(modelObject());
48
+ let changedParams;
49
+ if (!modelObject()?.[key]) {
50
+ const newArray = Array(arrayLength).fill();
51
+ newArray[index] = value;
52
+ changedParams = { [key]: newArray };
53
+ } else if (modelObject()[key][index] !== value) {
54
+ const newArray = [...modelObject()[key]];
55
+ newArray[index] = value;
56
+ changedParams = { [key]: newArray };
57
+ }
58
+
59
+ if (changedParams) {
60
+ emit('input', Object.assign(newParams, changedParams));
61
+ emit('propertyChange', changedParams);
62
+ }
63
+ },
64
+ });
65
+ });
66
+ }
67
+
68
+ /**
69
+ * Creates a computed property that returns whether a specific key of the modelled object (value prop) is undefined or not. If set to true, the provided default value is applied to the key of the modelled object.
70
+ * @param {function():Object} modelObject Getter for the property that is modelled by the component and should be updated with input event, usually this is the 'value' prop.
71
+ * @param {string} key The key of the modelObject that should be return on get and updated on set.
72
+ * @param {function(event: string, ...args: any[]):void} emit The emit function of the component context that is using this composable.
73
+ * @param {*} valueDefault The defualt value that is set when `true` is provided to the setter of the computed property.
74
+ * @returns {import('vue').WriteableComputedRef} A computed ref with a setter and a getter.
75
+ */
76
+ export function useHasProperty(modelObject, key, emit, valueDefault) {
77
+ return computed({
78
+ get() {
79
+ return modelObject()?.[key] !== undefined;
80
+ },
81
+ set(value) {
82
+ const newParams = structuredClone(modelObject());
83
+ let changedParams;
84
+ if (value) {
85
+ changedParams = { [key]: valueDefault };
86
+ } else {
87
+ changedParams = { [key]: undefined };
88
+ }
89
+ emit('input', Object.assign(newParams, changedParams));
90
+ emit('propertyChange', changedParams);
91
+ },
92
+ });
93
+ }
package/src/i18n/de.js CHANGED
@@ -1,9 +1,9 @@
1
1
  const messages = {
2
2
  navbar: {
3
3
  maps: {
4
- CesiumMap: '3D Karte aktivieren',
5
- OpenlayersMap: '2D Karte aktivieren',
6
- ObliqueMap: 'Schrägluftbilder aktivieren',
4
+ CesiumMap: '3D-Karte aktivieren',
5
+ OpenlayersMap: '2D-Karte aktivieren',
6
+ ObliqueMap: 'Schrägluftbildkarte aktivieren',
7
7
  },
8
8
  menu: {
9
9
  tooltip: 'Menü',
@@ -69,8 +69,8 @@ const messages = {
69
69
  noResultsPlaceholder: 'Keine übereinstimmenden Einträge gefunden',
70
70
  },
71
71
  style: {
72
- fill: 'Füll Stil',
73
- stroke: 'Linien Stil',
72
+ fill: 'Füllung',
73
+ stroke: 'Linie',
74
74
  reset: 'Zurücksetzen',
75
75
  lineWidth: 'Linienbreite',
76
76
  type: 'Typ',
@@ -81,7 +81,7 @@ const messages = {
81
81
  rotation: 'Rotation',
82
82
  scale: 'Skalierung',
83
83
  opacity: 'Deckkraft',
84
- image: 'Punkt Stil',
84
+ image: 'Symbol',
85
85
  icon: 'Icon',
86
86
  presets: 'Vorlagen',
87
87
  shape: 'Form',
@@ -97,11 +97,37 @@ const messages = {
97
97
  italic: 'Kursiv',
98
98
  text: 'Text',
99
99
  enterText: 'Text hier eingeben',
100
- allowedRange: 'Erlaubter Wertebereich',
101
- notValid: 'Eingabe nicht gültig',
102
- required: 'Eingabe ist erforderlich',
103
100
  offset: 'Versatz',
104
101
  },
102
+ vectorProperties: {
103
+ header: 'Vektor Eigenschaften',
104
+ altitudeMode: 'Höhenmodus',
105
+ clampToGround: 'Auf Gelände legen',
106
+ absolute: 'Absolut',
107
+ relativeToGround: 'Relativ zum Gelände',
108
+ groundLevel: 'Geländehöhe',
109
+ classificationType: 'Klassifizierung',
110
+ none: 'Keine',
111
+ both: 'Beide',
112
+ cesium3DTile: '3D Tiles',
113
+ terrain: 'Gelände',
114
+ heightAboveGround: 'Höhe über Gelände',
115
+ allowPicking: 'Auswahl erlauben',
116
+ scaleByDistance: 'Distanzskalierung',
117
+ eyeOffset: 'Blick Versatz',
118
+ storeys: 'Stockwerke',
119
+ storeyHeights: 'Stockwerkshöhe(n)',
120
+ aboveGround: 'Über Grund',
121
+ belowGround: 'Unter Grund',
122
+ modelUrl: 'Modell URL',
123
+ modelHeading: 'Modell Ausrichtung',
124
+ modelPitch: 'Modell Neigung',
125
+ modelRoll: 'Modell Rotation',
126
+ baseUrl: 'Basis URL',
127
+ extrudedHeight: 'Extrusion',
128
+ skirt: 'Skirts',
129
+ modelScale: 'Modell Skalierung',
130
+ },
105
131
  },
106
132
  settings: {
107
133
  title: 'Einstellungen',
@@ -117,6 +143,11 @@ const messages = {
117
143
  title: 'Hilfe',
118
144
  tooltip: 'Externe Hilfeseite in neuem Browser Tab öffnen',
119
145
  },
146
+ validation: {
147
+ allowedRange: 'Erlaubter Wertebereich',
148
+ notValid: 'Eingabe nicht gültig',
149
+ required: 'Eingabe ist erforderlich',
150
+ },
120
151
  featureInfo: {
121
152
  activateToolTitle: 'Informationswerkzeug aktivieren',
122
153
  deactivateToolTitle: 'Informationswerkzeug deaktivieren',
package/src/i18n/en.js CHANGED
@@ -1,9 +1,9 @@
1
1
  const messages = {
2
2
  navbar: {
3
3
  maps: {
4
- CesiumMap: 'Enable 3D view',
5
- OpenlayersMap: 'Enable 2D view',
6
- ObliqueMap: 'Enable oblique view',
4
+ CesiumMap: 'Enable 3D map',
5
+ OpenlayersMap: 'Enable 2D map',
6
+ ObliqueMap: 'Enable oblique imagery map',
7
7
  },
8
8
  menu: {
9
9
  tooltip: 'Menu',
@@ -81,7 +81,7 @@ const messages = {
81
81
  rotation: 'Rotation',
82
82
  scale: 'Scale',
83
83
  opacity: 'Opacity',
84
- image: 'Point style',
84
+ image: 'Symbol',
85
85
  icon: 'Icon',
86
86
  shape: 'Shape',
87
87
  presets: 'Presets',
@@ -97,11 +97,37 @@ const messages = {
97
97
  italic: 'Italic',
98
98
  text: 'Text',
99
99
  enterText: 'Enter text here',
100
- allowedRange: 'Allowed value range',
101
- notValid: 'Input not valid',
102
- required: 'Input is required',
103
100
  offset: 'Offset',
104
101
  },
102
+ vectorProperties: {
103
+ header: 'Vector properties',
104
+ altitudeMode: 'Altitude mode',
105
+ clampToGround: 'Clamp to ground',
106
+ absolute: 'Absolute',
107
+ relativeToGround: 'Relative to ground',
108
+ groundLevel: 'Ground level',
109
+ classificationType: 'Classification',
110
+ none: 'None',
111
+ both: 'Both',
112
+ cesium3DTile: '3D Tiles',
113
+ terrain: 'Terrain',
114
+ heightAboveGround: 'Height above ground',
115
+ allowPicking: 'Allow picking',
116
+ scaleByDistance: 'Scale by distance',
117
+ eyeOffset: 'Eye offset',
118
+ storeys: 'Storeys',
119
+ storeyHeights: 'Storey height(s)',
120
+ aboveGround: 'Above ground',
121
+ belowGround: 'Below ground',
122
+ modelUrl: 'Model URL',
123
+ modelHeading: 'Model heading',
124
+ modelPitch: 'Model pitch',
125
+ modelRoll: 'Model roll',
126
+ baseUrl: 'Base URL',
127
+ extrudedHeight: 'Extrusion',
128
+ skirt: 'Skirts',
129
+ modelScale: 'Model scale',
130
+ },
105
131
  },
106
132
  settings: {
107
133
  title: 'Settings',
@@ -117,6 +143,11 @@ const messages = {
117
143
  title: 'Help',
118
144
  tooltip: 'Open external help page in new browser tab',
119
145
  },
146
+ validation: {
147
+ allowedRange: 'Allowed value range',
148
+ notValid: 'Input not valid',
149
+ required: 'Input is required',
150
+ },
120
151
  featureInfo: {
121
152
  activateToolTitle: 'Enable Info Tool',
122
153
  deactivateToolTitle: 'Disable Info Tool',
@@ -243,7 +243,7 @@ class CollectionComponent {
243
243
  * @private
244
244
  */
245
245
  _insertListItem(listItem) {
246
- if (!this._listItems.value.includes(listItem)) {
246
+ if (!this._listItems.value.some((i) => i.name === listItem.name)) {
247
247
  if (this._collection instanceof IndexedCollection) {
248
248
  const newItemIndex = this._collection.indexOfKey(listItem.name);
249
249
  if (newItemIndex === this._collection.size - 1) {
@@ -25,9 +25,21 @@ export const pluginFactorySymbol = Symbol('pluginFactory');
25
25
  */
26
26
  export const pluginBaseUrlSymbol = Symbol('pluginBaseUrl');
27
27
 
28
+ /**
29
+ * A symbol added to each plugin which describes the module URL from which the plugin was loaded (with the filename and including searchParams)
30
+ * @type {symbol}
31
+ */
32
+ export const pluginModuleUrlSymbol = Symbol('pluginModuleUrl');
33
+ /**
34
+ * A symbol added to each plugin which describes the configured version range
35
+ * @type {symbol}
36
+ */
37
+ export const pluginVersionRangeSymbol = Symbol('pluginVersionRange');
38
+
28
39
  /**
29
40
  * A helper function to create an absolute URL from a relative plugin asset URL. For example, when
30
41
  * shipping your plugin with a "plugin-asset/icon.png", you can always retrieve said icon with getPluginAssetUrl(app, name, 'pluing-assets/icon.png')
42
+ * Sets the plugin version as searchParam.
31
43
  * Returns null, if the plugin does not exist.
32
44
  * @param {VcsUiApp} app
33
45
  * @param {string} pluginName
@@ -47,6 +59,7 @@ export function getPluginAssetUrl(app, pluginName, asset) {
47
59
  assetUrl.searchParams.set(key, value);
48
60
  }
49
61
  });
62
+ assetUrl.searchParams.set('version', plugin.version);
50
63
  return assetUrl.toString();
51
64
  }
52
65
  return null;
@@ -114,15 +127,24 @@ export async function loadPlugin(name, config) {
114
127
  baseUrl.pathname = baseUrl.pathname.replace(/\/[^/]+$/, '/');
115
128
  const pluginInstance = await plugin.default(config, baseUrl.toString());
116
129
 
117
- if (!pluginInstance.name) {
118
- getLogger().error(`plugin ${name} does not expose a name`);
130
+ if (!(pluginInstance.name || pluginInstance.version)) {
131
+ getLogger().error(
132
+ `plugin ${name} does not conform to the VcsPlugin interface, which requires a name and version`,
133
+ );
119
134
  if (pluginInstance.destroy) {
120
135
  pluginInstance.destroy();
121
136
  }
122
137
  return null;
123
138
  }
139
+ if (!isValidPackageName(pluginInstance.name)) {
140
+ getLogger().warning(
141
+ `plugin ${pluginInstance.name} has no valid package name!`,
142
+ );
143
+ }
124
144
  pluginInstance[pluginFactorySymbol] = plugin.default;
125
145
  pluginInstance[pluginBaseUrlSymbol] = baseUrl.toString();
146
+ pluginInstance[pluginModuleUrlSymbol] = module;
147
+ pluginInstance[pluginVersionRangeSymbol] = config.version;
126
148
  return pluginInstance;
127
149
  } catch (err) {
128
150
  getLogger().error(`failed to load plugin ${name}`);
@@ -132,19 +154,25 @@ export async function loadPlugin(name, config) {
132
154
  }
133
155
 
134
156
  /**
157
+ * Returns relative url, if base is same, otherwise absolute url
158
+ * Removes version from searchParams, since version is serialized itself
135
159
  * @param {string} base
136
- * @param {string} pluginBase
160
+ * @param {string} pluginUrl
137
161
  * @returns {string}
138
162
  */
139
- export function getPluginEntry(base, pluginBase) {
163
+ export function getPluginEntry(base, pluginUrl) {
140
164
  const baseUrl = new URL(base);
141
- const pluginBaseUrl = new URL(pluginBase);
142
- if (baseUrl.origin !== pluginBaseUrl.origin) {
143
- return pluginBase;
165
+ const pluginModuleUrl = new URL(pluginUrl);
166
+ pluginModuleUrl.searchParams.delete('version'); // semver is part of config
167
+ if (baseUrl.origin !== pluginModuleUrl.origin) {
168
+ return pluginModuleUrl.toString();
144
169
  }
145
170
  const baseSubs = baseUrl.pathname.split('/');
146
- const pluginSubs = pluginBaseUrl.pathname.split('/');
147
- return pluginSubs.filter((sub, idx) => sub !== baseSubs[idx]).join('/');
171
+ const pluginSubs = pluginModuleUrl.pathname.split('/');
172
+ pluginModuleUrl.pathname = pluginSubs
173
+ .filter((sub, idx) => sub !== baseSubs[idx])
174
+ .join('/');
175
+ return `${pluginModuleUrl.pathname}${pluginModuleUrl.search}`.substring(1);
148
176
  }
149
177
 
150
178
  /**
@@ -154,24 +182,36 @@ export function getPluginEntry(base, pluginBase) {
154
182
  export function serializePlugin(plugin) {
155
183
  const serializedPlugin = plugin.toJSON ? plugin.toJSON() : {};
156
184
  serializedPlugin.name = plugin.name;
185
+ if (serializedPlugin[pluginVersionRangeSymbol]) {
186
+ serializedPlugin.version = serializedPlugin[pluginVersionRangeSymbol];
187
+ }
157
188
  serializedPlugin.entry = getPluginEntry(
158
189
  window.location.href,
159
- plugin[pluginBaseUrlSymbol],
190
+ plugin[pluginModuleUrlSymbol],
160
191
  );
161
192
  serializedPlugin[pluginFactorySymbol] = plugin[pluginFactorySymbol];
162
193
  serializedPlugin[pluginBaseUrlSymbol] = plugin[pluginBaseUrlSymbol];
194
+ serializedPlugin[pluginModuleUrlSymbol] = plugin[pluginModuleUrlSymbol];
195
+ serializedPlugin[pluginVersionRangeSymbol] = plugin[pluginVersionRangeSymbol];
163
196
  return serializedPlugin;
164
197
  }
165
198
 
166
199
  /**
167
200
  * @param {Object} serializedPlugin
168
- * @returns {Promise<VcsPlugin>}
201
+ * @returns {Promise<VcsPlugin|null>}
169
202
  */
170
203
  export async function deserializePlugin(serializedPlugin) {
171
- const reincarnation = await serializedPlugin[pluginFactorySymbol](
172
- serializedPlugin,
173
- );
174
- reincarnation[pluginFactorySymbol] = serializedPlugin[pluginFactorySymbol];
175
- reincarnation[pluginBaseUrlSymbol] = serializedPlugin[pluginBaseUrlSymbol];
176
- return reincarnation;
204
+ if (serializedPlugin[pluginFactorySymbol]) {
205
+ const reincarnation = await serializedPlugin[pluginFactorySymbol](
206
+ serializedPlugin,
207
+ );
208
+ reincarnation[pluginFactorySymbol] = serializedPlugin[pluginFactorySymbol];
209
+ reincarnation[pluginBaseUrlSymbol] = serializedPlugin[pluginBaseUrlSymbol];
210
+ reincarnation[pluginModuleUrlSymbol] =
211
+ serializedPlugin[pluginModuleUrlSymbol];
212
+ reincarnation[pluginVersionRangeSymbol] =
213
+ serializedPlugin[pluginVersionRangeSymbol];
214
+ return reincarnation;
215
+ }
216
+ return loadPlugin(serializedPlugin.name, serializedPlugin);
177
217
  }
package/src/vcsUiApp.js CHANGED
@@ -13,12 +13,7 @@ import {
13
13
  volatileModuleId,
14
14
  } from '@vcmap/core';
15
15
  import { getLogger as getLoggerByName } from '@vcsuite/logger';
16
- import {
17
- deserializePlugin,
18
- isValidPackageName,
19
- loadPlugin,
20
- serializePlugin,
21
- } from './pluginHelper.js';
16
+ import { deserializePlugin, serializePlugin } from './pluginHelper.js';
22
17
  import ToolboxManager, {
23
18
  setupDefaultGroups,
24
19
  } from './manager/toolbox/toolboxManager.js';
@@ -54,8 +49,15 @@ import { callbackClassRegistry } from './callback/vcsCallback.js';
54
49
  /**
55
50
  * @typedef {Object} PluginConfig
56
51
  * @property {string} name
57
- * @property {string|undefined} entry
58
- * @property {string|undefined} version
52
+ * @property {string|undefined} entry - path to the plugin's index.js
53
+ * @property {string|undefined} version - version or version range
54
+ */
55
+
56
+ /**
57
+ * @typedef {Object} PluginConfigEditor
58
+ * @property {import("vue").Component} component - A editor component to configure a plugin or item
59
+ * @property {string} [collectionName='plugins'] - The collection the item belongs to. Default is plugins collection.
60
+ * @property {string} [itemName] - The item the editor can be used for. Can be a name or className. Default is the plugin's name.
59
61
  */
60
62
 
61
63
  /**
@@ -67,6 +69,8 @@ import { callbackClassRegistry } from './callback/vcsCallback.js';
67
69
  */
68
70
 
69
71
  /**
72
+ * Interface for VcsPlugins.
73
+ * The function implementing the interface should not throw!
70
74
  * @interface VcsPlugin
71
75
  * @template {Object} P
72
76
  * @template {Object} S
@@ -75,9 +79,11 @@ import { callbackClassRegistry } from './callback/vcsCallback.js';
75
79
  * @property {Object<string, *>} [i18n] - the i18n messages of this plugin
76
80
  * @property {function(VcsUiApp, S=)} initialize - called on plugin added. Is passed the VcsUiApp and optionally, the state for the plugin
77
81
  * @property {function(VcsUiApp)} onVcsAppMounted - called on mounted of VcsApp.vue
78
- * @property {function():P} [toJSON] - serialization
82
+ * @property {function():P} [toJSON] - should return the plugin's serialization excluding all default values
83
+ * @property {function():P} [getDefaultOptions] - should return the plugin's default options
84
+ * @property {function(boolean=):S|Promise<S>} [getState] - should return the plugin's state or a promise for said state. is passed a "for url" flag. If true, only the state relevant for sharing a URL should be passed and short keys shall be used
85
+ * @property {Array<PluginConfigEditor>} [getConfigEditors] - should return components for configuring the plugin or custom items defined by the plugin
79
86
  * @property {function():Promise<void>} destroy
80
- * @property {function(boolean=):S|Promise<S>} [getState] - should return the plugins state or a promise for said state. is passed a "for url" flag. If true, only the state relevant for sharing a URL should be passed and short keys shall be used
81
87
  * @api
82
88
  */
83
89
 
@@ -545,23 +551,7 @@ class VcsUiApp extends VcsApp {
545
551
  async _parseModule(module) {
546
552
  const { config } = module;
547
553
  if (Array.isArray(config.plugins)) {
548
- const plugins = await Promise.all(
549
- config.plugins.map(async (pluginConfig) => {
550
- const plugin = await loadPlugin(pluginConfig.name, pluginConfig);
551
- if (!plugin) {
552
- return null;
553
- }
554
- if (!isValidPackageName(plugin.name)) {
555
- getLogger().warning(
556
- `plugin ${plugin.name} has no valid package name!`,
557
- );
558
- }
559
- plugin[moduleIdSymbol] = module._id;
560
- return plugin;
561
- }),
562
- );
563
-
564
- plugins.filter((p) => p).map((p) => this._plugins.override(p));
554
+ await this._plugins.parseItems(config.plugins, module._id);
565
555
  }
566
556
  if (Array.isArray(config.i18n)) {
567
557
  await this.i18n.parseItems(config.i18n, module._id);
@@ -1 +0,0 @@
1
- import{initAppFromAppConfig as p}from"./ui.d3054c.js";p("#app","app.config.json");
File without changes
File without changes