@kalisio/kdk 2.5.3 → 2.6.0

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 (545) hide show
  1. package/.github/workflows/main.yaml +35 -6
  2. package/client.globe.js +8 -0
  3. package/client.js +8 -0
  4. package/client.map.js +8 -0
  5. package/core/api/hooks/hooks.push.js +3 -2
  6. package/core/api/hooks/hooks.tags.js +56 -0
  7. package/core/api/models/tags.model.mongodb.js +8 -0
  8. package/core/api/services/index.js +33 -2
  9. package/core/api/services/tags/tags.hooks.js +47 -0
  10. package/core/client/api.js +5 -5
  11. package/core/client/components/KActivity.vue +3 -2
  12. package/core/client/components/KChip.vue +2 -2
  13. package/core/client/components/KEditor.vue +3 -1
  14. package/core/client/components/KFollower.vue +4 -4
  15. package/core/client/components/KStore.vue +1 -1
  16. package/core/client/components/KTab.vue +20 -7
  17. package/core/client/components/account/KProfile.vue +9 -25
  18. package/core/client/components/action/KAction.vue +10 -10
  19. package/core/client/components/action/KToggleFullscreenAction.vue +2 -11
  20. package/core/client/components/app/KHome.vue +3 -2
  21. package/core/client/components/collection/KFilter.vue +5 -4
  22. package/core/client/components/collection/KGrid.vue +5 -1
  23. package/core/client/components/collection/KItemsFilter.vue +47 -0
  24. package/core/client/components/collection/KItemsSorter.vue +42 -0
  25. package/core/client/components/collection/KScrollDown.vue +2 -2
  26. package/core/client/components/collection/KSearchFilterControl.vue +3 -2
  27. package/core/client/components/collection/KSorter.vue +33 -37
  28. package/core/client/components/collection/KTagsFilterControl.vue +14 -40
  29. package/core/client/components/collection/KTagsFilterView.vue +10 -45
  30. package/core/client/components/collection/KTimeFilterControl.vue +6 -7
  31. package/core/client/components/collection/KTimeFilterView.vue +13 -22
  32. package/core/client/components/collection/KTimeLine.vue +18 -9
  33. package/core/client/components/form/KColorField.vue +13 -6
  34. package/core/client/components/form/KColorScaleField.vue +7 -12
  35. package/core/client/components/form/KFileField.vue +118 -89
  36. package/core/client/components/form/KForm.vue +30 -18
  37. package/core/client/components/form/KIconField.vue +4 -1
  38. package/core/client/components/form/KNumberField.vue +9 -2
  39. package/core/client/components/form/KSelectField.vue +1 -4
  40. package/core/client/components/form/KTagField.vue +229 -0
  41. package/core/client/components/form/KTextField.vue +4 -0
  42. package/core/client/components/form/KTextareaField.vue +3 -1
  43. package/core/client/components/input/KShapePicker.vue +3 -3
  44. package/core/client/components/layout/KFab.vue +32 -20
  45. package/core/client/components/layout/KPage.vue +11 -6
  46. package/core/client/components/layout/KWindow.vue +5 -0
  47. package/core/client/components/media/index.js +2 -6
  48. package/core/client/components/menu/KMenu.vue +12 -10
  49. package/core/client/components/menu/KSubMenu.vue +12 -12
  50. package/core/client/components/messages/KMessageCard.vue +13 -12
  51. package/core/client/components/messages/KMessageComposer.vue +13 -9
  52. package/core/client/components/messages/KMessagesTimeLine.vue +16 -8
  53. package/core/client/components/tags/KTagFilter.vue +99 -0
  54. package/core/client/components/tags/KTagItem.vue +65 -0
  55. package/core/client/components/tags/KTagManager.vue +198 -0
  56. package/core/client/components/tags/KTagSelection.vue +82 -0
  57. package/core/client/components/time/KDate.vue +3 -17
  58. package/core/client/components/time/KDateTime.vue +1 -1
  59. package/core/client/components/time/KTime.vue +0 -4
  60. package/core/client/composables/collection-filter.js +41 -2
  61. package/core/client/composables/collection.js +3 -3
  62. package/core/client/composables/index.js +1 -0
  63. package/core/client/composables/pwa.js +13 -0
  64. package/core/client/composables/session.js +7 -8
  65. package/core/client/composables/user.js +36 -0
  66. package/core/client/directives/index.js +1 -0
  67. package/core/client/directives/v-drop-file.js +174 -0
  68. package/core/client/document.js +2 -1
  69. package/core/client/exporter.js +17 -3
  70. package/core/client/i18n/core_en.json +34 -7
  71. package/core/client/i18n/core_fr.json +36 -9
  72. package/core/client/i18n.js +26 -11
  73. package/core/client/layout.js +5 -5
  74. package/core/client/mixins/mixin.base-activity.js +8 -5
  75. package/core/client/mixins/mixin.base-editor.js +2 -1
  76. package/core/client/mixins/mixin.base-field.js +3 -2
  77. package/core/client/mixins/mixin.base-item.js +12 -10
  78. package/core/client/mixins/mixin.service.js +3 -1
  79. package/core/client/platform.js +0 -3
  80. package/core/client/readers/reader.json.js +2 -2
  81. package/core/client/utils/index.js +2 -0
  82. package/core/client/utils/utils.collection.js +6 -6
  83. package/core/client/utils/utils.colors.js +46 -19
  84. package/core/client/utils/utils.files.js +19 -0
  85. package/core/client/utils/utils.locale.js +13 -17
  86. package/core/client/utils/utils.services.js +27 -0
  87. package/core/client/utils/utils.shapes.js +2 -2
  88. package/core/client/utils/utils.tags.js +17 -0
  89. package/core/client/utils/utils.tours.js +31 -0
  90. package/core/common/permissions.js +3 -0
  91. package/core/common/schemas/tags.update.json +35 -0
  92. package/core/common/schemas/users.update-profile.json +1 -1
  93. package/core/common/utils.js +5 -5
  94. package/extras/configs/panes.top.js +11 -0
  95. package/extras/configs/stickies.js +1 -1
  96. package/extras/configs/widgets.left.js +13 -1
  97. package/extras/libs/jsts.min.js +8 -0
  98. package/{test/client/core/account.js → extras/tests/core/account.mjs} +4 -4
  99. package/extras/tests/core/api.mjs +114 -0
  100. package/{test/client/core/collection.js → extras/tests/core/collection.mjs} +8 -8
  101. package/{test/client/core/dialogs.js → extras/tests/core/dialogs.mjs} +1 -1
  102. package/extras/tests/core/index.mjs +9 -0
  103. package/{test/client/core/layout.js → extras/tests/core/layout.mjs} +7 -3
  104. package/{test/client/core/runner.js → extras/tests/core/runner.mjs} +3 -3
  105. package/{test/client/core/screens.js → extras/tests/core/screens.mjs} +1 -1
  106. package/{test/client/core/utils.js → extras/tests/core/utils.mjs} +79 -26
  107. package/extras/tests/index.mjs +4 -0
  108. package/{test/client/map/api.js → extras/tests/map/api.mjs} +1 -1
  109. package/{test/client/map/catalog.js → extras/tests/map/catalog.mjs} +18 -18
  110. package/{test/client/map/controls.js → extras/tests/map/controls.mjs} +3 -3
  111. package/extras/tests/map/index.mjs +5 -0
  112. package/{test/client/map/time.js → extras/tests/map/time.mjs} +3 -3
  113. package/{test/client/map/utils.js → extras/tests/map/utils.mjs} +6 -5
  114. package/extras/tours/fab.js +36 -0
  115. package/extras/tours/layout.js +49 -0
  116. package/extras/tours/pane.left.js +78 -0
  117. package/extras/tours/pane.right.js +145 -0
  118. package/extras/tours/pane.top.js +239 -0
  119. package/map/api/config/layers.cjs +28 -13
  120. package/map/api/hooks/hooks.query.js +12 -7
  121. package/map/api/models/catalog.model.mongodb.js +17 -6
  122. package/map/api/services/catalog/catalog.hooks.js +1 -1
  123. package/map/api/services/index.js +18 -1
  124. package/map/client/cesium/utils/utils.cesium.js +25 -65
  125. package/map/client/cesium/utils/utils.features.js +1 -0
  126. package/map/client/cesium/utils/utils.geojson.js +1 -0
  127. package/map/client/cesium/utils/utils.style.js +7 -6
  128. package/map/client/components/KFeatureEditor.vue +3 -3
  129. package/map/client/components/KFeaturesChart.vue +4 -4
  130. package/map/client/components/KFeaturesFilterEditor.vue +19 -13
  131. package/map/client/components/KFeaturesFilterManager.vue +7 -4
  132. package/map/client/components/KFeaturesTable.vue +2 -2
  133. package/map/client/components/KLayerEditor.vue +6 -6
  134. package/map/client/components/KMeasureTool.vue +2 -1
  135. package/map/client/components/catalog/KBaseLayersSelector.vue +1 -1
  136. package/map/client/components/catalog/KCategoryItem.vue +15 -1
  137. package/map/client/components/catalog/KConnectLayer.vue +2 -2
  138. package/map/client/components/catalog/KCreateView.vue +3 -2
  139. package/map/client/components/catalog/KFilteredLayerItem.vue +26 -6
  140. package/map/client/components/catalog/KImportLayer.vue +6 -3
  141. package/map/client/components/catalog/KLayerCategories.vue +6 -6
  142. package/map/client/components/catalog/KLayerItem.vue +12 -2
  143. package/map/client/components/catalog/KLayersList.vue +180 -0
  144. package/map/client/components/catalog/KLayersPanel.vue +146 -36
  145. package/map/client/components/catalog/KLayersSelector.vue +96 -48
  146. package/map/client/components/catalog/KProjectEditor.vue +0 -9
  147. package/map/client/components/catalog/KProjectSelector.vue +3 -2
  148. package/map/client/components/catalog/KProjectsPanel.vue +23 -8
  149. package/map/client/components/catalog/KViewsPanel.vue +18 -8
  150. package/map/client/components/catalog/KWeatherLayersSelector.vue +3 -3
  151. package/map/client/components/form/KDirectionField.vue +3 -6
  152. package/map/client/components/form/KLayerCategoryField.vue +2 -2
  153. package/map/client/components/form/KOwsServiceField.vue +25 -24
  154. package/map/client/components/form/KSelectLayersField.vue +4 -4
  155. package/map/client/components/form/KSelectViewsField.vue +4 -4
  156. package/map/client/components/legend/KLayerLegend.vue +11 -2
  157. package/map/client/components/legend/KLegend.vue +44 -51
  158. package/map/client/components/location/KLocationCardSection.vue +6 -7
  159. package/map/client/components/location/KLocationMap.vue +23 -13
  160. package/map/client/components/stickies/KPosition.vue +5 -0
  161. package/map/client/components/styles/KLayerStyleAction.vue +59 -12
  162. package/map/client/components/styles/KStyleEditor.vue +71 -8
  163. package/map/client/components/styles/KStyleEditorSection.vue +82 -33
  164. package/map/client/components/styles/KStyleManager.vue +119 -59
  165. package/map/client/components/styles/KStylePreview.vue +9 -25
  166. package/map/client/components/styles/KStylePreviewItem.vue +22 -1
  167. package/map/client/components/tools/KSearchTool.vue +1 -1
  168. package/map/client/components/widget/KElevationProfile.vue +20 -17
  169. package/map/client/components/widget/KInformationBox.vue +5 -5
  170. package/map/client/components/widget/KMapillaryViewer.vue +2 -1
  171. package/map/client/components/widget/KTimeSeries.vue +11 -9
  172. package/map/client/globe.js +2 -0
  173. package/map/client/i18n/map_en.json +29 -7
  174. package/map/client/i18n/map_fr.json +29 -7
  175. package/map/client/leaflet/GradientPath.js +61 -24
  176. package/map/client/leaflet/ShapeMarker.js +12 -5
  177. package/map/client/leaflet/TiledMeshLayer.js +3 -3
  178. package/map/client/leaflet/utils/utils.geojson.js +66 -8
  179. package/map/client/leaflet/utils/utils.style.js +14 -15
  180. package/map/client/mixins/globe/mixin.base-globe.js +181 -34
  181. package/map/client/mixins/globe/mixin.file-layers.js +3 -0
  182. package/map/client/mixins/globe/mixin.geojson-layers.js +179 -31
  183. package/map/client/mixins/globe/mixin.opendap-layers.js +2 -1
  184. package/map/client/mixins/globe/mixin.style.js +23 -1
  185. package/map/client/mixins/globe/mixin.tooltip.js +14 -2
  186. package/map/client/mixins/map/mixin.base-map.js +146 -58
  187. package/map/client/mixins/map/mixin.edit-layers.js +18 -15
  188. package/map/client/mixins/map/mixin.geojson-layers.js +181 -106
  189. package/map/client/mixins/map/mixin.heatmap-layers.js +3 -2
  190. package/map/client/mixins/map/mixin.map-activity.js +6 -1
  191. package/map/client/mixins/map/mixin.mapillary-layers.js +2 -1
  192. package/map/client/mixins/map/mixin.pmtiles-layers.js +3 -3
  193. package/map/client/mixins/map/mixin.tiled-mesh-layers.js +3 -2
  194. package/map/client/mixins/map/mixin.tiled-wind-layers.js +3 -2
  195. package/map/client/mixins/mixin.activity.js +197 -51
  196. package/map/client/mixins/mixin.context.js +11 -11
  197. package/map/client/mixins/mixin.feature-service.js +11 -9
  198. package/map/client/mixins/mixin.weacast.js +5 -3
  199. package/map/client/readers/reader.geojson.js +3 -1
  200. package/map/client/utils/utils.capture.js +3 -3
  201. package/map/client/utils/utils.catalog.js +9 -5
  202. package/map/client/utils/utils.features.js +120 -54
  203. package/map/client/utils/utils.js +25 -10
  204. package/map/client/utils/utils.layers.js +148 -24
  205. package/map/client/utils/utils.location.js +26 -9
  206. package/map/client/utils/utils.schema.js +2 -1
  207. package/map/client/utils/utils.style.js +53 -9
  208. package/map/common/geotiff-grid-source.js +1 -3
  209. package/map/common/opendap-utils.js +0 -1
  210. package/map/common/tms-utils.js +0 -1
  211. package/map/common/wcs-utils.js +0 -1
  212. package/map/common/wfs-utils.js +0 -1
  213. package/map/common/wms-utils.js +7 -1
  214. package/map/common/wmts-utils.js +0 -1
  215. package/package.json +12 -12
  216. package/scripts/init_runner.sh +3 -3
  217. package/scripts/kash/CHANGELOG.md +27 -0
  218. package/scripts/kash/kash.sh +556 -237
  219. package/scripts/kash/scripts/run_tests.sh +44 -5
  220. package/scripts/setup_workspace.sh +23 -13
  221. package/test/api/core/config/default.cjs +2 -1
  222. package/test/api/core/tags.test.js +62 -0
  223. package/test/api/map/config/default.cjs +2 -1
  224. package/test/api/map/config/layers.json +9 -0
  225. package/test/api/map/data/openradiation.json +13811 -0
  226. package/test/api/map/grid-sources.test.js +1 -3
  227. package/test/api/map/index.test.js +60 -1
  228. package/test/api/map/style.test.js +30 -1
  229. package/test.api.js +1 -1
  230. package/vite/App.vue +18 -0
  231. package/vite/AppWithGlobe.vue +84 -0
  232. package/vite/GlobeActivity.vue +58 -0
  233. package/vite/MapActivity.vue +63 -0
  234. package/vite/MapActivityWithGlobe.vue +63 -0
  235. package/vite/README.md +169 -0
  236. package/vite/config.js +221 -0
  237. package/vite/index_with_globe.html +50 -0
  238. package/vite/index_with_map.html +50 -0
  239. package/vite/package.json +173 -0
  240. package/vite/quasar.variables.scss +17 -0
  241. package/vite/vite.config.js +166 -0
  242. package/vite/yarn.lock +11641 -0
  243. package/core/client/components/media/KImageViewer.vue +0 -68
  244. package/core/client/components/media/KMarkdownViewer.vue +0 -55
  245. package/core/client/components/media/KMediaBrowser.vue +0 -301
  246. package/coverage/base.css +0 -224
  247. package/coverage/block-navigation.js +0 -87
  248. package/coverage/core/api/application.js.html +0 -1870
  249. package/coverage/core/api/authentication.js.html +0 -874
  250. package/coverage/core/api/db.js.html +0 -793
  251. package/coverage/core/api/hooks/hooks.authentication.js.html +0 -139
  252. package/coverage/core/api/hooks/hooks.authorisations.js.html +0 -958
  253. package/coverage/core/api/hooks/hooks.groups.js.html +0 -229
  254. package/coverage/core/api/hooks/hooks.logger.js.html +0 -163
  255. package/coverage/core/api/hooks/hooks.model.js.html +0 -967
  256. package/coverage/core/api/hooks/hooks.organisations.js.html +0 -541
  257. package/coverage/core/api/hooks/hooks.push.js.html +0 -265
  258. package/coverage/core/api/hooks/hooks.query.js.html +0 -862
  259. package/coverage/core/api/hooks/hooks.schemas.js.html +0 -298
  260. package/coverage/core/api/hooks/hooks.service.js.html +0 -319
  261. package/coverage/core/api/hooks/hooks.storage.js.html +0 -193
  262. package/coverage/core/api/hooks/hooks.users.js.html +0 -595
  263. package/coverage/core/api/hooks/index.html +0 -266
  264. package/coverage/core/api/hooks/index.js.html +0 -115
  265. package/coverage/core/api/index.html +0 -176
  266. package/coverage/core/api/index.js.html +0 -148
  267. package/coverage/core/api/marshall.js.html +0 -448
  268. package/coverage/core/api/models/groups.model.mongodb.js.html +0 -109
  269. package/coverage/core/api/models/index.html +0 -131
  270. package/coverage/core/api/models/messages.model.mongodb.js.html +0 -121
  271. package/coverage/core/api/models/organisations.model.mongodb.js.html +0 -94
  272. package/coverage/core/api/models/tags.model.mongodb.js.html +0 -115
  273. package/coverage/core/api/models/users.model.mongodb.js.html +0 -115
  274. package/coverage/core/api/services/account/account.hooks.js.html +0 -208
  275. package/coverage/core/api/services/account/account.service.js.html +0 -436
  276. package/coverage/core/api/services/account/index.html +0 -131
  277. package/coverage/core/api/services/authorisations/authorisations.hooks.js.html +0 -184
  278. package/coverage/core/api/services/authorisations/authorisations.service.js.html +0 -520
  279. package/coverage/core/api/services/authorisations/index.html +0 -131
  280. package/coverage/core/api/services/databases/databases.hooks.js.html +0 -193
  281. package/coverage/core/api/services/databases/databases.service.js.html +0 -100
  282. package/coverage/core/api/services/databases/index.html +0 -131
  283. package/coverage/core/api/services/groups/groups.hooks.js.html +0 -178
  284. package/coverage/core/api/services/groups/index.html +0 -116
  285. package/coverage/core/api/services/import-export/import-export.hooks.js.html +0 -184
  286. package/coverage/core/api/services/import-export/import-export.service.js.html +0 -118
  287. package/coverage/core/api/services/import-export/index.html +0 -131
  288. package/coverage/core/api/services/index.html +0 -116
  289. package/coverage/core/api/services/index.js.html +0 -532
  290. package/coverage/core/api/services/mailer/index.html +0 -131
  291. package/coverage/core/api/services/mailer/mailer.hooks.js.html +0 -190
  292. package/coverage/core/api/services/mailer/mailer.service.js.html +0 -118
  293. package/coverage/core/api/services/messages/index.html +0 -116
  294. package/coverage/core/api/services/messages/messages.hooks.js.html +0 -202
  295. package/coverage/core/api/services/organisations/index.html +0 -131
  296. package/coverage/core/api/services/organisations/organisations.hooks.js.html +0 -178
  297. package/coverage/core/api/services/organisations/organisations.service.js.html +0 -343
  298. package/coverage/core/api/services/push/index.html +0 -131
  299. package/coverage/core/api/services/push/push.hooks.js.html +0 -190
  300. package/coverage/core/api/services/push/push.service.js.html +0 -121
  301. package/coverage/core/api/services/storage/index.html +0 -131
  302. package/coverage/core/api/services/storage/storage.hooks.js.html +0 -190
  303. package/coverage/core/api/services/storage/storage.service.js.html +0 -172
  304. package/coverage/core/api/services/tags/index.html +0 -116
  305. package/coverage/core/api/services/tags/tags.hooks.js.html +0 -178
  306. package/coverage/core/api/services/users/index.html +0 -131
  307. package/coverage/core/api/services/users/users.hooks.js.html +0 -310
  308. package/coverage/core/api/services/users/users.service.js.html +0 -100
  309. package/coverage/core/api/utils.js.html +0 -118
  310. package/coverage/core/common/errors.js.html +0 -88
  311. package/coverage/core/common/index.html +0 -191
  312. package/coverage/core/common/index.js.html +0 -115
  313. package/coverage/core/common/permissions.js.html +0 -733
  314. package/coverage/core/common/schema.js.html +0 -190
  315. package/coverage/core/common/utils.js.html +0 -226
  316. package/coverage/core/common/utils.offline.js.html +0 -199
  317. package/coverage/favicon.png +0 -0
  318. package/coverage/index.html +0 -476
  319. package/coverage/lcov-report/base.css +0 -224
  320. package/coverage/lcov-report/block-navigation.js +0 -87
  321. package/coverage/lcov-report/core/api/application.js.html +0 -1870
  322. package/coverage/lcov-report/core/api/authentication.js.html +0 -874
  323. package/coverage/lcov-report/core/api/db.js.html +0 -793
  324. package/coverage/lcov-report/core/api/hooks/hooks.authentication.js.html +0 -139
  325. package/coverage/lcov-report/core/api/hooks/hooks.authorisations.js.html +0 -958
  326. package/coverage/lcov-report/core/api/hooks/hooks.groups.js.html +0 -229
  327. package/coverage/lcov-report/core/api/hooks/hooks.logger.js.html +0 -163
  328. package/coverage/lcov-report/core/api/hooks/hooks.model.js.html +0 -967
  329. package/coverage/lcov-report/core/api/hooks/hooks.organisations.js.html +0 -541
  330. package/coverage/lcov-report/core/api/hooks/hooks.push.js.html +0 -265
  331. package/coverage/lcov-report/core/api/hooks/hooks.query.js.html +0 -862
  332. package/coverage/lcov-report/core/api/hooks/hooks.schemas.js.html +0 -298
  333. package/coverage/lcov-report/core/api/hooks/hooks.service.js.html +0 -319
  334. package/coverage/lcov-report/core/api/hooks/hooks.storage.js.html +0 -193
  335. package/coverage/lcov-report/core/api/hooks/hooks.users.js.html +0 -595
  336. package/coverage/lcov-report/core/api/hooks/index.html +0 -266
  337. package/coverage/lcov-report/core/api/hooks/index.js.html +0 -115
  338. package/coverage/lcov-report/core/api/index.html +0 -176
  339. package/coverage/lcov-report/core/api/index.js.html +0 -148
  340. package/coverage/lcov-report/core/api/marshall.js.html +0 -448
  341. package/coverage/lcov-report/core/api/models/groups.model.mongodb.js.html +0 -109
  342. package/coverage/lcov-report/core/api/models/index.html +0 -131
  343. package/coverage/lcov-report/core/api/models/messages.model.mongodb.js.html +0 -121
  344. package/coverage/lcov-report/core/api/models/organisations.model.mongodb.js.html +0 -94
  345. package/coverage/lcov-report/core/api/models/tags.model.mongodb.js.html +0 -115
  346. package/coverage/lcov-report/core/api/models/users.model.mongodb.js.html +0 -115
  347. package/coverage/lcov-report/core/api/services/account/account.hooks.js.html +0 -208
  348. package/coverage/lcov-report/core/api/services/account/account.service.js.html +0 -436
  349. package/coverage/lcov-report/core/api/services/account/index.html +0 -131
  350. package/coverage/lcov-report/core/api/services/authorisations/authorisations.hooks.js.html +0 -184
  351. package/coverage/lcov-report/core/api/services/authorisations/authorisations.service.js.html +0 -520
  352. package/coverage/lcov-report/core/api/services/authorisations/index.html +0 -131
  353. package/coverage/lcov-report/core/api/services/databases/databases.hooks.js.html +0 -193
  354. package/coverage/lcov-report/core/api/services/databases/databases.service.js.html +0 -100
  355. package/coverage/lcov-report/core/api/services/databases/index.html +0 -131
  356. package/coverage/lcov-report/core/api/services/groups/groups.hooks.js.html +0 -178
  357. package/coverage/lcov-report/core/api/services/groups/index.html +0 -116
  358. package/coverage/lcov-report/core/api/services/import-export/import-export.hooks.js.html +0 -184
  359. package/coverage/lcov-report/core/api/services/import-export/import-export.service.js.html +0 -118
  360. package/coverage/lcov-report/core/api/services/import-export/index.html +0 -131
  361. package/coverage/lcov-report/core/api/services/index.html +0 -116
  362. package/coverage/lcov-report/core/api/services/index.js.html +0 -532
  363. package/coverage/lcov-report/core/api/services/mailer/index.html +0 -131
  364. package/coverage/lcov-report/core/api/services/mailer/mailer.hooks.js.html +0 -190
  365. package/coverage/lcov-report/core/api/services/mailer/mailer.service.js.html +0 -118
  366. package/coverage/lcov-report/core/api/services/messages/index.html +0 -116
  367. package/coverage/lcov-report/core/api/services/messages/messages.hooks.js.html +0 -202
  368. package/coverage/lcov-report/core/api/services/organisations/index.html +0 -131
  369. package/coverage/lcov-report/core/api/services/organisations/organisations.hooks.js.html +0 -178
  370. package/coverage/lcov-report/core/api/services/organisations/organisations.service.js.html +0 -343
  371. package/coverage/lcov-report/core/api/services/push/index.html +0 -131
  372. package/coverage/lcov-report/core/api/services/push/push.hooks.js.html +0 -190
  373. package/coverage/lcov-report/core/api/services/push/push.service.js.html +0 -121
  374. package/coverage/lcov-report/core/api/services/storage/index.html +0 -131
  375. package/coverage/lcov-report/core/api/services/storage/storage.hooks.js.html +0 -190
  376. package/coverage/lcov-report/core/api/services/storage/storage.service.js.html +0 -172
  377. package/coverage/lcov-report/core/api/services/tags/index.html +0 -116
  378. package/coverage/lcov-report/core/api/services/tags/tags.hooks.js.html +0 -178
  379. package/coverage/lcov-report/core/api/services/users/index.html +0 -131
  380. package/coverage/lcov-report/core/api/services/users/users.hooks.js.html +0 -310
  381. package/coverage/lcov-report/core/api/services/users/users.service.js.html +0 -100
  382. package/coverage/lcov-report/core/api/utils.js.html +0 -118
  383. package/coverage/lcov-report/core/common/errors.js.html +0 -88
  384. package/coverage/lcov-report/core/common/index.html +0 -191
  385. package/coverage/lcov-report/core/common/index.js.html +0 -115
  386. package/coverage/lcov-report/core/common/permissions.js.html +0 -733
  387. package/coverage/lcov-report/core/common/schema.js.html +0 -190
  388. package/coverage/lcov-report/core/common/utils.js.html +0 -226
  389. package/coverage/lcov-report/core/common/utils.offline.js.html +0 -199
  390. package/coverage/lcov-report/favicon.png +0 -0
  391. package/coverage/lcov-report/index.html +0 -476
  392. package/coverage/lcov-report/map/api/hooks/hooks.catalog.js.html +0 -553
  393. package/coverage/lcov-report/map/api/hooks/hooks.features.js.html +0 -397
  394. package/coverage/lcov-report/map/api/hooks/hooks.query.js.html +0 -1294
  395. package/coverage/lcov-report/map/api/hooks/index.html +0 -161
  396. package/coverage/lcov-report/map/api/hooks/index.js.html +0 -94
  397. package/coverage/lcov-report/map/api/index.html +0 -131
  398. package/coverage/lcov-report/map/api/index.js.html +0 -139
  399. package/coverage/lcov-report/map/api/marshall.js.html +0 -178
  400. package/coverage/lcov-report/map/api/models/alerts.model.mongodb.js.html +0 -106
  401. package/coverage/lcov-report/map/api/models/catalog.model.mongodb.js.html +0 -169
  402. package/coverage/lcov-report/map/api/models/features.model.mongodb.js.html +0 -196
  403. package/coverage/lcov-report/map/api/models/index.html +0 -176
  404. package/coverage/lcov-report/map/api/models/projects.model.mongodb.js.html +0 -109
  405. package/coverage/lcov-report/map/api/models/styles.model.mongodb.js.html +0 -112
  406. package/coverage/lcov-report/map/api/services/alerts/alerts.hooks.js.html +0 -274
  407. package/coverage/lcov-report/map/api/services/alerts/alerts.service.js.html +0 -610
  408. package/coverage/lcov-report/map/api/services/alerts/index.html +0 -131
  409. package/coverage/lcov-report/map/api/services/catalog/catalog.hooks.js.html +0 -328
  410. package/coverage/lcov-report/map/api/services/catalog/index.html +0 -116
  411. package/coverage/lcov-report/map/api/services/daptiles/daptiles.service.js.html +0 -1510
  412. package/coverage/lcov-report/map/api/services/daptiles/index.html +0 -116
  413. package/coverage/lcov-report/map/api/services/features/features.hooks.js.html +0 -310
  414. package/coverage/lcov-report/map/api/services/features/features.service.js.html +0 -544
  415. package/coverage/lcov-report/map/api/services/features/index.html +0 -131
  416. package/coverage/lcov-report/map/api/services/index.html +0 -116
  417. package/coverage/lcov-report/map/api/services/index.js.html +0 -1054
  418. package/coverage/lcov-report/map/api/services/projects/index.html +0 -116
  419. package/coverage/lcov-report/map/api/services/projects/projects.hooks.js.html +0 -439
  420. package/coverage/lcov-report/map/api/services/styles/index.html +0 -116
  421. package/coverage/lcov-report/map/api/services/styles/styles.hooks.js.html +0 -196
  422. package/coverage/lcov-report/map/common/dynamic-grid-source.js.html +0 -466
  423. package/coverage/lcov-report/map/common/errors.js.html +0 -94
  424. package/coverage/lcov-report/map/common/geotiff-grid-source.js.html +0 -544
  425. package/coverage/lcov-report/map/common/grid.js.html +0 -1612
  426. package/coverage/lcov-report/map/common/index.html +0 -371
  427. package/coverage/lcov-report/map/common/index.js.html +0 -172
  428. package/coverage/lcov-report/map/common/meteo-model-grid-source.js.html +0 -556
  429. package/coverage/lcov-report/map/common/moment-utils.js.html +0 -157
  430. package/coverage/lcov-report/map/common/opendap-grid-source.js.html +0 -868
  431. package/coverage/lcov-report/map/common/opendap-utils.js.html +0 -826
  432. package/coverage/lcov-report/map/common/permissions.js.html +0 -130
  433. package/coverage/lcov-report/map/common/time-based-grid-source.js.html +0 -418
  434. package/coverage/lcov-report/map/common/tms-utils.js.html +0 -274
  435. package/coverage/lcov-report/map/common/wcs-grid-source.js.html +0 -364
  436. package/coverage/lcov-report/map/common/wcs-utils.js.html +0 -586
  437. package/coverage/lcov-report/map/common/weacast-grid-source.js.html +0 -1033
  438. package/coverage/lcov-report/map/common/wfs-utils.js.html +0 -574
  439. package/coverage/lcov-report/map/common/wms-utils.js.html +0 -451
  440. package/coverage/lcov-report/map/common/wmts-utils.js.html +0 -547
  441. package/coverage/lcov-report/prettify.css +0 -1
  442. package/coverage/lcov-report/prettify.js +0 -2
  443. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  444. package/coverage/lcov-report/sorter.js +0 -196
  445. package/coverage/lcov.info +0 -11520
  446. package/coverage/map/api/hooks/hooks.catalog.js.html +0 -553
  447. package/coverage/map/api/hooks/hooks.features.js.html +0 -397
  448. package/coverage/map/api/hooks/hooks.query.js.html +0 -1294
  449. package/coverage/map/api/hooks/index.html +0 -161
  450. package/coverage/map/api/hooks/index.js.html +0 -94
  451. package/coverage/map/api/index.html +0 -131
  452. package/coverage/map/api/index.js.html +0 -139
  453. package/coverage/map/api/marshall.js.html +0 -178
  454. package/coverage/map/api/models/alerts.model.mongodb.js.html +0 -106
  455. package/coverage/map/api/models/catalog.model.mongodb.js.html +0 -169
  456. package/coverage/map/api/models/features.model.mongodb.js.html +0 -196
  457. package/coverage/map/api/models/index.html +0 -176
  458. package/coverage/map/api/models/projects.model.mongodb.js.html +0 -109
  459. package/coverage/map/api/models/styles.model.mongodb.js.html +0 -112
  460. package/coverage/map/api/services/alerts/alerts.hooks.js.html +0 -274
  461. package/coverage/map/api/services/alerts/alerts.service.js.html +0 -610
  462. package/coverage/map/api/services/alerts/index.html +0 -131
  463. package/coverage/map/api/services/catalog/catalog.hooks.js.html +0 -328
  464. package/coverage/map/api/services/catalog/index.html +0 -116
  465. package/coverage/map/api/services/daptiles/daptiles.service.js.html +0 -1510
  466. package/coverage/map/api/services/daptiles/index.html +0 -116
  467. package/coverage/map/api/services/features/features.hooks.js.html +0 -310
  468. package/coverage/map/api/services/features/features.service.js.html +0 -544
  469. package/coverage/map/api/services/features/index.html +0 -131
  470. package/coverage/map/api/services/index.html +0 -116
  471. package/coverage/map/api/services/index.js.html +0 -1054
  472. package/coverage/map/api/services/projects/index.html +0 -116
  473. package/coverage/map/api/services/projects/projects.hooks.js.html +0 -439
  474. package/coverage/map/api/services/styles/index.html +0 -116
  475. package/coverage/map/api/services/styles/styles.hooks.js.html +0 -196
  476. package/coverage/map/common/dynamic-grid-source.js.html +0 -466
  477. package/coverage/map/common/errors.js.html +0 -94
  478. package/coverage/map/common/geotiff-grid-source.js.html +0 -544
  479. package/coverage/map/common/grid.js.html +0 -1612
  480. package/coverage/map/common/index.html +0 -371
  481. package/coverage/map/common/index.js.html +0 -172
  482. package/coverage/map/common/meteo-model-grid-source.js.html +0 -556
  483. package/coverage/map/common/moment-utils.js.html +0 -157
  484. package/coverage/map/common/opendap-grid-source.js.html +0 -868
  485. package/coverage/map/common/opendap-utils.js.html +0 -826
  486. package/coverage/map/common/permissions.js.html +0 -130
  487. package/coverage/map/common/time-based-grid-source.js.html +0 -418
  488. package/coverage/map/common/tms-utils.js.html +0 -274
  489. package/coverage/map/common/wcs-grid-source.js.html +0 -364
  490. package/coverage/map/common/wcs-utils.js.html +0 -586
  491. package/coverage/map/common/weacast-grid-source.js.html +0 -1033
  492. package/coverage/map/common/wfs-utils.js.html +0 -574
  493. package/coverage/map/common/wms-utils.js.html +0 -451
  494. package/coverage/map/common/wmts-utils.js.html +0 -547
  495. package/coverage/prettify.css +0 -1
  496. package/coverage/prettify.js +0 -2
  497. package/coverage/sort-arrow-sprite.png +0 -0
  498. package/coverage/sorter.js +0 -196
  499. package/coverage/tmp/coverage-151198-1753351220086-0.json +0 -1
  500. package/coverage/tmp/coverage-151210-1753351220070-0.json +0 -1
  501. package/coverage/tmp/coverage-151221-1753351129816-0.json +0 -1
  502. package/coverage/tmp/coverage-151233-1753351129803-0.json +0 -1
  503. package/coverage/tmp/coverage-151240-1753351129770-0.json +0 -1
  504. package/coverage/tmp/coverage-151307-1753351220058-0.json +0 -1
  505. package/coverage/tmp/coverage-151319-1753351220044-0.json +0 -1
  506. package/coverage/tmp/coverage-151326-1753351220010-0.json +0 -1
  507. package/extras/tours/core/account-profile.js +0 -32
  508. package/extras/tours/core/account.js +0 -143
  509. package/extras/tours/core/add-member.js +0 -75
  510. package/extras/tours/core/add-tag.js +0 -13
  511. package/extras/tours/core/create-group.js +0 -19
  512. package/extras/tours/core/create-organisation.js +0 -19
  513. package/extras/tours/core/create-tag.js +0 -26
  514. package/extras/tours/core/edit-member-role.js +0 -13
  515. package/extras/tours/core/groups.js +0 -65
  516. package/extras/tours/core/join-group.js +0 -13
  517. package/extras/tours/core/login.js +0 -41
  518. package/extras/tours/core/members.js +0 -108
  519. package/extras/tours/core/register.js +0 -61
  520. package/extras/tours/core/send-reset-password.js +0 -14
  521. package/extras/tours/core/tags.js +0 -65
  522. package/extras/tours/map/catalog-panel.js +0 -112
  523. package/extras/tours/map/fab.js +0 -26
  524. package/extras/tours/map/navigation-bar.js +0 -187
  525. package/extras/tours/map/side-nav.js +0 -36
  526. package/test/api/core/test-log-2025-02-05.log +0 -23
  527. package/test/api/core/test-log-2025-05-21.log +0 -15
  528. package/test/api/core/test-log-2025-06-25.log +0 -9
  529. package/test/api/core/test-log-2025-07-24.log +0 -44
  530. package/test/api/map/test-log-2025-05-27.log +0 -13
  531. package/test/api/map/test-log-2025-06-23.log +0 -7
  532. package/test/api/map/test-log-2025-07-24.log +0 -11
  533. package/test/client/core/api.js +0 -361
  534. package/test/client/core/index.js +0 -9
  535. package/test/client/index.js +0 -4
  536. package/test/client/map/index.js +0 -5
  537. package/test.client.js +0 -1
  538. /package/{test/client/core/time.js → extras/tests/core/time.mjs} +0 -0
  539. /package/extras/tours/{map/add-layer.js → add-layer.js} +0 -0
  540. /package/extras/tours/{map/catalog-categories.js → catalog-categories.js} +0 -0
  541. /package/extras/tours/{map/connect-layer.js → connect-layer.js} +0 -0
  542. /package/extras/tours/{map/create-layer.js → create-layer.js} +0 -0
  543. /package/extras/tours/{map/create-view.js → create-view.js} +0 -0
  544. /package/extras/tours/{map/import-layer.js → import-layer.js} +0 -0
  545. /package/extras/tours/{map/timeline.js → pane.bottom.js} +0 -0
@@ -1,7 +1,9 @@
1
1
  import _ from 'lodash'
2
2
  import logger from 'loglevel'
3
3
  import moment from 'moment'
4
+ import jsts from 'jsts'
4
5
  import { getType, getGeom } from '@turf/invariant'
6
+ import { lineString } from '@turf/helpers'
5
7
  import explode from '@turf/explode'
6
8
  import kinks from '@turf/kinks'
7
9
  import clean from '@turf/clean-coords'
@@ -10,13 +12,17 @@ import rhumbDistance from '@turf/rhumb-distance'
10
12
  import rotate from '@turf/transform-rotate'
11
13
  import scale from '@turf/transform-scale'
12
14
  import translate from '@turf/transform-translate'
15
+ import bbox from "@turf/bbox"
16
+ import convex from '@turf/convex'
13
17
  import { api, Time } from '../../../core/client/index.js'
14
18
  import { listenToServiceEvents, unlistenToServiceEvents } from '../../../core/client/utils/index.js'
19
+ import { getStyleType } from './utils.style.js'
15
20
  import { isInMemoryLayer, isFeatureLayer } from './utils.layers.js'
21
+ import { getGeoJsonFeatures } from '../utils.map.js'
16
22
  import chroma from 'chroma-js'
17
23
 
18
- export function processFeatures(geoJson, processor) {
19
- const features = (geoJson.type === 'FeatureCollection' ? geoJson.features : [geoJson])
24
+ export function processFeatures (geoJson, processor) {
25
+ const features = getGeoJsonFeatures(geoJson)
20
26
  if (typeof processor === 'function') {
21
27
  features.forEach(feature => processor(feature))
22
28
  } else if (typeof processor === 'string') {
@@ -25,8 +31,8 @@ export function processFeatures(geoJson, processor) {
25
31
  }
26
32
  }
27
33
 
28
- export function transformFeatures(geoJson, transform) {
29
- const features = (geoJson.type === 'FeatureCollection' ? geoJson.features : [geoJson])
34
+ export function transformFeatures (geoJson, transform) {
35
+ const features = getGeoJsonFeatures(geoJson)
30
36
  features.forEach(feature => {
31
37
  const scaling = _.get(transform, 'scale')
32
38
  const rotation = _.get(transform, 'rotate')
@@ -54,18 +60,40 @@ export function transformFeatures(geoJson, transform) {
54
60
  })
55
61
  }
56
62
 
57
- export async function buildGradientPath(geoJson, options) {
58
- const variable = options.build.variable
63
+ export function computeBoundingBox (geoJson, padding = 0) {
64
+ if (!geoJson) return
65
+ const box = bbox(geoJson)
66
+ if (!_.every(box, _.isFinite)) return null
67
+ if (!padding) return box
68
+ // compute padding
69
+ const padX = (box[2] - box[0]) * padding
70
+ const padY = (box[3] - box[1]) * padding
71
+ return [box[0] - padX, box[1] - padY, box[2] + padX, box[3] + padY]
72
+ }
73
+
74
+ export function computeConvexHull (geoJson) {
75
+ if (!geoJson) return
76
+ const points = explode(geoJson)
77
+ const count = _.size(points.features)
78
+ if (count === 0) return null
79
+ if (count === 1) return points.features[0]
80
+ if (count === 2) return lineString(points.features.map(point => point.geometry.coordinates))
81
+ const hull = convex(points)
82
+ // specific case if points are colinear
83
+ if (!hull) return lineString(points.features.map(point => point.geometry.coordinates))
84
+ return hull
85
+ }
59
86
 
87
+ export async function buildGradientPath (geoJson, options) {
88
+ const variable = options.build.variable
60
89
  // Check if the GeoJSON is a FeatureCollection
61
90
  if (!geoJson || geoJson.type !== 'FeatureCollection') {
62
- console.error('Invalid GeoJSON, a FeatureCollection is required to build a gradient path')
91
+ logger.warn('[KDK] Invalid GeoJSON, a FeatureCollection is required to build a gradient path')
63
92
  return
64
93
  }
65
-
66
94
  // Check chromajs has required infos
67
95
  if (!variable.chromajs.colors) {
68
- console.error(`Invalid chromajs on variable ${variable.name}, missing colors.`)
96
+ logger.warn(`[KDK] Invalid chromajs on variable ${variable.name}, missing colors.`)
69
97
  return
70
98
  }
71
99
  let scale
@@ -75,30 +103,25 @@ export async function buildGradientPath(geoJson, options) {
75
103
  scale = chroma.scale(variable.chromajs.colors).classes(variable.chromajs.classes)
76
104
  }
77
105
  if (!scale) {
78
- console.error(`Invalid chromajs on variable ${variable.name}, missing domain or classes.`)
106
+ logger.warn(`[KDK] Invalid chromajs on variable ${variable.name}, missing domain or classes.`)
79
107
  return
80
108
  }
81
-
82
109
  geoJson.features = geoJson.features.map((feature) => {
83
110
  const geometries = feature.geometry.geometries.map(g => g.coordinates)
84
111
  const values = feature.properties[variable.name]
85
-
112
+ const gradient = values.map(value => scale(value).hex())
86
113
  // Check if the feature has at least two geometries and they are different
87
- if (geometries.length < 2 || _.uniqBy(geometries, JSON.stringify).length < 2) {
88
- console.error('Invalid GeoJSON, at least two geometries are required to construct a line')
89
- // convert it to a point
114
+ if (geometries.length < 2) {
115
+ // Make it a line
90
116
  return {
91
117
  type: 'Feature',
92
118
  geometry: {
93
- type: 'Point',
94
- coordinates: geometries[0],
119
+ type: 'LineString',
120
+ coordinates: [ geometries[0], geometries[0] ]
95
121
  },
96
- properties: feature.properties,
122
+ properties: Object.assign({ gradient: [ gradient[0], gradient[0] ] }, _.omit(feature.properties, variable.name), variable.gradientPath.properties)
97
123
  }
98
124
  }
99
-
100
- const gradient = values.map(value => scale(value).hex())
101
-
102
125
  return {
103
126
  type: 'Feature',
104
127
  geometry: {
@@ -108,11 +131,10 @@ export async function buildGradientPath(geoJson, options) {
108
131
  properties: Object.assign({ gradient }, _.omit(feature.properties, variable.name), variable.gradientPath.properties)
109
132
  }
110
133
  })
111
-
112
134
  geoJson.total = geoJson.features.length
113
135
  }
114
136
 
115
- async function checkBuildInstructions(options) {
137
+ async function checkBuildInstructions (options) {
116
138
  const knownInstructions = ['gradientPath']
117
139
  if (!options.variables) return
118
140
 
@@ -125,7 +147,7 @@ async function checkBuildInstructions(options) {
125
147
  }
126
148
  }
127
149
 
128
- export async function getBaseQueryForFeatures(options) {
150
+ export async function getBaseQueryForFeatures (options) {
129
151
  // Any base query to process ?
130
152
  const baseQuery = {}
131
153
  if (options.baseQuery) {
@@ -141,7 +163,7 @@ export async function getBaseQueryForFeatures(options) {
141
163
  return baseQuery
142
164
  }
143
165
 
144
- export async function getFilterQueryForFeatures(options) {
166
+ export async function getFilterQueryForFeatures (options) {
145
167
  // Any filter query to process ?
146
168
  const filterQuery = {}
147
169
  if (options.filterQuery) {
@@ -173,7 +195,7 @@ export async function getFilterQueryForFeatures(options) {
173
195
  return filterQuery
174
196
  }
175
197
 
176
- export async function getSortQueryForFeatures(options) {
198
+ export async function getSortQueryForFeatures (options) {
177
199
  // Any sort query to process ?
178
200
  const sortQuery = {}
179
201
  if (options.sortQuery) {
@@ -187,12 +209,12 @@ export async function getSortQueryForFeatures(options) {
187
209
  return { $sort: sortQuery }
188
210
  }
189
211
 
190
- export function getFeaturesUpdateInterval(options) {
212
+ export function getFeaturesUpdateInterval (options) {
191
213
  const interval = _.get(options, 'every')
192
214
  return (interval ? moment.duration(interval) : null)
193
215
  }
194
216
 
195
- export function getFeaturesQueryInterval(options) {
217
+ export function getFeaturesQueryInterval (options) {
196
218
  const interval = getFeaturesUpdateInterval(options)
197
219
  let queryInterval = _.get(options, 'queryFrom')
198
220
  // If query interval not given use 2 x refresh interval as default value
@@ -214,7 +236,7 @@ export function shouldSkipFeaturesUpdate(lastUpdateTime, options, interval) {
214
236
  return (Math.abs(elapsed.asMilliseconds()) < interval.asMilliseconds())
215
237
  }
216
238
 
217
- export async function getProbeFeatures(options) {
239
+ export async function getProbeFeatures (options) {
218
240
  // Any base/filter/sort query to process ?
219
241
  const query = await getBaseQueryForFeatures(options)
220
242
  const filterQuery = await getFilterQueryForFeatures(options)
@@ -228,7 +250,7 @@ export async function getProbeFeatures(options) {
228
250
  return response
229
251
  }
230
252
 
231
- export async function getFeaturesQuery(options, queryInterval, queryLevel) {
253
+ export async function getFeaturesQuery (options, queryInterval, queryLevel) {
232
254
  // If not given try to compute query interval from options
233
255
  if (!queryInterval) {
234
256
  queryInterval = getFeaturesQueryInterval(options)
@@ -306,7 +328,7 @@ export async function getFeaturesQuery(options, queryInterval, queryLevel) {
306
328
  return query
307
329
  }
308
330
 
309
- export function isFeatureInQueryInterval(feature, options) {
331
+ export function isFeatureInQueryInterval (feature, options) {
310
332
  // We assume this is not a time-varying layer
311
333
  if (!feature.time) return true
312
334
  const queryInterval = getFeaturesQueryInterval(options)
@@ -324,7 +346,7 @@ export function isFeatureInQueryInterval(feature, options) {
324
346
  return time.isSameOrAfter(gte) && time.isSameOrBefore(lte)
325
347
  }
326
348
 
327
- export async function getFeaturesFromQuery(options, query) {
349
+ export async function getFeaturesFromQuery (options, query) {
328
350
  // Check API to be used in case the layer is coming from a remote "planet"
329
351
  const planetApi = (typeof options.getPlanetApi === 'function' ? options.getPlanetApi() : api)
330
352
  const response = await planetApi.getService(options.service).find(Object.assign({ query }, options.baseParams))
@@ -342,7 +364,7 @@ export async function getFeaturesFromQuery(options, query) {
342
364
  return response
343
365
  }
344
366
 
345
- export function getMeasureForFeatureBaseQuery(layer, feature) {
367
+ export function getMeasureForFeatureBaseQuery (layer, feature) {
346
368
  // We might have a different ID to identify measures related to a timeseries (what is called a chronicle)
347
369
  // than measures displayed on a map. For instance mobile measures might appear at different locations,
348
370
  // but when selecting one we would like to display the timeseries related to all locations.
@@ -356,7 +378,7 @@ export function getMeasureForFeatureBaseQuery(layer, feature) {
356
378
  return query
357
379
  }
358
380
 
359
- export async function getMeasureForFeatureQuery(layer, feature, startTime, endTime, level) {
381
+ export async function getMeasureForFeatureQuery (layer, feature, startTime, endTime, level) {
360
382
  const query = await getFeaturesQuery(_.merge({
361
383
  baseQuery: getMeasureForFeatureBaseQuery(layer, feature)
362
384
  }, layer), {
@@ -366,12 +388,12 @@ export async function getMeasureForFeatureQuery(layer, feature, startTime, endTi
366
388
  return query
367
389
  }
368
390
 
369
- export async function getMeasureForFeatureFromQuery(layer, feature, query) {
391
+ export async function getMeasureForFeatureFromQuery (layer, feature, query) {
370
392
  const result = await getFeaturesFromQuery(layer, query)
371
393
  return _.get(result, 'features[0]')
372
394
  }
373
395
 
374
- export async function getMeasureForFeature(layer, feature, startTime, endTime, level) {
396
+ export async function getMeasureForFeature (layer, feature, startTime, endTime, level) {
375
397
  let probedLocation
376
398
  try {
377
399
  const query = await getMeasureForFeatureQuery(layer, feature, startTime, endTime, level)
@@ -382,11 +404,59 @@ export async function getMeasureForFeature(layer, feature, startTime, endTime, l
382
404
  return probedLocation
383
405
  }
384
406
 
385
- export function checkFeatures(geoJson, options = {
407
+ const JstsErrorI18nKeys = [
408
+ 'GEOMETRY_ERROR',
409
+ 'GEOMETRY_REPEATED_POINT',
410
+ 'GEOMETRY_HOLE_OUTSIDE_SHELL',
411
+ 'GEOMETRY_NESTED_HOLES',
412
+ 'GEOMETRY_DISCONNECTED_INTERIOR',
413
+ 'GEOMETRY_SELF_INTERSECTION',
414
+ 'GEOMETRY_RING_SELF_INTERSECTION',
415
+ 'GEOMETRY_NESTED_SHELLS',
416
+ 'GEOMETRY_DUPLICATE_RINGS',
417
+ 'GEOMETRY_TOO_FEW_POINTS',
418
+ 'GEOMETRY_INVALID_COORDINATES',
419
+ 'GEOMETRY_RING_NOT_CLOSED'
420
+ ]
421
+
422
+ export function cleanFeatures (geoJson, precision = 1e-9) {
423
+ let errors = []
424
+ const geometryTypes = new Set()
425
+ if (geoJson.type === 'Feature') {
426
+ const geometryType = _.get(geoJson, 'geometry.type')
427
+ if (!geometryType) {
428
+ logger.warn('[KDK] feature has undefined geometry')
429
+ return
430
+ }
431
+ geometryTypes.add(geometryType)
432
+ if (geometryType === 'Polygon' || geometryType === 'MultiPolygon') {
433
+ const reader = new jsts.io.GeoJSONReader()
434
+ const writer = new jsts.io.GeoJSONWriter()
435
+ const geometry = reader.read(geoJson.geometry)
436
+ const validator = new jsts.operation.valid.IsValidOp(geometry)
437
+ if (!validator.isValid()) {
438
+ errors.push({ error: 'errors.' + JstsErrorI18nKeys[validator.getValidationError()._errorType], identifier: _.get(geoJson, 'properties.id', _.get(geoJson, 'properties.name', _.get(geoJson, 'properties.label'))) })
439
+ const correctedGeometry = geometry.buffer(precision).buffer(-precision)
440
+ geoJson.geometry = writer.write(correctedGeometry)
441
+ }
442
+ }
443
+ } else {
444
+ _.forEach(geoJson.features, feature => {
445
+ const { errors: errs, geometryTypes: types } = cleanFeatures(feature)
446
+ if (errs) errors = _.concat(errors, errs)
447
+ if (types) {
448
+ _.forEach(types, type => geometryTypes.add(type))
449
+ }
450
+ })
451
+ }
452
+ return { errors, geometryTypes: Array.from(geometryTypes) }
453
+ }
454
+
455
+ export function checkFeatures (geoJson, options = {
386
456
  kinks: true,
387
457
  redundantCoordinates: true
388
458
  }) {
389
- const features = (geoJson.type === 'FeatureCollection' ? geoJson.features : [geoJson])
459
+ const features = getGeoJsonFeatures(geoJson)
390
460
  // Removes redundant coordinates
391
461
  if (options.redundantCoordinates) {
392
462
  features.forEach(feature => clean(feature, { mutate: true }))
@@ -407,9 +477,9 @@ export function checkFeatures(geoJson, options = {
407
477
  return { kinks: kinksFeatures }
408
478
  }
409
479
 
410
- export async function createFeatures(geoJson, layer, chunkSize = 5000, processCallback) {
480
+ export async function createFeatures (geoJson, layer, chunkSize = 5000, processCallback) {
411
481
  if (!layer) return
412
- const features = (geoJson.type === 'FeatureCollection' ? geoJson.features : [geoJson])
482
+ const features = getGeoJsonFeatures(geoJson)
413
483
  features.forEach(feature => {
414
484
  // Remove any temporary ID as we will use the one from MongoDB
415
485
  delete feature._id
@@ -457,8 +527,8 @@ export async function createFeatures(geoJson, layer, chunkSize = 5000, processCa
457
527
  }
458
528
  }
459
529
 
460
- export async function editFeaturesGeometry(geoJson, layer) {
461
- const features = (geoJson.type === 'FeatureCollection' ? geoJson.features : [geoJson])
530
+ export async function editFeaturesGeometry (geoJson, layer) {
531
+ const features = getGeoJsonFeatures(geoJson)
462
532
  const updatedFeatures = []
463
533
  for (let i = 0; i < features.length; i++) {
464
534
  const feature = features[i]
@@ -470,8 +540,8 @@ export async function editFeaturesGeometry(geoJson, layer) {
470
540
  return (geoJson.type === 'FeatureCollection' ? Object.assign(geoJson, { features: updatedFeatures }) : updatedFeatures)
471
541
  }
472
542
 
473
- export async function editFeaturesProperties(geoJson, layer) {
474
- const features = (geoJson.type === 'FeatureCollection' ? geoJson.features : [geoJson])
543
+ export async function editFeaturesProperties (geoJson, layer) {
544
+ const features = getGeoJsonFeatures(geoJson)
475
545
  const updatedFeatures = []
476
546
  for (let i = 0; i < features.length; i++) {
477
547
  const feature = features[i]
@@ -483,8 +553,8 @@ export async function editFeaturesProperties(geoJson, layer) {
483
553
  return (geoJson.type === 'FeatureCollection' ? Object.assign(geoJson, { features: updatedFeatures }) : updatedFeatures)
484
554
  }
485
555
 
486
- export async function editFeaturesStyle(geoJson, layer) {
487
- const features = (geoJson.type === 'FeatureCollection' ? geoJson.features : [geoJson])
556
+ export async function editFeaturesStyle (geoJson, layer) {
557
+ const features = getGeoJsonFeatures(geoJson)
488
558
  const updatedFeatures = []
489
559
  for (let i = 0; i < features.length; i++) {
490
560
  const feature = features[i]
@@ -496,12 +566,12 @@ export async function editFeaturesStyle(geoJson, layer) {
496
566
  return (geoJson.type === 'FeatureCollection' ? Object.assign(geoJson, { features: updatedFeatures }) : updatedFeatures)
497
567
  }
498
568
 
499
- export async function removeFeatures(geoJson, layer) {
569
+ export async function removeFeatures (geoJson, layer) {
500
570
  // Remove all features of a given layer
501
571
  if (!geoJson) {
502
572
  await api.getService(layer.service).remove(null, { query: { layer: layer._id } })
503
573
  } else {
504
- const features = (geoJson.type === 'FeatureCollection' ? geoJson.features : [geoJson])
574
+ const features = getGeoJsonFeatures(geoJson)
505
575
  for (let i = 0; i < features.length; i++) {
506
576
  const feature = features[i]
507
577
  if (feature._id) await api.getService(layer.service).remove(feature._id)
@@ -509,7 +579,7 @@ export async function removeFeatures(geoJson, layer) {
509
579
  }
510
580
  }
511
581
 
512
- export async function fetchGeoJson(dataSource, options = {}) {
582
+ export async function fetchGeoJson (dataSource, options = {}) {
513
583
  const response = await fetch(dataSource)
514
584
  if (response.status !== 200) {
515
585
  throw new Error(`Impossible to fetch ${dataSource}: ` + response.status)
@@ -526,11 +596,7 @@ export function getFeatureStyleType (feature) {
526
596
  logger.warn('[KDK] feature has undefined geometry')
527
597
  return
528
598
  }
529
- if (['Point', 'MultiPoint'].includes(geometryType)) return 'point'
530
- if (['LineString', 'MultiLineString'].includes(geometryType)) return 'line'
531
- if (['Polygon', 'MultiPolygon'].includes(geometryType)) return 'polygon'
532
- logger.warn(`[KDK] unsupported geometry of type of ${geometryType}`)
533
- return
599
+ return getStyleType(geometryType)
534
600
  }
535
601
 
536
602
  // Bind listeners to layer service events and store it in the returned object
@@ -2,18 +2,29 @@ import _ from 'lodash'
2
2
  import formatcoords from 'formatcoords'
3
3
 
4
4
  // Find the nearest time of a given one in a given moment time list
5
- export function getNearestTime (time, times) {
5
+ // if the time list is already sorted in ascending order use the last argument to speed up search
6
+ export function getNearestTime (time, times, sorted = false) {
6
7
  // Look for the nearest time
7
- let timeIndex = -1
8
- let minDiff = Infinity
9
- times.forEach((currentTime, index) => {
10
- const diff = Math.abs(time.diff(currentTime))
11
- if (diff < minDiff) {
12
- minDiff = diff
13
- timeIndex = index
8
+ if (sorted) {
9
+ let timeIndex = 0
10
+ for (; timeIndex < times.length; timeIndex++) {
11
+ if (time.valueOf() < times[timeIndex].valueOf()) break
14
12
  }
15
- })
16
- return { index: timeIndex, difference: minDiff }
13
+ // We've found the first index greater than the time so return the previous
14
+ if (timeIndex > 0) timeIndex--
15
+ return { index: timeIndex, difference: Math.abs(time.diff(times[timeIndex])) }
16
+ } else {
17
+ let timeIndex = -1
18
+ let minDiff = Infinity
19
+ times.forEach((currentTime, index) => {
20
+ const diff = Math.abs(time.diff(currentTime))
21
+ if (diff < minDiff) {
22
+ minDiff = diff
23
+ timeIndex = index
24
+ }
25
+ })
26
+ return { index: timeIndex, difference: minDiff }
27
+ }
17
28
  }
18
29
 
19
30
  // Find the minimum or maximum time interval in a given moment time list
@@ -64,3 +75,7 @@ export function coordinatesToGeoJSON (lat, lon, format, options) {
64
75
  }
65
76
  }
66
77
  }
78
+
79
+ export function getGeoJsonFeatures (geoJson) {
80
+ return (Array.isArray(geoJson) ? geoJson : (geoJson.type === 'FeatureCollection' ? geoJson.features : [geoJson]))
81
+ }
@@ -4,14 +4,14 @@ import { Notify, Loading, uid } from 'quasar'
4
4
  import explode from '@turf/explode'
5
5
  import SphericalMercator from '@mapbox/sphericalmercator'
6
6
  import { i18n, api, LocalCache, utils as kCoreUtils, hooks as kCoreHooks } from '../../../core/client/index.js'
7
- import { checkFeatures, createFeatures, removeFeatures } from './utils.features.js'
7
+ import { cleanFeatures, createFeatures, removeFeatures } from './utils.features.js'
8
8
  import { PMTiles, findTile, zxyToTileId } from 'pmtiles'
9
9
  import { sourcesToViews } from 'protomaps-leaflet'
10
10
  import * as kMapHooks from '../hooks/index.js'
11
- import { generatePropertiesSchema } from '../utils.map.js'
12
- import { generateStyleTemplates, filterQueryToConditions, getDefaultStyleFromTemplates } from './utils.style.js'
11
+ import { generatePropertiesSchema, getGeoJsonFeatures } from '../utils.map.js'
12
+ import { generateStyleTemplates, filterQueryToConditions, getDefaultStyleFromTemplates, DefaultStyle, getStyleType } from './utils.style.js'
13
13
 
14
- export const InternalLayerProperties = ['actions', 'label', 'isVisible', 'isDisabled']
14
+ const InternalLayerProperties = ['actions', 'label', 'isVisible', 'isDisabled']
15
15
 
16
16
  export function isInMemoryLayer (layer) {
17
17
  return layer._id === undefined
@@ -330,6 +330,10 @@ export function isLayerDataEditable (layer) {
330
330
  return _.get(layer, 'isDataEditable', isUserLayer(layer) && isFeatureLayer(layer))
331
331
  }
332
332
 
333
+ export function isLayerFilterEditable (layer) {
334
+ return _.get(layer, 'isFilterEditable', isUserLayer(layer) && isFeatureLayer(layer))
335
+ }
336
+
333
337
  export function isTerrainLayer (layer) {
334
338
  if (layer.type === 'TerrainLayer') return true
335
339
  const cesiumOptions = layer.cesium || layer
@@ -349,7 +353,7 @@ async function parseFiltersFromLayer (layer) {
349
353
  if (!filter.style) continue
350
354
  styles.push({
351
355
  conditions: filterQueryToConditions(filter.active),
352
- values: await styleService.get(filter.style)
356
+ values: _.isObject(filter.style) ? filter.style : await styleService.get(filter.style)
353
357
  })
354
358
  }
355
359
  return styles
@@ -368,19 +372,27 @@ async function generateStyleFromFilters (layer, defaultStyle) {
368
372
  return result
369
373
  }
370
374
 
371
- export async function editLayerStyle (layer, style) {
375
+ export async function editLayerStyle (layer, style, ignoreFeatureStyle = false) {
372
376
  style = _.pick(style, ['point', 'line', 'polygon'])
373
377
  if (layer._id) {
374
378
  // Need to regenerate templates to update default style in them
375
379
  const result = await generateStyleFromFilters(layer, style)
376
380
  if (result) {
381
+ // Update legend
382
+ Object.assign(result, await getLegendForLayer(Object.assign({}, layer, result)))
383
+ if (ignoreFeatureStyle) result.ignoreFeatureStyle = true
377
384
  await api.getService('catalog').patch(layer._id, result)
378
385
  } else {
379
- await api.getService('catalog').patch(layer._id, { 'cesium.style': style, 'leaflet.style': style })
386
+ const legend = await getLegendForLayer(Object.assign({}, layer, { 'cesium.style': style, 'leaflet.style': style }))
387
+ const patch = Object.assign({}, { 'cesium.style': style, 'leaflet.style': style }, legend)
388
+ if (ignoreFeatureStyle) patch.ignoreFeatureStyle = true
389
+ await api.getService('catalog').patch(layer._id, patch)
380
390
  }
381
391
  } else {
382
392
  _.set(layer, 'cesium.style', style)
383
393
  _.set(layer, 'leaflet.style', style)
394
+ Object.assign(layer, await getLegendForLayer(layer))
395
+ if (ignoreFeatureStyle) layer.ignoreFeatureStyle = true
384
396
  }
385
397
  return layer
386
398
  }
@@ -394,6 +406,106 @@ export async function updateLayerWithFiltersStyle (layer) {
394
406
  await api.getService('catalog').patch(layer._id, style)
395
407
  }
396
408
 
409
+ export async function editFilterStyle (layer, filter, engineStyle, style, ignoreFeatureStyle = false) {
410
+ if (!layer._id) return
411
+ const layerDefaultStyle = getDefaultStyleFromTemplates(_.get(layer, 'leaflet.style', {}))
412
+
413
+ const filters = await parseFiltersFromLayer(layer)
414
+ const targetFilterCondition = filterQueryToConditions(filter.active)
415
+ // Update filter style
416
+ _.forEach(filters, f => {
417
+ if (_.isEqual(f.conditions, targetFilterCondition)) {
418
+ f.values = style
419
+ }
420
+ })
421
+
422
+ // Generate new templates
423
+ const templates = generateStyleTemplates(_.merge({}, DefaultStyle, engineStyle, layerDefaultStyle), filters)
424
+ const layerFilters = _.cloneDeep(_.get(layer, 'filters', []))
425
+ // Update filters in layer
426
+ _.forEach(layerFilters, f => {
427
+ if (_.isEqual(f.label, filter.label) && _.isEqual(f.active, filter.active)) {
428
+ f.style = style._id
429
+ }
430
+ })
431
+
432
+ // Patch layer with new templates and filters
433
+ const patch = Object.assign(
434
+ {},
435
+ _.mapKeys(templates, (value, key) => `leaflet.${key}`),
436
+ _.mapKeys(templates, (value, key) => `cesium.${key}`),
437
+ { filters: layerFilters }
438
+ )
439
+ if (ignoreFeatureStyle) patch.ignoreFeatureStyle = true
440
+ // Update legend
441
+ Object.assign(patch, await getLegendForLayer(Object.assign({}, layer, { filters: layerFilters })))
442
+ await api.getService('catalog').patch(layer._id, patch)
443
+ }
444
+
445
+ async function getLayerFiltersWithStyle (layer) {
446
+ const filters = _.get(layer, 'filters', [])
447
+ if (!filters.length) return []
448
+ const styleService = api.getService('styles')
449
+ const filtersWithStyle = []
450
+ for (const filter of filters) {
451
+ const filterWithStyle = _.cloneDeep(filter)
452
+ if (filter.style) {
453
+ filterWithStyle.linkedStyle = _.isObject(filter.style) ? filter.style : await styleService.get(filter.style)
454
+ }
455
+ filtersWithStyle.push(filterWithStyle)
456
+ }
457
+ return filtersWithStyle
458
+ }
459
+
460
+ // Return generic legend or filters for a layer without mutating it
461
+ export async function getLegendForLayer (layer) {
462
+ const generateLegendFromStyle = (root, style, layerGeometryTypes) => {
463
+ const layerStyleTypes = _.uniq(_.map(layerGeometryTypes, type => getStyleType(type)))
464
+ const shapes = { point: 'circle', line: 'polyline', polygon: 'rect' }
465
+ const symbols = []
466
+ _.forIn(shapes, (shape, type) => {
467
+ const isInLayerGeometryTypes = (layerStyleTypes.length === 0) || (layerStyleTypes.includes(type))
468
+ if (style[type] && isInLayerGeometryTypes) {
469
+ symbols.push({
470
+ symbol: { 'media/KShape': { options: _.merge({ shape }, _.omit(style[type], ['size'])) } },
471
+ label: _.get(root, 'label', _.get(root, 'name'))
472
+ })
473
+ }
474
+ })
475
+ return {
476
+ type: 'symbols',
477
+ content: {
478
+ symbols
479
+ }
480
+ }
481
+ }
482
+
483
+ if (_.has(layer, 'filters') && !_.isEmpty(layer.filters)) {
484
+ const filtersWithStyle = await getLayerFiltersWithStyle(layer)
485
+ let hasFilterWithStyle = false
486
+ _.forEach(filtersWithStyle, filter => {
487
+ if (!_.has(filter, 'linkedStyle')) return
488
+ hasFilterWithStyle = true
489
+
490
+ const filterLegend = generateLegendFromStyle(filter, filter.linkedStyle, _.get(layer, 'geometryTypes', []))
491
+ filter.legend = filterLegend
492
+ })
493
+ const legend = {
494
+ legend: { type: 'symbols', label: _.get(layer, 'label', _.get(layer, 'name')), content: {} },
495
+ filters: _.map(filtersWithStyle, filter => _.omit(filter, 'linkedStyle'))
496
+ }
497
+ // For now, only filter with style are displayed in the legend
498
+ // If no filter has style, we want to remove the legend
499
+ if (!hasFilterWithStyle) return { $unset: { legend: '' } }
500
+ return legend
501
+ } else {
502
+ const layerStyle = getDefaultStyleFromTemplates(_.get(layer, 'leaflet.style', {}))
503
+ const legend = generateLegendFromStyle(layer, layerStyle, _.get(layer, 'geometryTypes', []))
504
+ legend.label = _.get(layer, 'label', _.get(layer, 'name'))
505
+ return { legend }
506
+ }
507
+ }
508
+
397
509
  export function generateLayerDefinition (layerSpec, geoJson) {
398
510
  // Check wether the geoJson content is a valid geoJson
399
511
  if (geoJson.type !== 'FeatureCollection' && geoJson.type !== 'Feature') {
@@ -446,18 +558,35 @@ export function generateLayerDefinition (layerSpec, geoJson) {
446
558
 
447
559
  export async function saveGeoJsonLayer (layer, geoJson, chunkSize = 5000) {
448
560
  // Check for invalid features first
449
- const check = checkFeatures(geoJson)
450
- if (check.kinks.length > 0) {
561
+ const { errors } = cleanFeatures(geoJson)
562
+
563
+ if (errors.length > 0) {
564
+ const errorsByKeys = {}
565
+ _.forEach(errors, error => {
566
+ if (!_.has(errorsByKeys, error.error)) errorsByKeys[error.error] = { count: 0, features: [] }
567
+ errorsByKeys[error.error].count++
568
+ if (error.identifier) errorsByKeys[error.error].features.push(error.identifier)
569
+ })
570
+ const errorsList = _.map(errors, error => {
571
+ const hasIdentifiedFeatures = errorsByKeys[error.error].features.length
572
+ const errorString = [
573
+ '<li>',
574
+ i18n.t(error.error, { total: errorsByKeys[error.error].count }),
575
+ hasIdentifiedFeatures ? i18n.t('utils.layers.INVALID_FEATURES_LIST_FEATURES') : '',
576
+ '</li>'
577
+ ].join('')
578
+ const sublist = _.map(errorsByKeys[error.error].features, featureIdentifier => {
579
+ return '<li class="q-ml-lg">' + featureIdentifier + '</li>'
580
+ }).join('')
581
+ return errorString + sublist
582
+ }).join('')
583
+
451
584
  const result = await kCoreUtils.dialog({
452
- title: i18n.t('utils.layers.INVALID_FEATURES_DIALOG_TITLE', { total: check.kinks.length }),
453
- message: i18n.t('utils.layers.INVALID_FEATURES_DIALOG_MESSAGE', { total: check.kinks.length }),
454
- options: {
455
- type: 'toggle',
456
- model: [],
457
- items: [
458
- { label: i18n.t('utils.layers.DOWNLOAD_INVALID_FEATURES_LABEL'), value: 'download' }
459
- ]
460
- },
585
+ title: i18n.t('utils.layers.INVALID_FEATURES_DIALOG_TITLE', { total: errors.length }),
586
+ message: [
587
+ i18n.t('utils.layers.INVALID_FEATURES_DIALOG_MESSAGE', { total: errors.length }),
588
+ i18n.t('utils.layers.INVALID_FEATURES_LIST_ERRORS', { errors: errorsList })
589
+ ].join(''),
461
590
  html: true,
462
591
  ok: {
463
592
  label: i18n.t('OK'),
@@ -469,17 +598,12 @@ export async function saveGeoJsonLayer (layer, geoJson, chunkSize = 5000) {
469
598
  }
470
599
  })
471
600
  if (!result.ok) return
472
- // Export invalid features if required
473
- if (_.get(result, 'data', []).includes('download')) {
474
- kCoreUtils.downloadAsBlob(JSON.stringify({ type: 'FeatureCollection', features: check.kinks }),
475
- i18n.t('utils.layers.INVALID_FEATURES_FILE'), 'application/json;charset=utf-8;')
476
- }
477
601
  }
478
602
  // Change data source from in-memory to features service
479
603
  _.set(layer, 'service', 'features')
480
604
  if (_.has(layer, 'leaflet')) _.set(layer, 'leaflet.source', '/api/features')
481
605
  if (_.has(layer, 'cesium')) _.set(layer, 'cesium.source', '/api/features')
482
- const features = (geoJson.type === 'FeatureCollection' ? geoJson.features : [geoJson])
606
+ const features = getGeoJsonFeatures(geoJson)
483
607
  // If too much data use tiling
484
608
  // The threshold is based on the number of points and not features.
485
609
  // Indeed otherwise the complexity will be different depending on the geometry type