@kalisio/kdk 2.2.0 → 2.2.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 (75) hide show
  1. package/core/api/application.js +2 -3
  2. package/core/client/components/KModal.vue +1 -1
  3. package/core/client/components/form/KForm.vue +12 -3
  4. package/core/client/components/media/KColorScale.vue +1 -1
  5. package/core/client/exporter.js +14 -8
  6. package/core/client/mixins/mixin.base-field.js +4 -1
  7. package/core/client/units.js +3 -3
  8. package/core/client/utils/utils.shapes.js +1 -1
  9. package/extras/icons/wind-speed-0.svg +8 -0
  10. package/extras/icons/wind-speed-10.svg +8 -0
  11. package/extras/icons/wind-speed-100.svg +12 -0
  12. package/extras/icons/wind-speed-105.svg +13 -0
  13. package/extras/icons/wind-speed-15.svg +9 -0
  14. package/extras/icons/wind-speed-20.svg +9 -0
  15. package/extras/icons/wind-speed-25.svg +10 -0
  16. package/extras/icons/wind-speed-30.svg +10 -0
  17. package/extras/icons/wind-speed-35.svg +11 -0
  18. package/extras/icons/wind-speed-40.svg +11 -0
  19. package/extras/icons/wind-speed-45.svg +12 -0
  20. package/extras/icons/wind-speed-5.svg +9 -0
  21. package/extras/icons/wind-speed-50.svg +9 -0
  22. package/extras/icons/wind-speed-55.svg +10 -0
  23. package/extras/icons/wind-speed-60.svg +10 -0
  24. package/extras/icons/wind-speed-65.svg +11 -0
  25. package/extras/icons/wind-speed-70.svg +11 -0
  26. package/extras/icons/wind-speed-75.svg +12 -0
  27. package/extras/icons/wind-speed-80.svg +12 -0
  28. package/extras/icons/wind-speed-85.svg +13 -0
  29. package/extras/icons/wind-speed-90.svg +13 -0
  30. package/extras/icons/wind-speed-95.svg +14 -0
  31. package/map/api/hooks/hooks.query.js +34 -11
  32. package/map/client/cesium/utils/index.js +2 -1
  33. package/map/client/cesium/utils/utils.features.js +8 -0
  34. package/map/client/cesium/utils/utils.style.js +4 -4
  35. package/map/client/components/KFeatureEditor.vue +2 -3
  36. package/map/client/components/KLayerStyleForm.vue +32 -24
  37. package/map/client/components/KTimezoneMap.vue +3 -4
  38. package/map/client/components/catalog/KConnectLayer.vue +14 -10
  39. package/map/client/components/legend/KColorScaleLegend.vue +6 -2
  40. package/map/client/components/legend/KLayerLegend.vue +13 -3
  41. package/map/client/components/legend/KLegend.vue +12 -10
  42. package/map/client/components/location/KLocationCardSection.vue +8 -4
  43. package/map/client/components/widget/KTimeSeries.vue +0 -6
  44. package/map/client/composables/catalog.js +17 -2
  45. package/map/client/composables/highlight.js +9 -30
  46. package/map/client/composables/probe.js +4 -1
  47. package/map/client/composables/weather.js +3 -3
  48. package/map/client/i18n/map_en.json +4 -0
  49. package/map/client/i18n/map_fr.json +4 -0
  50. package/map/client/leaflet/ShapeMarker.js +23 -12
  51. package/map/client/leaflet/TiledFeatureLayer.js +38 -8
  52. package/map/client/leaflet/TiledMeshLayer.js +3 -1
  53. package/map/client/leaflet/utils/utils.style.js +7 -3
  54. package/map/client/mixins/globe/mixin.base-globe.js +29 -16
  55. package/map/client/mixins/globe/mixin.geojson-layers.js +7 -0
  56. package/map/client/mixins/map/mixin.base-map.js +40 -17
  57. package/map/client/mixins/map/mixin.geojson-layers.js +7 -3
  58. package/map/client/mixins/mixin.activity.js +5 -1
  59. package/map/client/planets.js +8 -0
  60. package/map/client/utils/utils.catalog.js +17 -0
  61. package/map/client/utils/utils.layers.js +2 -1
  62. package/map/client/utils/utils.schema.js +0 -28
  63. package/map/client/utils/utils.style.js +12 -0
  64. package/map/common/wms-utils.js +8 -3
  65. package/package.json +1 -1
  66. package/test/client/core/layout.js +0 -1
  67. package/test/client/map/catalog.js +1 -1
  68. package/test/api/core/test-log-2023-12-19.log +0 -7
  69. package/test/api/core/test-log-2024-01-04.log +0 -14
  70. package/test/api/map/test-log-2023-11-24.log +0 -121
  71. package/test/api/map/test-log-2023-12-12.log +0 -29
  72. package/test/api/map/test-log-2023-12-13.log +0 -5
  73. package/test/api/map/test-log-2024-01-04.log +0 -2
  74. package/test/api/map/test-log-2024-01-11.log +0 -1
  75. package/test/api/map/test-log-2024-01-25.log +0 -19
@@ -281,13 +281,15 @@ const TiledMeshLayer = L.GridLayer.extend({
281
281
  },
282
282
 
283
283
  updateColorMap () {
284
+ const chromajs = this.conf.chromajs
285
+ if (_.isNil(chromajs)) return
286
+
284
287
  // create color map using domain or classes
285
288
  // domain and classes can be specified from options
286
289
  // if not, domain can be gathered from grid source
287
290
  this.colorMap = null
288
291
  this.colorMapShaderCode = null
289
292
 
290
- const chromajs = _.get(this.conf, 'chromajs')
291
293
  const classes = chromajs.classes
292
294
  let domain
293
295
  if (!classes) {
@@ -4,6 +4,7 @@ import chroma from 'chroma-js'
4
4
  import moment from 'moment'
5
5
  import L from 'leaflet'
6
6
  import { Time, Units, utils as kdkCoreUtils } from '../../../../core/client/index.js'
7
+ import { getFeatureStyleType } from '../../utils/utils.features.js'
7
8
  import { convertStyle, convertSimpleStyleToPointStyle, convertSimpleStyleToLineStyle, convertSimpleStyleToPolygonStyle,
8
9
  PointStyleTemplateMappings, LineStyleTemplateMappings, PolygonStyleTemplateMappings } from '../../utils/utils.style.js'
9
10
  import { ShapeMarker } from '../ShapeMarker.js'
@@ -68,13 +69,15 @@ const LineStyleToLeafletPath = {
68
69
  cap: 'lineCap',
69
70
  join: 'lineJoin',
70
71
  dashArray: 'dashArray',
71
- dashOffset: 'dashOffset'
72
+ dashOffset: 'dashOffset',
73
+ pane: 'pane'
72
74
  }
73
75
 
74
76
  const PolygonStyleToLeafletPath = {
75
77
  color: 'fillColor',
76
78
  opacity: 'fillOpacity',
77
79
  rule: 'fillRule',
80
+ pane: 'pane'
78
81
  }
79
82
 
80
83
  // TODO: to be removed when updating 3D style
@@ -158,8 +161,9 @@ function processStyle (style, feature, options, mappings) {
158
161
  })
159
162
  }
160
163
  // We manage panes for z-index, so we need to forward it to marker options (only if not already defined)
161
- if (leafletOptions.pane && !style.pane) style.pane = leafletOptions.pane
162
- if (leafletOptions.shadowPane && !style.shadowPane) style.shadowPane = leafletOptions.shadowPane
164
+ const type = getFeatureStyleType(feature)
165
+ if (leafletOptions.pane && !_.has(style, `${type}.pane`)) _.set(style, `${type}.pane`, leafletOptions.pane)
166
+ if (leafletOptions.shadowPane && !_.has(style, `${type}.shadowPane`)) _.set(style, `${type}.shadowPane`, leafletOptions.shadowPane)
163
167
  return style
164
168
  }
165
169
 
@@ -3,12 +3,11 @@ import sift from 'sift'
3
3
  import logger from 'loglevel'
4
4
  import Emitter from 'tiny-emitter'
5
5
  import { getCssVar } from 'quasar'
6
- import { kml } from '@tmcw/togeojson'
7
6
  import Cesium from 'cesium/Source/Cesium.js'
8
7
  import 'cesium/Source/Widgets/widgets.css'
9
8
  import BuildModuleUrl from 'cesium/Source/Core/buildModuleUrl.js'
10
9
  import { Geolocation } from '../../geolocation.js'
11
- import { convertCesiumHandlerEvent, isTerrainLayer } from '../../utils.globe.js'
10
+ import { convertCesiumHandlerEvent, isTerrainLayer, convertEntitiesToGeoJson } from '../../utils.globe.js'
12
11
  // Cesium has its own dynamic module loader requiring to be configured
13
12
  // Cesium files need to be also added as static assets of the applciation
14
13
  BuildModuleUrl.setBaseUrl('/Cesium/')
@@ -279,6 +278,12 @@ export const baseGlobe = {
279
278
  clearLayers () {
280
279
  Object.keys(this.layers).forEach((layer) => this.removeLayer(layer))
281
280
  },
281
+ async toGeoJson (name) {
282
+ const layer = this.getCesiumLayerByName(name)
283
+ if (!layer.entities) return
284
+ const geoJson = await convertEntitiesToGeoJson(layer.entities)
285
+ return geoJson
286
+ },
282
287
  zoomToBounds (bounds) {
283
288
  this.viewer.camera.flyTo({
284
289
  duration: 0,
@@ -402,7 +407,7 @@ export const baseGlobe = {
402
407
  }
403
408
  return position
404
409
  },
405
- getDefaultPickHandler (event) {
410
+ async getDefaultPickHandler (event) {
406
411
  const emittedEvent = {}
407
412
  let options
408
413
  let pickedPosition = this.viewer.camera.pickEllipsoid(event.endPosition || event.position, this.viewer.scene.globe.ellipsoid)
@@ -422,24 +427,32 @@ export const baseGlobe = {
422
427
  emittedEvent.target = pickedObject.id || pickedObject.primitive.id
423
428
  if (emittedEvent.target instanceof Cesium.Entity) {
424
429
  // If feature have been lost at import try to recreate it in order to be compatible with 2D
430
+ // We attach it to the target entity so that we won't compute it each time the mouse move
431
+ // FIXME: should it be a problem with real-time updates ?
425
432
  if (!emittedEvent.target.feature) {
426
- let feature = { type: 'Feature' }
427
- /* FIXME: Generate GeoJson feature if possible (requires Cesium 1.59)
428
- However this does not work yet and could be too much slow
433
+ // Cesium expect id to be in a 'id' property but internally we use _id
434
+ // Get it back as otherwise it might break code relying on feature ID
435
+ let feature = {
436
+ _id: emittedEvent.target.id,
437
+ type: 'Feature'
438
+ }
439
+ // Generate GeoJson feature if possible (requires Cesium 1.59)
429
440
  if (typeof Cesium.exportKml === 'function') {
430
441
  const selection = new Cesium.EntityCollection()
431
442
  selection.add(emittedEvent.target)
432
- const kmlEntities = await Cesium.exportKml({ entities: selection, modelCallback: () => '' })
433
- const geoJson = kml(kmlEntities.kml)
434
- if (geoJson.features.length > 0) feature = geoJson.features[0]
443
+ const geoJson = await convertEntitiesToGeoJson(selection)
444
+ if (geoJson.features.length > 0) {
445
+ Object.assign(feature, geoJson.features[0])
446
+ }
435
447
  }
436
- */
437
- const position = Cesium.Cartographic.fromCartesian(emittedEvent.target.position
438
- ? emittedEvent.target.position.getValue(0)
439
- : emittedEvent.pickedPosition)
440
- feature.geometry = {
441
- type: 'Point',
442
- coordinates: [Cesium.Math.toDegrees(position.longitude), Cesium.Math.toDegrees(position.latitude)]
448
+ if (!feature.geometry) {
449
+ const position = Cesium.Cartographic.fromCartesian(emittedEvent.target.position
450
+ ? emittedEvent.target.position.getValue(0)
451
+ : emittedEvent.pickedPosition)
452
+ feature.geometry = {
453
+ type: 'Point',
454
+ coordinates: [Cesium.Math.toDegrees(position.longitude), Cesium.Math.toDegrees(position.latitude)]
455
+ }
443
456
  }
444
457
  feature.properties = (emittedEvent.target.properties ? emittedEvent.target.properties.getValue(0) : {})
445
458
  emittedEvent.target.feature = feature
@@ -2,6 +2,7 @@ import Cesium from 'cesium/Source/Cesium.js'
2
2
  import _ from 'lodash'
3
3
  import logger from 'loglevel'
4
4
  import sift from 'sift'
5
+ import { uid } from 'quasar'
5
6
  import { Time } from '../../../../core/client/time.js'
6
7
  import { fetchGeoJson, getFeatureId, processFeatures, getFeatureStyleType, isInMemoryLayer } from '../../utils.js'
7
8
  import { convertSimpleStyleToPointStyle, convertSimpleStyleToLineStyle, convertSimpleStyleToPolygonStyle } from '../../utils/utils.style.js'
@@ -120,6 +121,10 @@ export const geojsonLayers = {
120
121
  }
121
122
  })
122
123
  }
124
+ // Billboard with 'none' shape should be removed as Cesium creates it even if the maki icon id is unknown
125
+ if (entity.billboard && (_.get(properties, 'marker-symbol') === 'none')) {
126
+ entitiesToRemove.push(entity)
127
+ }
123
128
  // Labels
124
129
  const text = _.get(properties, 'icon-text')
125
130
  if (text) {
@@ -197,6 +202,8 @@ export const geojsonLayers = {
197
202
  if (cesiumOptions.type !== 'geoJson') return
198
203
  const engine = _.get(this, 'activityOptions.engine')
199
204
  options.processor = (feature) => {
205
+ // File import
206
+ if (!options.featureId && !feature._id) feature._id = uid().toString()
200
207
  // Cesium expect id to be in a 'id' property
201
208
  feature.id = getFeatureId(feature, options)
202
209
  // We cannot access data outside the properties object of a feature in Cesium
@@ -1,6 +1,7 @@
1
1
  import _ from 'lodash'
2
2
  import sift from 'sift'
3
3
  import logger from 'loglevel'
4
+ import moment from 'moment'
4
5
  import L from 'leaflet'
5
6
  import Emitter from 'tiny-emitter'
6
7
  import 'leaflet/dist/leaflet.css'
@@ -146,14 +147,20 @@ export const baseMap = {
146
147
  leafletOptions.attribution = processedOptions.attribution
147
148
  return processedOptions
148
149
  },
150
+ getLeafletPaneName (paneOrZIndex) {
151
+ return (typeof paneOrZIndex === 'object' ? paneOrZIndex.name || paneOrZIndex.zIndex.toString() : paneOrZIndex.toString())
152
+ },
149
153
  createLeafletPane (paneOrZIndex) {
150
- // Create pane if required
151
- const paneName = paneOrZIndex.toString()
154
+ // Input can be a name, a z-index, an object with both options
155
+ const paneName = this.getLeafletPaneName(paneOrZIndex)
152
156
  let pane = this.map.getPane(paneName)
157
+ // Create pane if required
153
158
  if (!pane) {
159
+ let zIndex
160
+ if (typeof paneOrZIndex === 'object') zIndex = paneOrZIndex.zIndex || 400
161
+ else if (typeof paneOrZIndex === 'number') zIndex = paneOrZIndex
154
162
  pane = this.map.createPane(paneName)
155
- if (typeof paneOrZIndex === 'number') _.set(pane, 'style.zIndex', paneOrZIndex)
156
- else _.set(pane, 'style.zIndex', 400) // Defaults for overlay in Leaflet
163
+ _.set(pane, 'style.zIndex', zIndex || 400) // Defaults for overlay in Leaflet
157
164
  }
158
165
  this.leafletPanes[paneName] = pane
159
166
  return pane
@@ -168,12 +175,10 @@ export const baseMap = {
168
175
  if (!pane) return
169
176
  delete this.leafletPanes[paneName]
170
177
  },
171
- updateLeafletPanesVisibility (panes) {
178
+ updateLeafletPanesVisibility () {
172
179
  const zoom = this.map.getZoom()
173
180
  // Check if we need to hide/show some panes based on current zoom level
174
181
  _.forOwn(this.leafletPanes, (pane, paneName) => {
175
- // Filter only some panes ?
176
- if (panes && panes.includes(paneName)) return
177
182
  const hasMinZoom = !!_.get(pane, 'minZoom')
178
183
  const hasMaxZoom = !!_.get(pane, 'maxZoom')
179
184
  if (!hasMinZoom && !hasMaxZoom) return
@@ -207,10 +212,10 @@ export const baseMap = {
207
212
  const panes = _.get(leafletOptions, 'panes')
208
213
  if (panes) {
209
214
  panes.forEach(paneOptions => {
210
- const pane = this.createLeafletPane(paneOptions.name || paneOptions.zIndex)
215
+ const pane = this.createLeafletPane(paneOptions)
211
216
  Object.assign(pane, paneOptions)
212
217
  })
213
- this.updateLeafletPanesVisibility(panes.map(paneOptions => paneOptions.name || paneOptions.zIndex.toString()))
218
+ this.updateLeafletPanesVisibility()
214
219
  }
215
220
 
216
221
  // Some Leaflet constructors can have additional arguments given as options
@@ -256,19 +261,36 @@ export const baseMap = {
256
261
  if (timeDimension) {
257
262
  // It appears that sometimes the time resolution is missing, default as 1 day
258
263
  // Please refer to https://www.mapserver.org/ogc/wms_time.html#specifying-time-extents
264
+ _.set(timeDimension, 'period', 'P1D')
259
265
  const timeRange = _.get(timeDimension, 'times')
260
- if ((typeof timeRange === 'string') && (timeRange.split('/').length === 2)) {
266
+ const timeRangeComponents = (typeof timeRange === 'string' ? timeRange.split('/') : [])
267
+ if (timeRangeComponents.length === 2) {
261
268
  _.set(timeDimension, 'times', `${timeRange}/P1D`)
269
+ } else if (timeRangeComponents.length === 3) {
270
+ _.set(timeDimension, 'period', timeRangeComponents[2])
262
271
  }
272
+ // Used to format time accordingly
273
+ const periodAsDuration = moment.duration(_.get(timeDimension, 'period'))
263
274
  // As we'd like to control time on a per-layer basis create a specific time dimension object
264
275
  layer = this.createLeafletLayer({
265
276
  type: 'timeDimension.layer.wms',
266
277
  source: layer,
267
278
  timeDimension: L.timeDimension(timeDimension),
268
- currentTime: Time.getCurrentTime()
279
+ currentTime: Time.getCurrentTime().toDate().getTime()
269
280
  })
270
281
  // This allow the layer to conform our internal time interface
271
- layer.setCurrentTime = (datetime) => { layer._timeDimension.setCurrentTime(datetime) }
282
+ layer.setCurrentTime = (datetime) => { layer._timeDimension.setCurrentTime(datetime.toDate().getTime()) }
283
+ // Default implementation always generate ISO datetime that might break some servers with eg day period only
284
+ layer._createLayerForTime = (time) => {
285
+ // Remove some internals to avoid polluting request
286
+ const wmsParams = _.omit(layer._baseLayer.options, ['timeDimension', 'isVisible', 'type'])
287
+ // Format time according to period
288
+ if (periodAsDuration.years() > 0) wmsParams.time = moment.utc(time).format('YYYY').toISOString()
289
+ else if (periodAsDuration.months() > 0) wmsParams.time = moment.utc(time).format('YYYY-MM')
290
+ else if (periodAsDuration.days() > 0) wmsParams.time = moment.utc(time).format('YYYY-MM-DD')
291
+ else wmsParams.time = moment.utc(time).toISOString()
292
+ return new layer._baseLayer.constructor(layer._baseLayer.getURL(), wmsParams)
293
+ }
272
294
  }
273
295
  return layer
274
296
  },
@@ -289,11 +311,12 @@ export const baseMap = {
289
311
  },
290
312
  updateLayerDisabled (layer) {
291
313
  const wasDisabled = layer.isDisabled
292
- layer.isDisabled = this.isLayerDisabled(layer)
293
- if (layer.isDisabled !== wasDisabled) {
294
- if (wasDisabled) this.onLayerEnabled(layer)
295
- else this.onLayerDisabled(layer)
296
- }
314
+ const isDisabled = this.isLayerDisabled(layer)
315
+ // Test if state changed
316
+ if (wasDisabled === isDisabled) return
317
+ layer.isDisabled = isDisabled
318
+ if (wasDisabled) this.onLayerEnabled(layer)
319
+ else this.onLayerDisabled(layer)
297
320
  },
298
321
  onLayerEnabled (layer) {
299
322
  this.$emit('layer-enabled', layer)
@@ -267,9 +267,13 @@ export const geojsonLayers = {
267
267
  leafletOptions.panes = [pane]
268
268
  leafletOptions.pane = options.name
269
269
  leafletOptions.shadowPane = options.name
270
- // Make pane available to point style as well as shape markers are created from here
271
- _.set(leafletOptions, 'style.point.options.pane', options.name)
272
- _.set(leafletOptions, 'style.point.options.shadowPane', options.name)
270
+ // Make pane available to styles as well as eg shape markers are created from here
271
+ for (const type in ['point', 'line', 'polygon']) {
272
+ if (_.has(leafletOptions, `style.${type}`)) {
273
+ _.set(leafletOptions, `style.${type}.pane`, options.name)
274
+ _.set(leafletOptions, `style.${type}.shadowPane`, options.name)
275
+ }
276
+ }
273
277
  }
274
278
  // If not explicitely disable use defaults for clustering
275
279
  if (!_.has(leafletOptions, 'cluster') && _.get(this, 'activityOptions.engine.cluster')) {
@@ -239,12 +239,16 @@ export const activity = {
239
239
  // Check if the activity is using context restoration
240
240
  const hasContext = (typeof this.restoreContext === 'function')
241
241
  // Retrieve the forecast models
242
- if (this.setupWeacast) {
242
+ const weacastEnabled = _.get(config, 'weacast.enabled', true)
243
+ if (weacastEnabled && this.setupWeacast) {
243
244
  try {
244
245
  await this.setupWeacast()
245
246
  } catch (error) {
246
247
  logger.error(`[KDK] ${error}`)
247
248
  }
249
+ } else {
250
+ if (weacastEnabled) logger.warn('[KDK] Weacast setup function is missing')
251
+ else logger.debug('[KDK] disabling Weacast')
248
252
  }
249
253
  // Retrieve the layers
250
254
  try {
@@ -33,6 +33,10 @@ export const Planets = {
33
33
  client.get('storage').removeItem(options.gatewayJwt)
34
34
  })
35
35
  const accessToken = await client.get('storage').getItem(options.apiJwt)
36
+ if (!accessToken) {
37
+ logger.error(new Error(`You must set planet ${name} token first`))
38
+ return
39
+ }
36
40
  await client.authenticate({
37
41
  strategy: 'jwt',
38
42
  accessToken
@@ -46,6 +50,10 @@ export const Planets = {
46
50
  delete this.planets[name]
47
51
  },
48
52
 
53
+ isConnected (name) {
54
+ return !_.isNil(this.planets[name])
55
+ },
56
+
49
57
  get (name) {
50
58
  if (!this.planets[name]) logger.error(new Error(`You must connect to planet ${name} first`))
51
59
  else return this.planets[name]
@@ -131,6 +131,23 @@ export async function getCategories (options = {}) {
131
131
  return categories
132
132
  }
133
133
 
134
+ export async function getSublegends (options = {}) {
135
+ _.defaults(options, {
136
+ query: {},
137
+ context: '',
138
+ planetApi: api
139
+ })
140
+
141
+ let sublegends = []
142
+ const catalogService = options.planetApi.getService('catalog', options.context)
143
+ if (catalogService) {
144
+ const response = await catalogService.find({ query: Object.assign({ type: 'Sublegend' }, options.query) })
145
+ _.forEach(response.data, processTranslations)
146
+ sublegends = sublegends.concat(response.data)
147
+ }
148
+ return sublegends
149
+ }
150
+
134
151
  export async function getViews (options = {}) {
135
152
  _.defaults(options, {
136
153
  query: {},
@@ -138,7 +138,8 @@ export async function saveGeoJsonLayer (layer, geoJson, chunkSize = 5000) {
138
138
  }
139
139
 
140
140
  export async function saveLayer (layer) {
141
- await api.getService('catalog').create(_.omit(layer, InternalLayerProperties))
141
+ layer = await api.getService('catalog').create(_.omit(layer, InternalLayerProperties))
142
+ return layer
142
143
  }
143
144
 
144
145
  export async function removeLayer (layer) {
@@ -44,31 +44,3 @@ export function generatePropertiesSchema (geoJson, name) {
44
44
  })
45
45
  return schema
46
46
  }
47
-
48
- export function updatePropertiesSchema (schema) {
49
- const props = schema.properties
50
- if (!props) return
51
-
52
- const bestGuesses = {
53
- undefined: 'form/KTextField',
54
- object: 'form/KTextField',
55
- string: 'form/KTextField',
56
- number: 'form/KNumberField',
57
- boolean: 'form/KToggleField'
58
- }
59
-
60
- // Loop over declared props and add best guesses to field components based on property type
61
- for (const prop in props) {
62
- const propEntry = props[prop]
63
- // Field already here, skip entry
64
- if (propEntry.field && propEntry.field.component) continue
65
-
66
- propEntry.field = {
67
- component: bestGuesses[propEntry.type],
68
- label: prop,
69
- helper: propEntry.description
70
- }
71
- }
72
-
73
- return schema
74
- }
@@ -1,4 +1,5 @@
1
1
  import _ from 'lodash'
2
+ import { getCssVar } from 'quasar'
2
3
  import { utils as kdkCoreUtils } from '../../../core/client/index.js'
3
4
 
4
5
  export const IconStyleToSimpleStyle = {
@@ -149,6 +150,17 @@ export function convertStyle (style, mapping, asNumber = []) {
149
150
  return convertedStyle
150
151
  }
151
152
 
153
+ export function convertSimpleStyleColors (style) {
154
+ // Convert from quasar color palette to actual color
155
+ _.forOwn(style, (value, key) => {
156
+ if (['stroke', 'fill', 'marker-color'].includes(key)) {
157
+ const color = getCssVar(value)
158
+ if (color) _.set(style, key, color)
159
+ }
160
+ })
161
+ return style
162
+ }
163
+
152
164
  export function convertPointStyleToSimpleStyle (style) {
153
165
  return style ? Object.assign(convertStyle(style.icon, IconStyleToSimpleStyle, SimpleStyleNumbers), convertStyle(style, PointStyleToSimpleStyle, SimpleStyleNumbers)) : {}
154
166
  }
@@ -96,15 +96,20 @@ export async function discover (url, searchParams = {}, caps = null) {
96
96
  // check for time dimension
97
97
  for (const dimension of _.get(layer, 'Dimension', [])) {
98
98
  if (_.get(dimension, '$.name', '').toLowerCase() === 'time') {
99
- _.set(obj, 'timeDimension', {})
99
+ const timeRange = _.get(dimension, '_')
100
+ // If time range is not given in dimension it should be in extent
101
+ if (timeRange) _.set(obj, 'timeDimension.times', timeRange.trim())
102
+ else if (!_.has(obj, 'timeDimension')) _.set(obj, 'timeDimension', {})
100
103
  }
101
104
  }
102
105
  // check for time range
103
106
  if (obj.timeDimension) {
104
107
  for (const extent of _.get(layer, 'Extent', [])) {
105
108
  if (_.get(extent, '$.name', '').toLowerCase() === 'time') {
106
- const timeRange = _.get(extent, '_', '').trim()
107
- _.set(obj, 'timeDimension.times', timeRange)
109
+ const timeRange = _.get(extent, '_')
110
+ // If time range is not given in extent it should be in dimension
111
+ if (timeRange) _.set(obj, 'timeDimension.times', timeRange.trim())
112
+ else if (!_.has(obj, 'timeDimension')) _.set(obj, 'timeDimension', {})
108
113
  }
109
114
  }
110
115
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kalisio/kdk",
3
3
  "description": "Kalisio Development Kit",
4
- "version": "2.2.0",
4
+ "version": "2.2.2",
5
5
  "homepage": "https://github.com/kalisio/kdk",
6
6
  "type": "module",
7
7
  "keywords": [
@@ -118,7 +118,6 @@ export async function countFabActions (page) {
118
118
  return countElements(page, '//a[contains(@class, "k-action-fab-action")]')
119
119
  }
120
120
 
121
-
122
121
  export async function closeWelcomeDialog (page) {
123
122
  await click(page, '.q-dialog #close-button')
124
123
  }
@@ -119,7 +119,7 @@ export async function dropFile (page, filePath, wait = 2000) {
119
119
  const loaderSelector = '#dropFileInput'
120
120
  const loader = await page.$(loaderSelector)
121
121
  await loader.uploadFile(filePath)
122
- await page.waitForNetworkIdle()
122
+ await page.waitForNetworkIdle()
123
123
  await page.waitForTimeout(wait)
124
124
  }
125
125
 
@@ -1,7 +0,0 @@
1
- {"level":"info","message":"This is a log test"}
2
- {"level":"error","message":"error: api/tags - Method: create: You are not allowed to access service tags"}
3
- {"level":"error","message":"error: api/users - Method: create: The provided password does not comply to the password policy"}
4
- {"level":"error","message":"error: api/users - Method: create: The provided password does not comply to the password policy"}
5
- {"level":"error","message":"error: api/authorisations - Method: create: You are not allowed to change authorisation on resource"}
6
- {"level":"error","message":"error: api/authorisations - Method: remove: You are not allowed to change authorisation on subject(s)"}
7
- {"level":"info","message":"This is a log test"}
@@ -1,14 +0,0 @@
1
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
2
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
3
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
4
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
5
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
6
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
7
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
8
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
9
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
10
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
11
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
12
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
13
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}
14
- {"level":"error","message":"error: api/account - Method: create: The provided password does not comply to the password policy"}