@kalisio/kdk 2.1.9 → 2.2.1

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 (272) hide show
  1. package/.travis.test.sh +42 -10
  2. package/README.md +2 -2
  3. package/core/api/application.js +7 -2
  4. package/core/api/authentication.js +17 -1
  5. package/core/api/db.js +7 -2
  6. package/core/api/hooks/hooks.authentication.js +4 -2
  7. package/core/api/hooks/hooks.authorisations.js +12 -2
  8. package/core/api/hooks/hooks.model.js +5 -5
  9. package/core/api/hooks/hooks.organisations.js +0 -4
  10. package/core/api/services/account/account.hooks.js +10 -6
  11. package/core/api/services/account/account.service.js +1 -1
  12. package/{map/api/services/geocoder/geocoder.hooks.js → core/api/services/import-export/import-export.hooks.js} +7 -5
  13. package/core/api/services/import-export/import-export.service.js +11 -0
  14. package/core/api/services/index.js +13 -1
  15. package/core/api/services/users/users.hooks.js +2 -3
  16. package/core/client/api.js +16 -14
  17. package/core/client/capabilities.js +6 -2
  18. package/core/client/components/KContent.vue +11 -1
  19. package/core/client/components/KDialog.vue +17 -15
  20. package/core/client/components/KModal.vue +1 -1
  21. package/core/client/components/KSponsor.vue +1 -1
  22. package/core/client/components/KTextArea.vue +5 -1
  23. package/core/client/components/app/KAbout.vue +1 -2
  24. package/core/client/components/app/KWelcome.vue +3 -5
  25. package/core/client/components/chart/KTimeSeriesChart.vue +24 -37
  26. package/core/client/components/collection/KColumn.vue +20 -17
  27. package/core/client/components/editor/KModalEditor.vue +0 -2
  28. package/core/client/components/form/KChipsField.vue +12 -2
  29. package/core/client/components/form/KColorField.vue +12 -2
  30. package/core/client/components/form/KColorScaleField.vue +12 -2
  31. package/core/client/components/form/KDateTimeRangeField.vue +12 -2
  32. package/core/client/components/form/KDatetimeField.vue +12 -2
  33. package/core/client/components/form/KEmailField.vue +12 -2
  34. package/core/client/components/form/KFileField.vue +12 -2
  35. package/core/client/components/form/KForm.vue +47 -9
  36. package/core/client/components/form/KIconField.vue +12 -2
  37. package/core/client/components/form/KItemField.vue +25 -4
  38. package/core/client/components/form/KNumberField.vue +12 -2
  39. package/core/client/components/form/KOptionsField.vue +12 -2
  40. package/core/client/components/form/KPasswordField.vue +12 -2
  41. package/core/client/components/form/KPhoneField.vue +13 -3
  42. package/core/client/components/form/KPropertyItemField.vue +12 -2
  43. package/core/client/components/form/KResolutionField.vue +126 -0
  44. package/core/client/components/form/KRoleField.vue +12 -2
  45. package/core/client/components/form/KSelectField.vue +14 -4
  46. package/core/client/components/form/KTextField.vue +12 -2
  47. package/core/client/components/form/KTextareaField.vue +13 -3
  48. package/core/client/components/form/KToggleField.vue +12 -2
  49. package/core/client/components/form/KTokenField.vue +12 -2
  50. package/core/client/components/form/KUnitField.vue +12 -2
  51. package/core/client/components/form/KUrlField.vue +12 -2
  52. package/core/client/components/input/KIconChooser.vue +10 -12
  53. package/core/client/components/input/KPalette.vue +2 -1
  54. package/core/client/components/layout/KPage.vue +5 -4
  55. package/core/client/components/layout/KWindow.vue +10 -10
  56. package/core/client/components/media/KColorScale.vue +25 -19
  57. package/core/client/components/media/KImageViewer.vue +57 -33
  58. package/core/client/components/media/KShape.vue +14 -103
  59. package/core/client/components/screen/KRegisterScreen.vue +0 -1
  60. package/core/client/components/screen/KScreenFooter.vue +0 -18
  61. package/core/client/components/team/KAddMember.vue +16 -22
  62. package/core/client/components/team/KGroupsActivity.vue +14 -0
  63. package/core/client/components/team/KMembersActivity.vue +12 -0
  64. package/core/client/components/team/KTagsActivity.vue +14 -0
  65. package/core/client/components/time/KDateTime.vue +23 -7
  66. package/core/client/components/time/KTimeControl.vue +142 -0
  67. package/core/client/components/tool/KExportTool.vue +57 -0
  68. package/core/client/composables/collection.js +0 -1
  69. package/core/client/composables/pwa.js +0 -1
  70. package/core/client/composables/schema.js +1 -1
  71. package/core/client/composables/session.js +30 -6
  72. package/core/client/exporter.js +147 -0
  73. package/core/client/i18n/core_en.json +91 -23
  74. package/core/client/i18n/core_fr.json +92 -23
  75. package/core/client/index.js +3 -0
  76. package/core/client/layout.js +34 -14
  77. package/core/client/local-storage.js +8 -6
  78. package/core/client/mixins/index.js +0 -1
  79. package/core/client/mixins/mixin.base-field.js +24 -2
  80. package/core/client/mixins/mixin.object-proxy.js +0 -1
  81. package/core/client/search.js +2 -1
  82. package/core/client/services/index.js +2 -1
  83. package/core/client/services/local-settings.service.js +4 -4
  84. package/core/client/theme.js +3 -3
  85. package/core/client/time.js +4 -0
  86. package/core/client/units.js +150 -5
  87. package/core/client/utils/index.js +13 -6
  88. package/core/client/utils/utils.account.js +1 -1
  89. package/core/client/utils/utils.colors.js +43 -0
  90. package/core/client/utils/utils.platform.js +0 -1
  91. package/core/client/utils/utils.pwa.js +14 -14
  92. package/core/client/utils/utils.session.js +1 -1
  93. package/core/client/utils/utils.shapes.js +270 -0
  94. package/core/client/utils/utils.time.js +37 -0
  95. package/core/common/permissions.js +3 -0
  96. package/core/common/schemas/settings.update.json +50 -29
  97. package/extras/css/core.variables.scss +3 -1
  98. package/extras/icons/wind-speed-0.svg +8 -0
  99. package/extras/icons/wind-speed-10.svg +8 -0
  100. package/extras/icons/wind-speed-100.svg +12 -0
  101. package/extras/icons/wind-speed-105.svg +13 -0
  102. package/extras/icons/wind-speed-15.svg +9 -0
  103. package/extras/icons/wind-speed-20.svg +9 -0
  104. package/extras/icons/wind-speed-25.svg +10 -0
  105. package/extras/icons/wind-speed-30.svg +10 -0
  106. package/extras/icons/wind-speed-35.svg +11 -0
  107. package/extras/icons/wind-speed-40.svg +11 -0
  108. package/extras/icons/wind-speed-45.svg +12 -0
  109. package/extras/icons/wind-speed-5.svg +9 -0
  110. package/extras/icons/wind-speed-50.svg +9 -0
  111. package/extras/icons/wind-speed-55.svg +10 -0
  112. package/extras/icons/wind-speed-60.svg +10 -0
  113. package/extras/icons/wind-speed-65.svg +11 -0
  114. package/extras/icons/wind-speed-70.svg +11 -0
  115. package/extras/icons/wind-speed-75.svg +12 -0
  116. package/extras/icons/wind-speed-80.svg +12 -0
  117. package/extras/icons/wind-speed-85.svg +13 -0
  118. package/extras/icons/wind-speed-90.svg +13 -0
  119. package/extras/icons/wind-speed-95.svg +14 -0
  120. package/extras/tours/map/navigation-bar.js +17 -15
  121. package/extras/tours/map/timeline.js +33 -33
  122. package/map/api/config/categories.cjs +4 -1
  123. package/map/api/hooks/hooks.catalog.js +39 -0
  124. package/map/api/hooks/hooks.features.js +23 -3
  125. package/map/api/hooks/hooks.query.js +65 -21
  126. package/map/api/models/projects.model.mongodb.js +8 -0
  127. package/map/api/services/catalog/catalog.hooks.js +5 -3
  128. package/map/api/services/features/features.hooks.js +18 -6
  129. package/map/api/services/index.js +22 -6
  130. package/map/api/services/projects/projects.hooks.js +118 -0
  131. package/map/client/capture.js +16 -0
  132. package/map/client/cesium/utils/index.js +4 -0
  133. package/map/client/cesium/utils/utils.events.js +30 -0
  134. package/map/client/cesium/utils/utils.features.js +8 -0
  135. package/map/client/cesium/utils/utils.popup.js +17 -0
  136. package/map/client/cesium/utils/utils.style.js +137 -0
  137. package/map/client/components/KCapture.vue +50 -0
  138. package/map/client/components/KCaptureTextArea.vue +53 -0
  139. package/map/client/components/KCompass.vue +2 -2
  140. package/map/client/components/KFeaturesChart.vue +1 -1
  141. package/map/client/components/KFeaturesFilter.vue +2 -2
  142. package/map/client/components/KLayerStyleForm.vue +288 -454
  143. package/map/client/components/KLevelSlider.vue +1 -1
  144. package/map/client/components/KNorth.vue +31 -0
  145. package/map/client/components/KProjectMenu.vue +88 -0
  146. package/map/client/components/KTimezoneMap.vue +36 -24
  147. package/map/client/components/catalog/KAddLayer.vue +3 -4
  148. package/map/client/components/catalog/KConnectLayer.vue +20 -4
  149. package/map/client/components/catalog/KCreateLayer.vue +1 -2
  150. package/map/client/components/catalog/KCreateProject.vue +100 -0
  151. package/map/client/components/catalog/KCreateView.vue +25 -2
  152. package/map/client/components/catalog/KLayersPanel.vue +24 -27
  153. package/map/client/components/catalog/KLayersSelector.vue +1 -1
  154. package/map/client/components/catalog/KProjectEditor.vue +91 -0
  155. package/map/client/components/catalog/KProjectManager.vue +60 -0
  156. package/map/client/components/catalog/KProjectSelector.vue +38 -0
  157. package/map/client/components/catalog/KProjectsPanel.vue +153 -0
  158. package/map/client/components/catalog/KSelectLayers.vue +96 -0
  159. package/map/client/components/catalog/KSelectViews.vue +96 -0
  160. package/map/client/components/catalog/KViewsPanel.vue +66 -30
  161. package/map/client/components/form/KDirectionField.vue +24 -5
  162. package/map/client/components/form/KLayerCategoryField.vue +12 -2
  163. package/map/client/components/form/KLocationField.vue +20 -5
  164. package/map/client/components/form/KOwsLayerField.vue +12 -2
  165. package/map/client/components/form/KOwsServiceField.vue +12 -2
  166. package/map/client/components/form/KSelectLayersField.vue +159 -0
  167. package/map/client/components/form/KSelectViewsField.vue +121 -0
  168. package/map/client/components/form/KTimezoneField.vue +24 -17
  169. package/map/client/components/legend/KColorScaleLegend.vue +6 -2
  170. package/map/client/components/legend/KLayerLegend.vue +71 -0
  171. package/map/client/components/legend/KLegend.vue +54 -51
  172. package/map/client/components/legend/KLegendRenderer.vue +5 -3
  173. package/map/client/components/legend/KSymbolsLegend.vue +12 -10
  174. package/map/client/components/legend/KVariablesLegend.vue +78 -0
  175. package/map/client/components/location/KGeocodersFilter.vue +2 -4
  176. package/map/client/components/location/KLocationCardSection.vue +8 -4
  177. package/map/client/components/location/KLocationMap.vue +48 -17
  178. package/map/client/components/location/KLocationSearch.vue +13 -3
  179. package/map/client/components/tools/KSearchTool.vue +17 -12
  180. package/map/client/components/widget/KElevationProfile.vue +16 -19
  181. package/map/client/components/widget/KMapillaryViewer.vue +21 -22
  182. package/map/client/components/widget/KTimeSeries.vue +35 -29
  183. package/map/client/composables/activity.js +15 -2
  184. package/map/client/composables/catalog.js +81 -0
  185. package/map/client/composables/highlight.js +45 -30
  186. package/map/client/composables/index.js +2 -0
  187. package/map/client/composables/location.js +25 -18
  188. package/map/client/composables/probe.js +4 -1
  189. package/map/client/composables/project.js +122 -0
  190. package/map/client/composables/weather.js +3 -3
  191. package/map/client/geolocation.js +1 -1
  192. package/map/client/globe.js +2 -0
  193. package/map/client/i18n/map_en.json +127 -76
  194. package/map/client/i18n/map_fr.json +128 -72
  195. package/map/client/index.js +3 -0
  196. package/map/client/init.js +17 -0
  197. package/map/client/leaflet/GSMaPLayer.js +16 -17
  198. package/map/client/leaflet/ShapeMarker.js +51 -0
  199. package/map/client/leaflet/TiledFeatureLayer.js +39 -9
  200. package/map/client/leaflet/TiledMeshLayer.js +13 -15
  201. package/map/client/leaflet/TiledWindLayer.js +6 -10
  202. package/map/client/leaflet/utils/index.js +4 -0
  203. package/map/client/leaflet/utils/utils.events.js +41 -0
  204. package/map/client/leaflet/utils/utils.popup.js +21 -0
  205. package/map/client/leaflet/utils/utils.style.js +195 -0
  206. package/map/client/leaflet/utils/utils.tiles.js +87 -0
  207. package/map/client/map.js +2 -0
  208. package/map/client/mixins/globe/mixin.base-globe.js +39 -18
  209. package/map/client/mixins/globe/mixin.geojson-layers.js +139 -69
  210. package/map/client/mixins/globe/mixin.popup.js +2 -1
  211. package/map/client/mixins/globe/mixin.style.js +6 -4
  212. package/map/client/mixins/globe/mixin.tooltip.js +8 -3
  213. package/map/client/mixins/map/mixin.base-map.js +53 -28
  214. package/map/client/mixins/map/mixin.edit-layers.js +15 -15
  215. package/map/client/mixins/map/mixin.forecast-layers.js +3 -1
  216. package/map/client/mixins/map/mixin.geojson-layers.js +60 -20
  217. package/map/client/mixins/map/mixin.georaster-layers.js +4 -11
  218. package/map/client/mixins/map/mixin.heatmap-layers.js +1 -1
  219. package/map/client/mixins/map/mixin.popup.js +2 -1
  220. package/map/client/mixins/map/mixin.style.js +4 -67
  221. package/map/client/mixins/map/mixin.tiled-mesh-layers.js +2 -1
  222. package/map/client/mixins/map/mixin.tiled-wind-layers.js +4 -2
  223. package/map/client/mixins/map/mixin.tooltip.js +2 -1
  224. package/map/client/mixins/mixin.activity.js +71 -192
  225. package/map/client/mixins/mixin.catalog-panel.js +6 -6
  226. package/map/client/mixins/mixin.context.js +12 -9
  227. package/map/client/mixins/mixin.feature-service.js +29 -300
  228. package/map/client/mixins/mixin.weacast.js +11 -17
  229. package/map/client/pixi-utils.js +1 -1
  230. package/map/client/planets.js +66 -0
  231. package/map/client/utils/index.js +6 -0
  232. package/map/client/utils/utils.capture.js +176 -0
  233. package/map/client/utils/utils.catalog.js +166 -0
  234. package/map/client/utils/utils.features.js +364 -0
  235. package/map/client/utils/utils.js +0 -151
  236. package/map/client/utils/utils.layers.js +175 -0
  237. package/map/client/utils/utils.location.js +91 -23
  238. package/map/client/utils/utils.project.js +8 -0
  239. package/map/client/utils/utils.schema.js +0 -1
  240. package/map/client/utils/utils.style.js +309 -0
  241. package/map/client/utils.all.js +2 -2
  242. package/map/client/utils.globe.js +1 -1
  243. package/map/client/utils.map.js +1 -1
  244. package/map/common/permissions.js +2 -0
  245. package/map/common/schemas/capture.create.json +132 -0
  246. package/map/common/schemas/projects.create.json +52 -0
  247. package/map/common/schemas/projects.update.json +52 -0
  248. package/map/common/wms-utils.js +8 -3
  249. package/package.json +6 -5
  250. package/test/api/core/account.test.js +20 -0
  251. package/test/api/core/config/default.cjs +16 -3
  252. package/test/api/core/import-export.test.js +86 -0
  253. package/test/api/core/test-log-2024-01-04.log +14 -0
  254. package/test/api/map/catalog.test.js +164 -0
  255. package/test/api/map/index.test.js +25 -61
  256. package/test/api/map/test-log-2024-01-04.log +2 -0
  257. package/test/api/map/test-log-2024-01-11.log +1 -0
  258. package/test/api/map/test-log-2024-01-25.log +19 -0
  259. package/test/client/core/layout.js +24 -5
  260. package/test/client/core/utils.js +7 -0
  261. package/test/client/map/catalog.js +78 -1
  262. package/test/client/map/time.js +2 -1
  263. package/core/client/components/screen/KEndpointScreen.vue +0 -80
  264. package/core/client/mixins/mixin.account.js +0 -61
  265. package/extras/icons/kdk.png +0 -0
  266. package/map/api/services/geocoder/geocoder.service.js +0 -79
  267. package/map/client/cesium/utils.js +0 -133
  268. package/map/client/components/KCaptureToolbar.vue +0 -155
  269. package/map/client/components/KColorLegend.vue +0 -349
  270. package/map/client/components/KTimeline.vue +0 -293
  271. package/map/client/components/KUrlLegend.vue +0 -122
  272. package/map/client/leaflet/utils.js +0 -246
@@ -26,11 +26,7 @@ import { i18n } from '../../i18n'
26
26
  // unit:
27
27
  // }
28
28
 
29
- let canvas = null
30
- let chart = null
31
- const unit2axis = new Map()
32
-
33
- const emit = defineEmits(['zoom-start', 'zoom-end', 'legend-click'])
29
+ // Props
34
30
  const props = defineProps({
35
31
  timeSeries: { type: Array, default: () => [] },
36
32
  xAxisKey: { type: String, default: 'x' },
@@ -44,19 +40,19 @@ const props = defineProps({
44
40
  options: { type: Object, default: () => ({}) }
45
41
  })
46
42
 
47
- defineExpose({
48
- update,
49
- getZoom,
50
- exportSeries
51
- })
43
+ // Emits
44
+ const emit = defineEmits(['zoom-start', 'zoom-end', 'legend-click'])
52
45
 
53
- // data
46
+ // Data
47
+ let canvas = null
48
+ let chart = null
49
+ const unit2axis = new Map()
54
50
  const startTime = ref(props.startTime ? moment.utc(props.startTime) : null)
55
51
  const endTime = ref(props.endTime ? moment.utc(props.endTime) : null)
56
52
  let min = null
57
53
  let max = null
58
54
 
59
- // watch
55
+ // Watch
60
56
  watch(() => props.timeSeries, update)
61
57
  watch(() => props.xAxisKey, update)
62
58
  watch(() => props.yAxisKey, update)
@@ -67,7 +63,7 @@ watch(() => props.logarithmic, update)
67
63
  watch(() => props.currentTime, update)
68
64
  watch(() => props.options, update)
69
65
 
70
- // function
66
+ // Functions
71
67
  async function onCanvasRef (ref) {
72
68
  if (ref) {
73
69
  if (!chart) {
@@ -82,14 +78,10 @@ async function onCanvasRef (ref) {
82
78
  }
83
79
  canvas = ref
84
80
  }
85
-
86
- function getUnits (timeSerie) {
81
+ function getUnit (timeSerie) {
87
82
  // Falback to base unit
88
- const baseUnit = _.get(timeSerie, 'variable.units[0]')
89
- // Get default unit for this quantity instead if available
90
- const defaultUnit = Units.getDefaultUnit(baseUnit)
91
- const unit = (timeSerie.variable.units.includes(defaultUnit) ? defaultUnit : baseUnit)
92
- return { unit, baseUnit }
83
+ const unit = _.get(timeSerie, 'variable.unit')
84
+ return unit
93
85
  }
94
86
  function getZoom () {
95
87
  const start = moment.utc(_.get(chart, 'scales.x.min'))
@@ -113,13 +105,11 @@ function computeScaleBound (scale, property, min, max) {
113
105
  _.set(scale, property, scaleBound(min, max))
114
106
  }
115
107
  }
116
-
117
108
  async function makeChartConfig () {
118
109
  // Order matters as we compute internals like data time range
119
110
  const datasets = await makeDatasets()
120
111
  const scales = makeScales()
121
112
  const annotation = makeAnnotation()
122
-
123
113
  const config = {
124
114
  type: 'line',
125
115
  data: { datasets },
@@ -145,9 +135,9 @@ async function makeChartConfig () {
145
135
  return (x ? `${Time.format(x, 'date.short')} - ${Time.format(x, 'time.long')}` : '')
146
136
  },
147
137
  label: (context) => {
148
- const { baseUnit, unit, label } = context.dataset
138
+ const { unit, label } = context.dataset
149
139
  const y = _.get(context, 'parsed.y')
150
- return label + ': ' + Units.format(y, baseUnit, unit)
140
+ return label + ': ' + Units.format(y, unit)
151
141
  }
152
142
  }
153
143
  },
@@ -200,7 +190,6 @@ async function makeChartConfig () {
200
190
  computeScaleBound(scales.x, 'suggestedMax', startTime.value, endTime.value)
201
191
  return config
202
192
  }
203
-
204
193
  function makeScales () {
205
194
  // Setup time ticks unit
206
195
  const hours = endTime.value.diff(startTime.value, 'hours')
@@ -248,19 +237,16 @@ function makeScales () {
248
237
  }
249
238
  }
250
239
  }
251
-
252
240
  const scales = { x }
253
-
254
241
  // Build a scale per unit
255
242
  unit2axis.clear()
256
243
  let axisId = 0
257
244
  for (const timeSerie of props.timeSeries) {
258
- const { unit, baseUnit } = getUnits(timeSerie)
245
+ const unit = getUnit(timeSerie)
259
246
  if (!unit2axis.has(unit)) {
260
247
  const axis = `y${axisId}`
261
248
  unit2axis.set(unit, axis)
262
249
  scales[axis] = _.merge({
263
- baseUnit,
264
250
  unit,
265
251
  type: props.logarithmic ? 'logarithmic' : 'linear',
266
252
  position: (axisId + 1) % 2 ? 'left' : 'right',
@@ -271,7 +257,7 @@ function makeScales () {
271
257
  ticks: {
272
258
  callback: function (value, index, values) {
273
259
  if (values[index] !== undefined) {
274
- return Units.format(values[index].value, baseUnit, unit, { symbol: false })
260
+ return Units.format(values[index].value, unit, null, { symbol: false })
275
261
  }
276
262
  }
277
263
  }
@@ -285,17 +271,15 @@ function makeScales () {
285
271
  }
286
272
  return scales
287
273
  }
288
-
289
274
  async function makeDatasets () {
290
275
  const datasets = []
291
276
  for (const timeSerie of props.timeSeries) {
292
277
  const label = _.get(timeSerie, 'variable.label')
293
- const { unit, baseUnit } = getUnits(timeSerie)
278
+ const unit = getUnit(timeSerie)
294
279
  const data = await timeSerie.data
295
280
  const dataset = Object.assign({
296
281
  label,
297
282
  data,
298
- baseUnit,
299
283
  unit,
300
284
  yAxisID: unit2axis.get(unit)
301
285
  }, _.omit(_.get(timeSerie, 'variable.chartjs', {}), 'yAxis'))
@@ -332,7 +316,6 @@ async function makeDatasets () {
332
316
 
333
317
  return datasets
334
318
  }
335
-
336
319
  function makeAnnotation () {
337
320
  let annotation = {}
338
321
  // Is current time visible in chart ?
@@ -360,7 +343,6 @@ function makeAnnotation () {
360
343
  }
361
344
  return annotation
362
345
  }
363
-
364
346
  async function exportSeries (options = {}) {
365
347
  let times = []
366
348
  for (let i = 0; i < props.timeSeries.length; i++) {
@@ -398,7 +380,6 @@ async function exportSeries (options = {}) {
398
380
  downloadAsBlob(csv, _.template(options.filename || i18n.t('KTimeSeriesChart.SERIES_EXPORT_FILE'))(),
399
381
  'text/csv;charset=utf-8;')
400
382
  }
401
-
402
383
  async function update () {
403
384
  if (!canvas) return
404
385
  // Reset time/value range
@@ -415,7 +396,6 @@ async function update () {
415
396
  chart.update()
416
397
  }
417
398
  }
418
-
419
399
  async function updateCurrentTime () {
420
400
  if (!props.currentTime) return
421
401
  update()
@@ -428,4 +408,11 @@ onMounted(() => {
428
408
  onBeforeUnmount(() => {
429
409
  Events.off('time-current-time-changed', updateCurrentTime)
430
410
  })
411
+
412
+ // Expose
413
+ defineExpose({
414
+ update,
415
+ getZoom,
416
+ exportSeries
417
+ })
431
418
  </script>
@@ -16,7 +16,7 @@
16
16
  -->
17
17
  <div v-if="items.length > 0">
18
18
  <KScrollArea
19
- ref="scrollArea"
19
+ ref="scrollAreaRef"
20
20
  :max-height="scrollHeight"
21
21
  @scrolled="onScrolled"
22
22
  >
@@ -38,22 +38,22 @@
38
38
  v-bind="renderer"
39
39
  @item-selected="onItemSelected"
40
40
  :class="{
41
- 'q-pr-xs': dense,
42
- 'q-pr-sm': !dense
41
+ 'q-pr-xs': hasScrollArea && dense,
42
+ 'q-pr-sm': hasScrollArea && !dense
43
43
  }"
44
44
  />
45
45
  </template>
46
46
  </div>
47
47
  </KScrollArea>
48
48
  <div
49
- v-if="scrollAction"
49
+ v-if="hasScrollAction"
50
50
  class="row justify-center"
51
51
  >
52
52
  <KAction
53
53
  id="scroll-action"
54
54
  icon="las la-angle-double-down"
55
55
  color="accent"
56
- size="1rem"
56
+ size="0.8rem"
57
57
  :handler="scrollDown"
58
58
  />
59
59
  </div>
@@ -90,7 +90,7 @@ const emit = defineEmits(['selection-changed', 'collection-refreshed'])
90
90
  const props = defineProps({
91
91
  name: {
92
92
  type: String,
93
- required: true
93
+ default: undefined
94
94
  },
95
95
  header: {
96
96
  type: Array,
@@ -151,8 +151,9 @@ const props = defineProps({
151
151
  })
152
152
 
153
153
  // Data
154
- const scrollArea = ref(null)
155
- const scrollAction = ref(false)
154
+ const scrollAreaRef = ref(null)
155
+ const hasScrollArea = ref(false)
156
+ const hasScrollAction = ref(false)
156
157
  const headerHeight = ref(0)
157
158
  // Configuration
158
159
  const scrollOffset = 350
@@ -160,7 +161,7 @@ const scrollDuration = 250
160
161
 
161
162
  // Computed
162
163
  const rendererComponent = computed(() => loadComponent(props.renderer.component))
163
- const scrollHeight = computed(() => props.height - headerHeight.value)
164
+ const scrollHeight = computed(() => props.height - headerHeight.value - (hasScrollAction.value ? 24 : 0))
164
165
 
165
166
  // Always use append mode for columns
166
167
  const { items, nbTotalItems, nbPages, currentPage, refreshCollection, resetCollection } =
@@ -171,25 +172,26 @@ function onHeaderResized (size) {
171
172
  headerHeight.value = size.height
172
173
  }
173
174
  function onScrolled (info) {
175
+ hasScrollArea.value = info.verticalSize > scrollHeight.value
174
176
  if (items.value.length < nbTotalItems.value) {
175
177
  if (info.verticalPercentage === 1) {
176
178
  if (items.value.length === currentPage.value * props.nbItemsPerPage) currentPage.value++
177
179
  refreshCollection()
178
- scrollAction.value = true
180
+ hasScrollAction.value = true
179
181
  } else {
180
- scrollAction.value = info.verticalSize > scrollHeight.value
182
+ hasScrollAction.value = hasScrollArea.value
181
183
  }
182
184
  } else {
183
185
  if (info.verticalPercentage === 1) {
184
- scrollAction.value = false
186
+ hasScrollAction.value = false
185
187
  } else {
186
- scrollAction.value = info.verticalSize > scrollHeight.value
188
+ hasScrollAction.value = hasScrollArea.value
187
189
  }
188
190
  }
189
191
  }
190
192
  function scrollDown () {
191
- const position = scrollArea.value.getScrollPosition('vertical')
192
- scrollArea.value.setScrollPosition('vertical', position + scrollOffset, scrollDuration)
193
+ const position = scrollAreaRef.value.getScrollPosition('vertical')
194
+ scrollAreaRef.value.setScrollPosition('vertical', position + scrollOffset, scrollDuration)
193
195
  }
194
196
  function onItemSelected (item, section) {
195
197
  emit('selection-changed', item, section)
@@ -198,14 +200,15 @@ function onCollectionRefreshed () {
198
200
  emit('collection-refreshed', items.value)
199
201
  }
200
202
 
201
- // Lifecycle hooks
203
+ // Watch
202
204
  watch(items, () => {
203
205
  // On reset, reset as well scroll area
204
- if (_.isEmpty(items.value) && scrollArea.value) scrollArea.value.setScrollPosition('vertical', 0)
206
+ if (_.isEmpty(items.value) && scrollAreaRef.value) scrollAreaRef.value.setScrollPosition('vertical', 0)
205
207
  // Emit events so that embbeding components can be aware of it
206
208
  onCollectionRefreshed()
207
209
  })
208
210
 
211
+ // Hooks
209
212
  onBeforeMount(() => {
210
213
  refreshCollection()
211
214
  // Whenever the user abilities are updated, update collection as well
@@ -16,14 +16,12 @@
16
16
 
17
17
  <script>
18
18
  import KModal from '../KModal.vue'
19
- import KScrollArea from '../KScrollArea.vue'
20
19
  import KForm from '../form/KForm.vue'
21
20
  import { baseModal, service, objectProxy, schemaProxy, baseEditor } from '../../mixins'
22
21
 
23
22
  export default {
24
23
  components: {
25
24
  KModal,
26
- KScrollArea,
27
25
  KForm
28
26
  },
29
27
  mixins: [
@@ -53,8 +53,18 @@
53
53
  </div>
54
54
  </template>
55
55
  <!-- Helper -->
56
- <template v-if="helper" v-slot:hint>
57
- <span v-html="helper"></span>
56
+ <template v-if="hasHelper" v-slot:append>
57
+ <k-action
58
+ :id="properties.name + '-helper'"
59
+ :label="helperLabel"
60
+ :icon="helperIcon"
61
+ :tooltip="helperTooltip"
62
+ :url="helperUrl"
63
+ :dialog="helperDialog"
64
+ :context="helperContext"
65
+ @dialog-confirmed="onHelperDialogConfirmed"
66
+ color="primary"
67
+ />
58
68
  </template>
59
69
  </q-field>
60
70
  <k-icon-chooser
@@ -29,8 +29,18 @@
29
29
  </q-dialog>
30
30
  </template>
31
31
  <!-- Helper -->
32
- <template v-if="helper" v-slot:hint>
33
- <span v-html="helper"></span>
32
+ <template v-if="hasHelper" v-slot:append>
33
+ <k-action
34
+ :id="properties.name + '-helper'"
35
+ :label="helperLabel"
36
+ :icon="helperIcon"
37
+ :tooltip="helperTooltip"
38
+ :url="helperUrl"
39
+ :dialog="helperDialog"
40
+ :context="helperContext"
41
+ @dialog-confirmed="onHelperDialogConfirmed"
42
+ color="primary"
43
+ />
34
44
  </template>
35
45
  </q-field>
36
46
  </div>
@@ -50,8 +50,18 @@
50
50
  </q-item>
51
51
  </template>
52
52
  <!-- Helper -->
53
- <template v-if="helper" v-slot:hint>
54
- <span v-html="helper"></span>
53
+ <template v-if="hasHelper" v-slot:append>
54
+ <k-action
55
+ :id="properties.name + '-helper'"
56
+ :label="helperLabel"
57
+ :icon="helperIcon"
58
+ :tooltip="helperTooltip"
59
+ :url="helperUrl"
60
+ :dialog="helperDialog"
61
+ :context="helperContext"
62
+ @dialog-confirmed="onHelperDialogConfirmed"
63
+ color="primary"
64
+ />
55
65
  </template>
56
66
  </q-select>
57
67
  </template>
@@ -25,8 +25,18 @@
25
25
  />
26
26
  </template>
27
27
  <!-- Helper -->
28
- <template v-if="helper" v-slot:hint>
29
- <span v-html="helper"></span>
28
+ <template v-if="hasHelper" v-slot:append>
29
+ <k-action
30
+ :id="properties.name + '-helper'"
31
+ :label="helperLabel"
32
+ :icon="helperIcon"
33
+ :tooltip="helperTooltip"
34
+ :url="helperUrl"
35
+ :dialog="helperDialog"
36
+ :context="helperContext"
37
+ @dialog-confirmed="onHelperDialogConfirmed"
38
+ color="primary"
39
+ />
30
40
  </template>
31
41
  </q-field>
32
42
  </template>
@@ -25,8 +25,18 @@
25
25
  />
26
26
  </template>
27
27
  <!-- Helper -->
28
- <template v-if="helper" v-slot:hint>
29
- <span v-html="helper"></span>
28
+ <template v-if="hasHelper" v-slot:append>
29
+ <k-action
30
+ :id="properties.name + '-helper'"
31
+ :label="helperLabel"
32
+ :icon="helperIcon"
33
+ :tooltip="helperTooltip"
34
+ :url="helperUrl"
35
+ :dialog="helperDialog"
36
+ :context="helperContext"
37
+ @dialog-confirmed="onHelperDialogConfirmed"
38
+ color="primary"
39
+ />
30
40
  </template>
31
41
  </q-field>
32
42
  </template>
@@ -18,8 +18,18 @@
18
18
  @update:model-value="onChanged"
19
19
  >
20
20
  <!-- Helper -->
21
- <template v-if="helper" v-slot:hint>
22
- <span v-html="helper"></span>
21
+ <template v-if="hasHelper" v-slot:append>
22
+ <k-action
23
+ :id="properties.name + '-helper'"
24
+ :label="helperLabel"
25
+ :icon="helperIcon"
26
+ :tooltip="helperTooltip"
27
+ :url="helperUrl"
28
+ :dialog="helperDialog"
29
+ :context="helperContext"
30
+ @dialog-confirmed="onHelperDialogConfirmed"
31
+ color="primary"
32
+ />
23
33
  </template>
24
34
  </q-input>
25
35
  </template>
@@ -30,8 +30,18 @@
30
30
  @update:model-value="onFileChanged"
31
31
  @rejected="onFileRejected">
32
32
  <!-- Helper -->
33
- <template v-if="helper" v-slot:hint>
34
- <span v-html="helper"></span>
33
+ <template v-if="hasHelper" v-slot:append>
34
+ <k-action
35
+ :id="properties.name + '-helper'"
36
+ :label="helperLabel"
37
+ :icon="helperIcon"
38
+ :tooltip="helperTooltip"
39
+ :url="helperUrl"
40
+ :dialog="helperDialog"
41
+ :context="helperContext"
42
+ @dialog-confirmed="onHelperDialogConfirmed"
43
+ color="primary"
44
+ />
35
45
  </template>
36
46
  </q-file>
37
47
  </template>
@@ -22,13 +22,32 @@
22
22
  <!--
23
23
  Grouped fields
24
24
  -->
25
- <template v-for="group in groups" :key="group">
26
- <q-expansion-item icon="las la-file-alt" :group="group" :label="$t(group)">
25
+ <template v-for="(group, id) in groups" :key="id">
26
+ <q-expansion-item v-show="group.hasFields" icon="las la-file-alt" :group="id">
27
+ <template v-slot:header>
28
+ <!-- Label -->
29
+ <q-item-section>
30
+ {{ $t(group.label) }}
31
+ </q-item-section>
32
+ <!-- Helper -->
33
+ <q-item-section v-if="group.helper" side >
34
+ <k-action
35
+ :id="id + '-helper'"
36
+ color="primary"
37
+ :propagate="false"
38
+ :icon="getHelperIcon(group.helper)"
39
+ :tooltip="getHelperTooltip(group.helper)"
40
+ :url="getHelperUrl(group.helper)"
41
+ :dialog="getHelperDialog(group.helper)"
42
+ />
43
+ </q-item-section>
44
+ </template>
45
+ <!-- Content -->
27
46
  <q-card>
28
47
  <q-card-section>
29
48
  <template v-for="field in fields" :key="field.name">
30
- <slot v-if="field.group === group" :name="'before-' + field.name"/>
31
- <slot v-if="field.group === group" :name="field.name">
49
+ <slot v-if="field.group === id" :name="'before-' + field.name"/>
50
+ <slot v-if="field.group === id" :name="field.name">
32
51
  <component
33
52
  :ref="onFieldRefCreated"
34
53
  :is="field.component"
@@ -38,7 +57,7 @@
38
57
  :dense="dense"
39
58
  @field-changed="onFieldChanged" />
40
59
  </slot>
41
- <slot v-if="field.group === group" :name="'after-' + field.name"/>
60
+ <slot v-if="field.group === id" :name="'after-' + field.name"/>
42
61
  </template>
43
62
  </q-card-section>
44
63
  </q-card>
@@ -50,7 +69,7 @@
50
69
  <script setup>
51
70
  import _ from 'lodash'
52
71
  import logger from 'loglevel'
53
- import { ref, watch, onMounted } from 'vue'
72
+ import { ref, watch, computed, onMounted } from 'vue'
54
73
  import { loadComponent } from '../../utils/index.js'
55
74
  import { useSchema } from '../../composables'
56
75
 
@@ -80,11 +99,20 @@ const emit = defineEmits(['field-changed', 'form-ready'])
80
99
  // Data
81
100
  const { schema, compile: compileSchema, validate: validateSchema } = useSchema()
82
101
  const fields = ref([])
83
- const groups = ref([])
84
102
  const isReady = ref(false)
85
103
  const nbReadyFields = ref(0)
86
104
  let buildInProgress = false
87
105
 
106
+ // Computed
107
+ const groups = computed(() => {
108
+ if (schema.value && schema.value.groups) {
109
+ return _.mapValues(schema.value.groups, (group, id) => Object.assign({
110
+ hasFields: _.find(fields.value, { group: id })
111
+ }, group))
112
+ }
113
+ return {}
114
+ })
115
+
88
116
  // Watch
89
117
  watch(() => props.schema, async (value) => {
90
118
  logger.debug('[KDK] Schema changed', value)
@@ -146,7 +174,6 @@ function hasFieldError (field, errors) {
146
174
  }
147
175
  async function build () {
148
176
  fields.value = []
149
- groups.value = []
150
177
  nbReadyFields.value = 0
151
178
  isReady.value = false
152
179
  if (!props.schema) throw new Error('Cannot build the form without schema')
@@ -165,7 +192,6 @@ async function build () {
165
192
  cloneField.required = _.includes(schema.value.required, property) // add extra required info
166
193
  // add the field to the list of fields to be rendered
167
194
  fields.value.push(cloneField)
168
- if (cloneField.group && !groups.value.includes(cloneField.group)) groups.value.push(cloneField.group)
169
195
  })
170
196
  buildInProgress = false
171
197
  }
@@ -226,6 +252,18 @@ async function submitted (object) {
226
252
  await field.reference.submitted(object, field.name)
227
253
  }
228
254
  }
255
+ function getHelperIcon (helper) {
256
+ return _.get(helper, 'icon', undefined)
257
+ }
258
+ function getHelperTooltip (helper) {
259
+ return _.get(helper, 'tooltip', '')
260
+ }
261
+ function getHelperUrl (helper) {
262
+ return _.get(helper, 'url', null)
263
+ }
264
+ function getHelperDialog (helper) {
265
+ return _.get(helper, 'dialog', null)
266
+ }
229
267
 
230
268
  // Hooks
231
269
  onMounted(async () => {
@@ -39,8 +39,18 @@
39
39
  :color="iconColor" />
40
40
  </template>
41
41
  <!-- Helper -->
42
- <template v-if="helper" v-slot:hint>
43
- <span v-html="helper"></span>
42
+ <template v-if="hasHelper" v-slot:append>
43
+ <k-action
44
+ :id="properties.name + '-helper'"
45
+ :label="helperLabel"
46
+ :icon="helperIcon"
47
+ :tooltip="helperTooltip"
48
+ :url="helperUrl"
49
+ :dialog="helperDialog"
50
+ :context="helperContext"
51
+ @dialog-confirmed="onHelperDialogConfirmed"
52
+ color="primary"
53
+ />
44
54
  </template>
45
55
  </q-field>
46
56
  </div>
@@ -52,8 +52,18 @@
52
52
  </q-item>
53
53
  </template>
54
54
  <!-- Helper -->
55
- <template v-if="helper" v-slot:hint>
56
- <span v-html="helper"></span>
55
+ <template v-if="hasHelper" v-slot:append>
56
+ <k-action
57
+ :id="properties.name + '-helper'"
58
+ :label="helperLabel"
59
+ :icon="helperIcon"
60
+ :tooltip="helperTooltip"
61
+ :url="helperUrl"
62
+ :dialog="helperDialog"
63
+ :context="helperContext"
64
+ @dialog-confirmed="onHelperDialogConfirmed"
65
+ color="primary"
66
+ />
57
67
  </template>
58
68
  </q-select>
59
69
  </template>
@@ -71,16 +81,27 @@ export default {
71
81
  options: []
72
82
  }
73
83
  },
84
+ computed: {
85
+ hasSingleService () {
86
+ const services = _.uniqBy(this.properties.services, 'service')
87
+ return services.length === 1
88
+ }
89
+ },
74
90
  methods: {
91
+ getServiceForItem (item) {
92
+ return (this.hasSingleService
93
+ ? this.properties.services[0]
94
+ : _.find(this.properties.services, { service: item.service }))
95
+ },
75
96
  getId (item) {
76
97
  return _.kebabCase(this.getLabel(item))
77
98
  },
78
99
  getLabel (item) {
79
- const service = _.find(this.properties.services, { service: item.service })
100
+ const service = this.getServiceForItem(item)
80
101
  return _.get(item, service.field || 'name', '')
81
102
  },
82
103
  getDescription (item) {
83
- const service = _.find(this.properties.services, { service: item.service })
104
+ const service = this.getServiceForItem(item)
84
105
  return _.get(item, service.description || 'description', '')
85
106
  },
86
107
  getIcon (item) {
@@ -18,8 +18,18 @@
18
18
 
19
19
  >
20
20
  <!-- Helper -->
21
- <template v-if="helper" v-slot:hint>
22
- <span v-html="helper"></span>
21
+ <template v-if="hasHelper" v-slot:append>
22
+ <k-action
23
+ :id="properties.name + '-helper'"
24
+ :label="helperLabel"
25
+ :icon="helperIcon"
26
+ :tooltip="helperTooltip"
27
+ :url="helperUrl"
28
+ :dialog="helperDialog"
29
+ :context="helperContext"
30
+ @dialog-confirmed="onHelperDialogConfirmed"
31
+ color="primary"
32
+ />
23
33
  </template>
24
34
  </q-input>
25
35
  </template>