@kalisio/kdk 2.6.3 → 2.7.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 (419) hide show
  1. package/core/api/application.js +2 -4
  2. package/core/api/authentication.js +2 -3
  3. package/core/api/db.js +10 -2
  4. package/core/api/hooks/hooks.authorisations.js +4 -2
  5. package/core/api/hooks/hooks.push.js +6 -2
  6. package/core/api/hooks/hooks.query.js +29 -12
  7. package/core/api/hooks/hooks.users.js +30 -17
  8. package/core/api/models/configurations.model.mongodb.js +4 -0
  9. package/core/api/services/authorisations/authorisations.service.js +1 -1
  10. package/core/api/services/configurations/configurations.hooks.js +33 -0
  11. package/core/api/services/index.js +41 -7
  12. package/core/api/services/messages/messages.hooks.js +9 -3
  13. package/core/client/api.js +14 -1
  14. package/core/client/capabilities.js +1 -6
  15. package/core/client/components/KAvatar.vue +24 -20
  16. package/core/client/components/account/KProfile.vue +10 -71
  17. package/core/client/components/account/index.js +0 -2
  18. package/core/client/components/app/KSettings.vue +1 -0
  19. package/core/client/components/collection/KBoard.vue +4 -3
  20. package/core/client/components/collection/KCardSection.vue +1 -0
  21. package/core/client/components/collection/KGrid.vue +2 -0
  22. package/core/client/components/collection/KTable.vue +5 -1
  23. package/core/client/components/collection/KTimeLine.vue +9 -1
  24. package/core/client/components/collection/index.js +0 -2
  25. package/core/client/components/form/KChipsField.vue +2 -1
  26. package/core/client/components/form/KEmailField.vue +1 -0
  27. package/core/client/components/form/KFileField.vue +22 -1
  28. package/core/client/components/form/KForm.vue +2 -0
  29. package/core/client/components/form/KItemField.vue +1 -0
  30. package/core/client/components/form/KNumberField.vue +1 -0
  31. package/core/client/components/form/KPasswordField.vue +1 -0
  32. package/core/client/components/form/KPhoneField.vue +1 -0
  33. package/core/client/components/form/KPropertyItemField.vue +1 -0
  34. package/core/client/components/form/KResolutionField.vue +1 -0
  35. package/core/client/components/form/KSelectField.vue +31 -0
  36. package/core/client/components/form/KTagField.vue +1 -0
  37. package/core/client/components/form/KTextField.vue +1 -0
  38. package/core/client/components/form/KTokenField.vue +1 -0
  39. package/core/client/components/form/KUnitField.vue +1 -0
  40. package/core/client/components/form/KUrlField.vue +1 -0
  41. package/core/client/components/graphics/KIcon.vue +3 -4
  42. package/core/client/components/layout/KPage.vue +1 -0
  43. package/core/client/components/layout/KWindow.vue +6 -3
  44. package/core/client/components/messages/KMessageComposer.vue +2 -1
  45. package/core/client/components/messages/KMessagesTimeLine.vue +1 -1
  46. package/core/client/components/time/KDate.vue +1 -2
  47. package/core/client/components/time/KDateTime.vue +11 -11
  48. package/core/client/components/time/KTime.vue +1 -1
  49. package/core/client/composables/collection.js +33 -8
  50. package/core/client/composables/errors.js +1 -1
  51. package/core/client/composables/layout.js +9 -9
  52. package/core/client/configurations.js +50 -0
  53. package/core/client/exporter.js +1 -1
  54. package/core/client/i18n/core_en.json +6 -39
  55. package/core/client/i18n/core_fr.json +6 -39
  56. package/core/client/index.js +2 -0
  57. package/core/client/layout.js +8 -8
  58. package/core/client/mixins/mixin.base-activity.js +5 -2
  59. package/core/client/mixins/mixin.base-field.js +3 -3
  60. package/core/client/search.js +2 -1
  61. package/core/client/utils/utils.collection.js +8 -8
  62. package/core/client/utils/utils.items.js +4 -0
  63. package/core/client/utils/utils.push.js +3 -3
  64. package/core/client/utils/utils.session.js +7 -5
  65. package/core/client/utils/utils.shapes.js +38 -7
  66. package/core/client/utils/utils.time.js +21 -22
  67. package/core/common/schemas/users.update-profile.json +3 -2
  68. package/coverage/core/api/application.js.html +1 -1
  69. package/coverage/core/api/authentication.js.html +1 -1
  70. package/coverage/core/api/db.js.html +1 -1
  71. package/coverage/core/api/hooks/hooks.authentication.js.html +1 -1
  72. package/coverage/core/api/hooks/hooks.authorisations.js.html +1 -1
  73. package/coverage/core/api/hooks/hooks.logger.js.html +1 -1
  74. package/coverage/core/api/hooks/hooks.model.js.html +1 -1
  75. package/coverage/core/api/hooks/hooks.push.js.html +22 -10
  76. package/coverage/core/api/hooks/hooks.query.js.html +33 -6
  77. package/coverage/core/api/hooks/hooks.schemas.js.html +1 -1
  78. package/coverage/core/api/hooks/hooks.service.js.html +1 -1
  79. package/coverage/core/api/hooks/hooks.storage.js.html +1 -1
  80. package/coverage/core/api/hooks/hooks.tags.js.html +1 -1
  81. package/coverage/core/api/hooks/hooks.users.js.html +4 -4
  82. package/coverage/core/api/hooks/index.html +23 -23
  83. package/coverage/core/api/hooks/index.js.html +1 -1
  84. package/coverage/core/api/index.html +1 -1
  85. package/coverage/core/api/index.js.html +1 -1
  86. package/coverage/core/api/marshall.js.html +1 -1
  87. package/coverage/core/api/models/configurations.model.mongodb.js.html +1 -1
  88. package/coverage/core/api/models/index.html +1 -1
  89. package/coverage/core/api/models/messages.model.mongodb.js.html +1 -1
  90. package/coverage/core/api/models/tags.model.mongodb.js.html +1 -1
  91. package/coverage/core/api/models/users.model.mongodb.js.html +1 -1
  92. package/coverage/core/api/services/account/account.hooks.js.html +1 -1
  93. package/coverage/core/api/services/account/account.service.js.html +1 -1
  94. package/coverage/core/api/services/account/index.html +1 -1
  95. package/coverage/core/api/services/authorisations/authorisations.hooks.js.html +1 -1
  96. package/coverage/core/api/services/authorisations/authorisations.service.js.html +1 -1
  97. package/coverage/core/api/services/authorisations/index.html +1 -1
  98. package/coverage/core/api/services/configurations/configurations.hooks.js.html +1 -1
  99. package/coverage/core/api/services/configurations/index.html +1 -1
  100. package/coverage/core/api/services/databases/databases.hooks.js.html +1 -1
  101. package/coverage/core/api/services/databases/databases.service.js.html +1 -1
  102. package/coverage/core/api/services/databases/index.html +1 -1
  103. package/coverage/core/api/services/import-export/import-export.hooks.js.html +1 -1
  104. package/coverage/core/api/services/import-export/import-export.service.js.html +1 -1
  105. package/coverage/core/api/services/import-export/index.html +1 -1
  106. package/coverage/core/api/services/index.html +1 -1
  107. package/coverage/core/api/services/index.js.html +1 -1
  108. package/coverage/core/api/services/mailer/index.html +1 -1
  109. package/coverage/core/api/services/mailer/mailer.hooks.js.html +1 -1
  110. package/coverage/core/api/services/mailer/mailer.service.js.html +1 -1
  111. package/coverage/core/api/services/messages/index.html +1 -1
  112. package/coverage/core/api/services/messages/messages.hooks.js.html +1 -1
  113. package/coverage/core/api/services/push/index.html +1 -1
  114. package/coverage/core/api/services/push/push.hooks.js.html +1 -1
  115. package/coverage/core/api/services/push/push.service.js.html +1 -1
  116. package/coverage/core/api/services/storage/index.html +1 -1
  117. package/coverage/core/api/services/storage/storage.hooks.js.html +1 -1
  118. package/coverage/core/api/services/storage/storage.service.js.html +1 -1
  119. package/coverage/core/api/services/tags/index.html +1 -1
  120. package/coverage/core/api/services/tags/tags.hooks.js.html +1 -1
  121. package/coverage/core/api/services/users/index.html +1 -1
  122. package/coverage/core/api/services/users/users.hooks.js.html +1 -1
  123. package/coverage/core/api/services/users/users.service.js.html +1 -1
  124. package/coverage/core/common/errors.js.html +1 -1
  125. package/coverage/core/common/index.html +1 -1
  126. package/coverage/core/common/index.js.html +1 -1
  127. package/coverage/core/common/permissions.js.html +1 -1
  128. package/coverage/core/common/schema.js.html +1 -1
  129. package/coverage/core/common/utils.js.html +1 -1
  130. package/coverage/core/common/utils.offline.js.html +1 -1
  131. package/coverage/index.html +17 -17
  132. package/coverage/lcov-report/core/api/application.js.html +1 -1
  133. package/coverage/lcov-report/core/api/authentication.js.html +1 -1
  134. package/coverage/lcov-report/core/api/db.js.html +1 -1
  135. package/coverage/lcov-report/core/api/hooks/hooks.authentication.js.html +1 -1
  136. package/coverage/lcov-report/core/api/hooks/hooks.authorisations.js.html +1 -1
  137. package/coverage/lcov-report/core/api/hooks/hooks.logger.js.html +1 -1
  138. package/coverage/lcov-report/core/api/hooks/hooks.model.js.html +1 -1
  139. package/coverage/lcov-report/core/api/hooks/hooks.push.js.html +22 -10
  140. package/coverage/lcov-report/core/api/hooks/hooks.query.js.html +33 -6
  141. package/coverage/lcov-report/core/api/hooks/hooks.schemas.js.html +1 -1
  142. package/coverage/lcov-report/core/api/hooks/hooks.service.js.html +1 -1
  143. package/coverage/lcov-report/core/api/hooks/hooks.storage.js.html +1 -1
  144. package/coverage/lcov-report/core/api/hooks/hooks.tags.js.html +1 -1
  145. package/coverage/lcov-report/core/api/hooks/hooks.users.js.html +4 -4
  146. package/coverage/lcov-report/core/api/hooks/index.html +23 -23
  147. package/coverage/lcov-report/core/api/hooks/index.js.html +1 -1
  148. package/coverage/lcov-report/core/api/index.html +1 -1
  149. package/coverage/lcov-report/core/api/index.js.html +1 -1
  150. package/coverage/lcov-report/core/api/marshall.js.html +1 -1
  151. package/coverage/lcov-report/core/api/models/configurations.model.mongodb.js.html +1 -1
  152. package/coverage/lcov-report/core/api/models/index.html +1 -1
  153. package/coverage/lcov-report/core/api/models/messages.model.mongodb.js.html +1 -1
  154. package/coverage/lcov-report/core/api/models/tags.model.mongodb.js.html +1 -1
  155. package/coverage/lcov-report/core/api/models/users.model.mongodb.js.html +1 -1
  156. package/coverage/lcov-report/core/api/services/account/account.hooks.js.html +1 -1
  157. package/coverage/lcov-report/core/api/services/account/account.service.js.html +1 -1
  158. package/coverage/lcov-report/core/api/services/account/index.html +1 -1
  159. package/coverage/lcov-report/core/api/services/authorisations/authorisations.hooks.js.html +1 -1
  160. package/coverage/lcov-report/core/api/services/authorisations/authorisations.service.js.html +1 -1
  161. package/coverage/lcov-report/core/api/services/authorisations/index.html +1 -1
  162. package/coverage/lcov-report/core/api/services/configurations/configurations.hooks.js.html +1 -1
  163. package/coverage/lcov-report/core/api/services/configurations/index.html +1 -1
  164. package/coverage/lcov-report/core/api/services/databases/databases.hooks.js.html +1 -1
  165. package/coverage/lcov-report/core/api/services/databases/databases.service.js.html +1 -1
  166. package/coverage/lcov-report/core/api/services/databases/index.html +1 -1
  167. package/coverage/lcov-report/core/api/services/import-export/import-export.hooks.js.html +1 -1
  168. package/coverage/lcov-report/core/api/services/import-export/import-export.service.js.html +1 -1
  169. package/coverage/lcov-report/core/api/services/import-export/index.html +1 -1
  170. package/coverage/lcov-report/core/api/services/index.html +1 -1
  171. package/coverage/lcov-report/core/api/services/index.js.html +1 -1
  172. package/coverage/lcov-report/core/api/services/mailer/index.html +1 -1
  173. package/coverage/lcov-report/core/api/services/mailer/mailer.hooks.js.html +1 -1
  174. package/coverage/lcov-report/core/api/services/mailer/mailer.service.js.html +1 -1
  175. package/coverage/lcov-report/core/api/services/messages/index.html +1 -1
  176. package/coverage/lcov-report/core/api/services/messages/messages.hooks.js.html +1 -1
  177. package/coverage/lcov-report/core/api/services/push/index.html +1 -1
  178. package/coverage/lcov-report/core/api/services/push/push.hooks.js.html +1 -1
  179. package/coverage/lcov-report/core/api/services/push/push.service.js.html +1 -1
  180. package/coverage/lcov-report/core/api/services/storage/index.html +1 -1
  181. package/coverage/lcov-report/core/api/services/storage/storage.hooks.js.html +1 -1
  182. package/coverage/lcov-report/core/api/services/storage/storage.service.js.html +1 -1
  183. package/coverage/lcov-report/core/api/services/tags/index.html +1 -1
  184. package/coverage/lcov-report/core/api/services/tags/tags.hooks.js.html +1 -1
  185. package/coverage/lcov-report/core/api/services/users/index.html +1 -1
  186. package/coverage/lcov-report/core/api/services/users/users.hooks.js.html +1 -1
  187. package/coverage/lcov-report/core/api/services/users/users.service.js.html +1 -1
  188. package/coverage/lcov-report/core/common/errors.js.html +1 -1
  189. package/coverage/lcov-report/core/common/index.html +1 -1
  190. package/coverage/lcov-report/core/common/index.js.html +1 -1
  191. package/coverage/lcov-report/core/common/permissions.js.html +1 -1
  192. package/coverage/lcov-report/core/common/schema.js.html +1 -1
  193. package/coverage/lcov-report/core/common/utils.js.html +1 -1
  194. package/coverage/lcov-report/core/common/utils.offline.js.html +1 -1
  195. package/coverage/lcov-report/index.html +17 -17
  196. package/coverage/lcov-report/map/api/hooks/hooks.catalog.js.html +1 -1
  197. package/coverage/lcov-report/map/api/hooks/hooks.features.js.html +1 -1
  198. package/coverage/lcov-report/map/api/hooks/hooks.query.js.html +184 -4
  199. package/coverage/lcov-report/map/api/hooks/index.html +5 -5
  200. package/coverage/lcov-report/map/api/hooks/index.js.html +1 -1
  201. package/coverage/lcov-report/map/api/index.html +1 -1
  202. package/coverage/lcov-report/map/api/index.js.html +1 -1
  203. package/coverage/lcov-report/map/api/marshall.js.html +1 -1
  204. package/coverage/lcov-report/map/api/models/alerts.model.mongodb.js.html +1 -1
  205. package/coverage/lcov-report/map/api/models/catalog.model.mongodb.js.html +1 -1
  206. package/coverage/lcov-report/map/api/models/features.model.mongodb.js.html +1 -1
  207. package/coverage/lcov-report/map/api/models/index.html +1 -1
  208. package/coverage/lcov-report/map/api/models/projects.model.mongodb.js.html +1 -1
  209. package/coverage/lcov-report/map/api/models/styles.model.mongodb.js.html +1 -1
  210. package/coverage/lcov-report/map/api/services/alerts/alerts.hooks.js.html +1 -1
  211. package/coverage/lcov-report/map/api/services/alerts/alerts.service.js.html +1 -1
  212. package/coverage/lcov-report/map/api/services/alerts/index.html +1 -1
  213. package/coverage/lcov-report/map/api/services/catalog/catalog.hooks.js.html +1 -1
  214. package/coverage/lcov-report/map/api/services/catalog/index.html +1 -1
  215. package/coverage/lcov-report/map/api/services/daptiles/daptiles.service.js.html +1 -1
  216. package/coverage/lcov-report/map/api/services/daptiles/index.html +1 -1
  217. package/coverage/lcov-report/map/api/services/features/features.hooks.js.html +1 -1
  218. package/coverage/lcov-report/map/api/services/features/features.service.js.html +1 -1
  219. package/coverage/lcov-report/map/api/services/features/index.html +1 -1
  220. package/coverage/lcov-report/map/api/services/index.html +1 -1
  221. package/coverage/lcov-report/map/api/services/index.js.html +1 -1
  222. package/coverage/lcov-report/map/api/services/projects/index.html +1 -1
  223. package/coverage/lcov-report/map/api/services/projects/projects.hooks.js.html +1 -1
  224. package/coverage/lcov-report/map/api/services/styles/index.html +1 -1
  225. package/coverage/lcov-report/map/api/services/styles/styles.hooks.js.html +1 -1
  226. package/coverage/lcov-report/map/common/dynamic-grid-source.js.html +1 -1
  227. package/coverage/lcov-report/map/common/errors.js.html +1 -1
  228. package/coverage/lcov-report/map/common/geotiff-grid-source.js.html +1 -1
  229. package/coverage/lcov-report/map/common/grid.js.html +1 -1
  230. package/coverage/lcov-report/map/common/index.html +1 -1
  231. package/coverage/lcov-report/map/common/index.js.html +1 -1
  232. package/coverage/lcov-report/map/common/meteo-model-grid-source.js.html +1 -1
  233. package/coverage/lcov-report/map/common/moment-utils.js.html +1 -1
  234. package/coverage/lcov-report/map/common/opendap-grid-source.js.html +1 -1
  235. package/coverage/lcov-report/map/common/opendap-utils.js.html +1 -1
  236. package/coverage/lcov-report/map/common/permissions.js.html +1 -1
  237. package/coverage/lcov-report/map/common/time-based-grid-source.js.html +1 -1
  238. package/coverage/lcov-report/map/common/tms-utils.js.html +1 -1
  239. package/coverage/lcov-report/map/common/wcs-grid-source.js.html +1 -1
  240. package/coverage/lcov-report/map/common/wcs-utils.js.html +1 -1
  241. package/coverage/lcov-report/map/common/weacast-grid-source.js.html +1 -1
  242. package/coverage/lcov-report/map/common/wfs-utils.js.html +1 -1
  243. package/coverage/lcov-report/map/common/wms-utils.js.html +1 -1
  244. package/coverage/lcov-report/map/common/wmts-utils.js.html +1 -1
  245. package/coverage/lcov.info +358 -280
  246. package/coverage/map/api/hooks/hooks.catalog.js.html +1 -1
  247. package/coverage/map/api/hooks/hooks.features.js.html +1 -1
  248. package/coverage/map/api/hooks/hooks.query.js.html +184 -4
  249. package/coverage/map/api/hooks/index.html +5 -5
  250. package/coverage/map/api/hooks/index.js.html +1 -1
  251. package/coverage/map/api/index.html +1 -1
  252. package/coverage/map/api/index.js.html +1 -1
  253. package/coverage/map/api/marshall.js.html +1 -1
  254. package/coverage/map/api/models/alerts.model.mongodb.js.html +1 -1
  255. package/coverage/map/api/models/catalog.model.mongodb.js.html +1 -1
  256. package/coverage/map/api/models/features.model.mongodb.js.html +1 -1
  257. package/coverage/map/api/models/index.html +1 -1
  258. package/coverage/map/api/models/projects.model.mongodb.js.html +1 -1
  259. package/coverage/map/api/models/styles.model.mongodb.js.html +1 -1
  260. package/coverage/map/api/services/alerts/alerts.hooks.js.html +1 -1
  261. package/coverage/map/api/services/alerts/alerts.service.js.html +1 -1
  262. package/coverage/map/api/services/alerts/index.html +1 -1
  263. package/coverage/map/api/services/catalog/catalog.hooks.js.html +1 -1
  264. package/coverage/map/api/services/catalog/index.html +1 -1
  265. package/coverage/map/api/services/daptiles/daptiles.service.js.html +1 -1
  266. package/coverage/map/api/services/daptiles/index.html +1 -1
  267. package/coverage/map/api/services/features/features.hooks.js.html +1 -1
  268. package/coverage/map/api/services/features/features.service.js.html +1 -1
  269. package/coverage/map/api/services/features/index.html +1 -1
  270. package/coverage/map/api/services/index.html +1 -1
  271. package/coverage/map/api/services/index.js.html +1 -1
  272. package/coverage/map/api/services/projects/index.html +1 -1
  273. package/coverage/map/api/services/projects/projects.hooks.js.html +1 -1
  274. package/coverage/map/api/services/styles/index.html +1 -1
  275. package/coverage/map/api/services/styles/styles.hooks.js.html +1 -1
  276. package/coverage/map/common/dynamic-grid-source.js.html +1 -1
  277. package/coverage/map/common/errors.js.html +1 -1
  278. package/coverage/map/common/geotiff-grid-source.js.html +1 -1
  279. package/coverage/map/common/grid.js.html +1 -1
  280. package/coverage/map/common/index.html +1 -1
  281. package/coverage/map/common/index.js.html +1 -1
  282. package/coverage/map/common/meteo-model-grid-source.js.html +1 -1
  283. package/coverage/map/common/moment-utils.js.html +1 -1
  284. package/coverage/map/common/opendap-grid-source.js.html +1 -1
  285. package/coverage/map/common/opendap-utils.js.html +1 -1
  286. package/coverage/map/common/permissions.js.html +1 -1
  287. package/coverage/map/common/time-based-grid-source.js.html +1 -1
  288. package/coverage/map/common/tms-utils.js.html +1 -1
  289. package/coverage/map/common/wcs-grid-source.js.html +1 -1
  290. package/coverage/map/common/wcs-utils.js.html +1 -1
  291. package/coverage/map/common/weacast-grid-source.js.html +1 -1
  292. package/coverage/map/common/wfs-utils.js.html +1 -1
  293. package/coverage/map/common/wms-utils.js.html +1 -1
  294. package/coverage/map/common/wmts-utils.js.html +1 -1
  295. package/coverage/tmp/coverage-1028514-1773134124472-0.json +1 -0
  296. package/coverage/tmp/coverage-1028526-1773134124448-0.json +1 -0
  297. package/coverage/tmp/coverage-1028537-1773134124431-0.json +1 -0
  298. package/coverage/tmp/coverage-1028549-1773134124401-0.json +1 -0
  299. package/coverage/tmp/{coverage-222566-1765963609278-0.json → coverage-1028556-1773134124353-0.json} +1 -1
  300. package/extras/configs/widgets.top.js +3 -3
  301. package/extras/tests/core/collection.mjs +2 -9
  302. package/map/api/hooks/hooks.catalog.js +18 -4
  303. package/map/api/services/catalog/catalog.hooks.js +3 -0
  304. package/map/api/services/features/features.hooks.js +3 -1
  305. package/map/api/services/index.js +2 -6
  306. package/map/api/services/styles/styles.hooks.js +6 -1
  307. package/map/client/components/KFeatureActionButton.vue +9 -3
  308. package/map/client/components/KFeaturesFilterManager.vue +5 -5
  309. package/map/client/components/KFilterCondition.vue +17 -10
  310. package/map/client/components/KLayerEditor.vue +49 -39
  311. package/map/client/components/KMeasureTool.vue +7 -1
  312. package/map/client/components/KTimezoneMap.vue +29 -9
  313. package/map/client/components/catalog/KLayersPanel.vue +26 -16
  314. package/map/client/components/catalog/KLayersSelector.vue +13 -2
  315. package/map/client/components/catalog/KViewsPanel.vue +5 -4
  316. package/map/client/components/form/KSelectLayersField.vue +28 -17
  317. package/map/client/components/form/KSelectViewsField.vue +18 -9
  318. package/map/client/components/form/KTimezoneField.vue +1 -2
  319. package/map/client/components/legend/KVariablesLegend.vue +10 -1
  320. package/map/client/components/location/KLocationCardSection.vue +7 -2
  321. package/map/client/components/location/KLocationMap.vue +31 -7
  322. package/map/client/components/selection/KSelectedLayerFeatures.vue +2 -2
  323. package/map/client/components/stickies/KZoomControl.vue +1 -1
  324. package/map/client/components/styles/KStyleManager.vue +4 -1
  325. package/map/client/components/widget/KTimeSeries.vue +174 -497
  326. package/map/client/components/widget/KTimeSeriesSelector.vue +72 -0
  327. package/map/client/components/widget/KTimeSeriesToolbar.vue +83 -0
  328. package/map/client/composables/catalog.js +6 -10
  329. package/map/client/composables/highlight.js +12 -9
  330. package/map/client/composables/project.js +1 -1
  331. package/map/client/composables/selection.js +8 -7
  332. package/map/client/composables/weather.js +9 -2
  333. package/map/client/geolocation.js +8 -5
  334. package/map/client/i18n/map_en.json +10 -8
  335. package/map/client/i18n/map_fr.json +9 -7
  336. package/map/client/leaflet/TiledFeatureLayer.js +85 -82
  337. package/map/client/leaflet/utils/utils.geojson.js +3 -3
  338. package/map/client/mixins/globe/mixin.base-globe.js +15 -6
  339. package/map/client/mixins/globe/mixin.geojson-layers.js +27 -18
  340. package/map/client/mixins/map/mixin.edit-layers.js +9 -1
  341. package/map/client/mixins/map/mixin.pmtiles-layers.js +118 -29
  342. package/map/client/mixins/map/mixin.tiled-mesh-layers.js +12 -5
  343. package/map/client/mixins/map/mixin.tiled-wind-layers.js +19 -10
  344. package/map/client/mixins/mixin.activity.js +23 -30
  345. package/map/client/mixins/mixin.feature-selection.js +41 -5
  346. package/map/client/planets.js +1 -1
  347. package/map/client/readers/reader.kml.js +2 -3
  348. package/map/client/utils/utils.catalog.js +36 -10
  349. package/map/client/utils/utils.layers.js +39 -8
  350. package/map/client/utils/utils.project.js +4 -0
  351. package/map/client/utils/utils.style.js +37 -7
  352. package/map/client/utils/utils.time-series.js +215 -6
  353. package/map/common/schemas/catalog.update.json +1 -1
  354. package/map/common/weacast-grid-source.js +1 -1
  355. package/package.json +3 -3
  356. package/scripts/kash/CHANGELOG.md +0 -4
  357. package/scripts/kash/README.md +0 -9
  358. package/scripts/kash/kash.sh +45 -40
  359. package/scripts/kash/scripts/run_tests.sh +1 -4
  360. package/test/api/core/authentication.test.js +9 -4
  361. package/test/api/core/config/default.cjs +1 -0
  362. package/test/api/core/hooks.test.js +6 -0
  363. package/test/api/core/index.test.js +43 -18
  364. package/test/api/core/push.test.js +8 -8
  365. package/test/api/core/test-log-2026-03-10.log +60 -0
  366. package/test/api/core/users.test.js +384 -0
  367. package/test/api/map/grid-sources.test.js +1 -1
  368. package/test/api/map/test-log-2026-03-10.log +56 -0
  369. package/vite/package.json +11 -2
  370. package/vite/test/core/composables.test.js +77 -0
  371. package/vite/vitest.config.js +13 -0
  372. package/vite/yarn.lock +1096 -18
  373. package/client/css/core.variables.scss +0 -72
  374. package/client/i18n/core_en.json +0 -744
  375. package/client/i18n/core_fr.json +0 -744
  376. package/client/i18n/map_en.json +0 -800
  377. package/client/i18n/map_fr.json +0 -800
  378. package/client/kdk.client.css +0 -47
  379. package/client/kdk.client.js +0 -41097
  380. package/client/kdk.client.map.css +0 -47
  381. package/client/kdk.client.map.js +0 -38182
  382. package/client/kdk.client.map.min.css +0 -1
  383. package/client/kdk.client.map.min.js +0 -27032
  384. package/client/kdk.client.min.css +0 -1
  385. package/client/kdk.client.min.js +0 -29074
  386. package/client/schemas/capture.create.json +0 -132
  387. package/client/schemas/catalog.update.json +0 -44
  388. package/client/schemas/messages.update.json +0 -16
  389. package/client/schemas/projects.create.json +0 -52
  390. package/client/schemas/projects.update.json +0 -52
  391. package/client/schemas/settings.update.json +0 -286
  392. package/client/schemas/tags.update.json +0 -35
  393. package/client/schemas/users.update-profile.json +0 -34
  394. package/core/client/components/account/KAccount.vue +0 -68
  395. package/core/client/components/account/KDeleteAccountManager.vue +0 -62
  396. package/core/client/components/account/KEmailManager.vue +0 -128
  397. package/core/client/components/account/KPasswordManager.vue +0 -90
  398. package/core/client/components/account/KVerifyEmailManager.vue +0 -105
  399. package/core/client/components/collection/KColumn.vue +0 -227
  400. package/core/client/components/collection/KHistory.vue +0 -113
  401. package/core/client/components/collection/KHistoryEntry.vue +0 -109
  402. package/coverage/tmp/coverage-222524-1765963609350-0.json +0 -1
  403. package/coverage/tmp/coverage-222536-1765963609335-0.json +0 -1
  404. package/coverage/tmp/coverage-222547-1765963609324-0.json +0 -1
  405. package/coverage/tmp/coverage-222559-1765963609309-0.json +0 -1
  406. package/scripts/kash/LICENSE +0 -21
  407. package/test/api/core/test-log-2025-07-31.log +0 -15
  408. package/test/api/core/test-log-2025-10-03.log +0 -18
  409. package/test/api/core/test-log-2025-11-10.log +0 -0
  410. package/test/api/core/test-log-2025-11-12.log +0 -117
  411. package/test/api/core/test-log-2025-11-27.log +0 -0
  412. package/test/api/core/test-log-2025-11-28.log +0 -17
  413. package/test/api/core/test-log-2025-12-09.log +0 -148
  414. package/test/api/core/test-log-2025-12-17.log +0 -58
  415. package/test/api/core/test-log-2026-01-29.log +0 -17
  416. package/test/api/map/test-log-2025-07-23.log +0 -1
  417. package/test/api/map/test-log-2025-11-28.log +0 -33
  418. package/test/api/map/test-log-2025-12-10.log +0 -2
  419. package/test/api/map/test-log-2026-01-06.log +0 -26
@@ -16,14 +16,12 @@ import configuration from '@feathersjs/configuration'
16
16
  import errors from '@feathersjs/errors'
17
17
  import express, { authenticate } from '@feathersjs/express'
18
18
  import socketio from '@feathersjs/socketio'
19
- import mongodb from 'mongodb'
20
- import { Database, idToString } from './db.js'
19
+ import { Database, isObjectID, idToString } from './db.js'
21
20
  import auth from './authentication.js'
22
21
 
23
22
  const debug = makeDebug('kdk:core:application')
24
23
  const debugLimiter = makeDebug('kdk:core:application:limiter')
25
24
  const { TooManyRequests, Forbidden, BadRequest } = errors
26
- const { ObjectID } = mongodb
27
25
  const { rest } = express
28
26
  const sift = siftModule.default
29
27
 
@@ -507,7 +505,7 @@ export function kdk (config = {}) {
507
505
  return app.service(app.get('apiPath') + '/' + context + '/' + path)
508
506
  } else if (context && typeof context === 'object') {
509
507
  // Could be Object ID or raw object
510
- if (ObjectID.isValid(context)) return app.service(app.get('apiPath') + '/' + context.toString() + '/' + path)
508
+ if (isObjectID(context)) return app.service(app.get('apiPath') + '/' + context.toString() + '/' + path)
511
509
  else return app.service(app.get('apiPath') + '/' + context._id.toString() + '/' + path)
512
510
  } else {
513
511
  return app.service(app.get('apiPath') + '/' + path)
@@ -4,15 +4,14 @@ import qs from 'qs'
4
4
  import 'winston-daily-rotate-file'
5
5
  // import { RateLimiter } from 'limiter'
6
6
  import HttpLimiter from 'express-rate-limit'
7
- import mongodb from 'mongodb'
8
7
  import errors from '@feathersjs/errors'
9
8
  import { AuthenticationService, JWTStrategy } from '@feathersjs/authentication'
10
9
  import { LocalStrategy } from '@feathersjs/authentication-local'
11
10
  import OAuth from '@feathersjs/authentication-oauth'
12
11
  import PasswordValidator from 'password-validator'
12
+ import { isValidObjectID } from './db.js'
13
13
 
14
14
  const debug = makeDebug('kdk:core:authentication')
15
- const { ObjectID } = mongodb
16
15
  const { oauth, OAuthStrategy } = OAuth
17
16
  const { NotAuthenticated } = errors
18
17
 
@@ -139,7 +138,7 @@ export class JWTAuthenticationStrategy extends JWTStrategy {
139
138
  // Return basic information for a stateless token otherwise
140
139
  if (payload.sub) {
141
140
  // Check for a valid MongoDB ID
142
- if (ObjectID.isValid(payload.sub)) {
141
+ if (isValidObjectID(payload.sub)) {
143
142
  const entityId = await this.getEntityId(result, params)
144
143
  const value = await this.getEntity(entityId, params)
145
144
 
package/core/api/db.js CHANGED
@@ -12,13 +12,21 @@ Object.getPrototypeOf(moment()).toBSON = function () {
12
12
  return this.toDate()
13
13
  }
14
14
 
15
+ // Check if a given object is an instance of MongoDB ObjectID
15
16
  export function isObjectID (id) {
16
17
  return id && (typeof id.toHexString === 'function') && (typeof id.getTimestamp === 'function')
17
18
  }
19
+ // Check if a given string is a valid MongoDB ObjectID
20
+ export function isValidObjectID (id) {
21
+ // We don't use ObjectID.isValid as it returns true for any string that contains 12 characters: https://jira.mongodb.org/browse/NODE-4912.
22
+ // Regular expression that checks for hex value
23
+ const checkForHexRegExp = /^[0-9a-fA-F]{24}$/
24
+ return (id && (id.length === 24) && checkForHexRegExp.test(id))
25
+ }
18
26
 
19
27
  export function idToString (id) {
20
28
  return (typeof id === 'object'
21
- ? (ObjectID.isValid(id)
29
+ ? (isObjectID(id)
22
30
  ? id.toString()
23
31
  : idToString(id._id))
24
32
  : id)
@@ -28,7 +36,7 @@ export function createObjectID (id) {
28
36
  // This ensure it works even if id is already an ObjectID
29
37
  if (isObjectID(id)) return id
30
38
  // Take care that numbers could be a valid object ID
31
- else if ((typeof id === 'number') || !ObjectID.isValid(id)) return null
39
+ else if ((typeof id === 'number') || !isValidObjectID(id)) return null
32
40
  else {
33
41
  const objectId = new ObjectID(id)
34
42
  // It appears that ObjectID.isValid is not reliable in some driver versions, see eg https://jira.mongodb.org/browse/NODE-3760
@@ -187,11 +187,12 @@ export async function authorise (hook) {
187
187
  const authorisationService = hook.app.getService('authorisations')
188
188
  let subject = hook.params.user
189
189
  const payload = _.get(hook.params, 'authentication.payload')
190
+ const subjectId = payload && (payload.sub || payload.appId)
190
191
  if (payload) {
191
192
  // If no user we allow for a stateless token with permissions inside, e.g.
192
193
  // token targeting API gateway (sub = keyId) or app used through iframe (appId = keyId)
193
- if (!subject && (payload.sub || payload.appId)) {
194
- subject = Object.assign({ _id: (payload.sub || payload.appId) }, payload)
194
+ if (!subject && subjectId) {
195
+ subject = Object.assign({ _id: subjectId }, payload)
195
196
  } else if (subject) { // Otherwise we allow to "extend" user abilities by providing additional information in the token
196
197
  subject = Object.assign(subject, _.omit(payload, ['aud', 'iss', 'exp', 'sub', 'iat', 'jti', 'nbf']))
197
198
  }
@@ -232,6 +233,7 @@ export async function authorise (hook) {
232
233
  _.merge(hook.params.query, dbQuery)
233
234
  } else {
234
235
  if (operation === 'find') { // You don't have right to read any items but you have access to the service so the result is empty
236
+ debug('Service access granted but no resource allowed')
235
237
  hook.result = (!_.get(hook, 'params.paginate', true) ? [] : { total: 0, skip: 0, data: [] })
236
238
  } else { // You don't have the right to update/patch/remove any items so any tentative should throw
237
239
  debug('Resource access not granted')
@@ -21,7 +21,11 @@ export async function sendNewSubscriptionEmail (hook) {
21
21
  const currentUser = hook.result
22
22
  const previousUser = hook.params.user
23
23
  // If we can't compare abort, eg f-a-m might patch user to update tokens
24
- if (!currentUser || !previousUser) return
24
+ if (!currentUser || !previousUser) return
25
+ // Or an app might allow a user to patch another for eg permissions management
26
+ const currentUserId = (currentUser._id ? currentUser._id.toString() : null)
27
+ const previousUserId = (previousUser._id ? previousUser._id.toString() : null)
28
+ if (!currentUserId || !previousUserId || (currentUserId !== previousUserId)) return
25
29
  // Retrieve the last subscription
26
30
  const lastSubscription = _.last(_.get(currentUser, 'subscriptions', []))
27
31
  if (!lastSubscription) return
@@ -33,7 +37,7 @@ export async function sendNewSubscriptionEmail (hook) {
33
37
  debug('Last subscription uses an existing fingerprint')
34
38
  return
35
39
  }
36
- debug('Last subscription uses uses a new fingerprint')
40
+ debug('Last subscription uses a new fingerprint')
37
41
  // Send an email to notify the user
38
42
  const domainPath = app.get('domain') + '/#/'
39
43
  const email = {
@@ -1,8 +1,9 @@
1
1
  import _ from 'lodash'
2
- import { marshallComparisonFields, marshallTime, marshallBooleanFields, marshallNumberFields, marshallDateFields } from '../marshall.js'
3
2
  import mongodb from 'mongodb'
4
3
  import errors from '@feathersjs/errors'
5
4
  import makeDebug from 'debug'
5
+ import { marshallComparisonFields, marshallTime, marshallBooleanFields, marshallNumberFields, marshallDateFields } from '../marshall.js'
6
+ import { isValidObjectID, isObjectID } from '../db.js'
6
7
  import { makeDiacriticPattern } from '../../common/utils.js'
7
8
 
8
9
  const { ObjectID } = mongodb
@@ -123,12 +124,12 @@ export function populateObject (options) {
123
124
  // Set the retrieved service on the same field or given one in hook params
124
125
  _.set(params, serviceProperty, service)
125
126
  // Let it work with id/name string or real object
126
- if (typeof id === 'string' || ObjectID.isValid(id)) {
127
+ if (typeof id === 'string' || isObjectID(id)) {
127
128
  const args = { user: hook.params.user }
128
129
  let object
129
130
  try {
130
131
  // Get by ID or name ?
131
- if (ObjectID.isValid(id)) {
132
+ if (isObjectID(id) || isValidObjectID(id)) {
132
133
  object = await service.get(id.toString(), args)
133
134
  } else {
134
135
  Object.assign(args, { query: { name: id.toString() }, paginate: false })
@@ -219,11 +220,11 @@ export function populateObjects (options) {
219
220
  } else {
220
221
  debug(`Populating ${idProperty} with ID ${id}`)
221
222
  // Let it work with id/name string or real object
222
- if (typeof id === 'string' || ObjectID.isValid(id)) {
223
+ if (typeof id === 'string' || isObjectID(id)) {
223
224
  let object
224
225
  try {
225
226
  // Get by ID or name ?
226
- if (ObjectID.isValid(id)) {
227
+ if (isObjectID(id) || isValidObjectID(id)) {
227
228
  object = await service.get(id.toString(), { user: hook.params.user })
228
229
  } else {
229
230
  const results = await service.find({ query: { name: id.toString() }, paginate: false, user: hook.params.user })
@@ -254,15 +255,31 @@ export function unpopulateObjects (options) {
254
255
  return unpopulateObject(options)
255
256
  }
256
257
 
257
- // Used to manage diacritic insensitive fuzzy search
258
- export function diacriticSearch (options = {}) {
259
- return hook => {
260
- const query = hook.params.query
261
- _.forOwn(query, (value, key) => {
262
- if (value.$regex && value.$regex.source && !value.$diacriticSensitive) {
258
+ // Recursively transform any $regex on object to a new $regex managing diacritics.
259
+ // Will flag the regex items with a diacritic property in order to avoid do it twice.
260
+ export function toDiacriticRegex(object) {
261
+ if (Array.isArray(object)) {
262
+ object.forEach(toDiacriticRegex)
263
+ } else if (typeof object === 'object') {
264
+ _.forOwn(object, (value, key) => {
265
+ if (!value) return
266
+ // Check if applicable
267
+ if (value.$regex && !value.$regex.diacritic && value.$regex.source && !value.$diacriticSensitive) {
263
268
  // Take care to support as well case sensitivity by keeping flags
264
- query[key].$regex = new RegExp(makeDiacriticPattern(value.$regex.source), value.$regex.flags)
269
+ value.$regex = new RegExp(makeDiacriticPattern(value.$regex.source), value.$regex.flags)
270
+ // Custom internal property to make the hook reentrant
271
+ value.$regex.diacritic = true
272
+ } else {
273
+ toDiacriticRegex(value)
265
274
  }
266
275
  })
267
276
  }
268
277
  }
278
+
279
+ // Used to manage diacritic insensitive fuzzy search
280
+ export function diacriticSearch (options = {}) {
281
+ return hook => {
282
+ const query = hook.params.query
283
+ if (query) toDiacriticRegex(query)
284
+ }
285
+ }
@@ -3,9 +3,8 @@ import makeDebug from 'debug'
3
3
  import generateRandomPassword from 'password-generator'
4
4
  import common from 'feathers-hooks-common'
5
5
  import errors from '@feathersjs/errors'
6
- import { Roles, RoleNames } from '../../common/permissions.js'
7
6
  import authManagement from 'feathers-authentication-management'
8
-
7
+ import { createObjectID } from '../db.js'
9
8
  const { Forbidden, BadRequest } = errors
10
9
  const { getItems, replaceItems } = common
11
10
  const verifyHooks = authManagement.hooks
@@ -21,23 +20,37 @@ export function allowLocalAuthentication (context) {
21
20
  return _.get(context.app.get('authentication'), 'authStrategies', []).includes('local')
22
21
  }
23
22
 
24
- export function isNotMe (context) {
25
- const userId = _.toString(_.get(context.params, 'user._id'))
26
- if (_.isEmpty(userId)) throw new Forbidden('Not authenticated')
27
- // Before hook
28
- if (context.type === 'before') {
29
- if (context.method === 'find') {
30
- context.params.query = {
31
- ...context.params.query,
32
- _id: userId
33
- }
34
- return context
23
+ export function onlyMe (options = { throwOnMissingUser: true }) {
24
+ return function (context) {
25
+ if (context.type !== 'before') {
26
+ throw new Error('The \'onlyMe\' hook should only be used as a \'before\' hook.')
35
27
  }
36
- return _.toString(context.id) !== userId
28
+ const userId = _.toString(_.get(context.params, 'user._id'))
29
+ if (userId) {
30
+ _.set(context.params, 'query._id', createObjectID(userId))
31
+ } else if (options.throwOnMissingUser) {
32
+ throw new Forbidden('This operation is subject to user identify check but none can be found')
33
+ }
34
+ }
35
+ }
36
+
37
+ export function isNotMe (options = { throwOnMissingUser: false }) {
38
+ return function (context) {
39
+ const userId = _.get(context.params, 'user._id')
40
+ // As no user to compare with can't be me
41
+ if (_.isNil(userId)) {
42
+ if (options.throwOnMissingUser) throw new Forbidden('This operation is subject to user identify check but none can be found')
43
+ else return true
44
+ }
45
+ // Manage get/update/patch/remove before hook
46
+ if (context.id) return (_.toString(context.id) !== _.toString(userId))
47
+ // Manage after hook including multi-operations
48
+ let items = getItems(context)
49
+ if (!Array.isArray(items)) items = [items]
50
+ items = items.filter(item => _.toString(item._id) !== _.toString(userId))
51
+ // If any item not targetting myself
52
+ return items.length > 0
37
53
  }
38
- // After hook
39
- const item = getItems(context)
40
- return _.toString(item._id) !== userId
41
54
  }
42
55
 
43
56
  export function enforcePasswordPolicy (options = {}) {
@@ -0,0 +1,4 @@
1
+ export default function (app, options) {
2
+ const db = options.db || app.db
3
+ options.Model = db.collection('configurations')
4
+ }
@@ -60,7 +60,7 @@ export default {
60
60
  let resources = _.remove(scope, resource => resource._id && (resource._id.toString() === id.toString()))
61
61
  if (resources.length === 0) {
62
62
  // Fallback as name
63
- resources = _.remove(scope, resource => resource.name && (resource.name === id))
63
+ resources = _.remove(scope, resource => resource.name && (resource.name === id.toString()))
64
64
  }
65
65
  if (resources.length > 0) {
66
66
  // This cover the case when we create the scope on the first auth,
@@ -0,0 +1,33 @@
1
+ import commonHooks from 'feathers-hooks-common'
2
+
3
+ export default {
4
+ before: {
5
+ all: [],
6
+ find: [],
7
+ get: [],
8
+ create: [commonHooks.disallow('external')],
9
+ update: [commonHooks.disallow()],
10
+ patch: [],
11
+ remove: [commonHooks.disallow()]
12
+ },
13
+
14
+ after: {
15
+ all: [],
16
+ find: [],
17
+ get: [],
18
+ create: [],
19
+ update: [],
20
+ patch: [],
21
+ remove: []
22
+ },
23
+
24
+ error: {
25
+ all: [],
26
+ find: [],
27
+ get: [],
28
+ create: [],
29
+ update: [],
30
+ patch: [],
31
+ remove: []
32
+ }
33
+ }
@@ -3,6 +3,7 @@ import path from 'path'
3
3
  import makeDebug from 'debug'
4
4
  import { fileURLToPath } from 'url'
5
5
  import mongodb from 'mongodb'
6
+ import { isValidObjectID } from '../db.js'
6
7
  const { ObjectID } = mongodb
7
8
 
8
9
  const __dirname = path.dirname(fileURLToPath(import.meta.url))
@@ -18,11 +19,8 @@ export function getServiceNameAndContext (servicePath) {
18
19
  // Then without context if any
19
20
  const lastSlash = name.lastIndexOf('/')
20
21
  const contextId = (lastSlash >= 0 ? name.substring(0, lastSlash) : '')
21
- // Check if a string is a valid MongoDB Object ID.
22
- // We don't use ObjectID.isValid as it returns true for any string that contains 12 characters: https://jira.mongodb.org/browse/NODE-4912.
23
- // Regular expression that checks for hex value
24
- const checkForHexRegExp = /^[0-9a-fA-F]{24}$/
25
- if (contextId && (contextId.length === 24) && checkForHexRegExp.test(contextId)) {
22
+ // Check if it is a valid MongoDB Object ID otherwise it is not a context string
23
+ if (isValidObjectID(contextId)) {
26
24
  name = name.replace(contextId + '/', '')
27
25
  return { name, contextId }
28
26
  } else {
@@ -80,6 +78,36 @@ export function removeMessagesService (options = {}) {
80
78
  return app.removeService(app.getService('messages', options.context))
81
79
  }
82
80
 
81
+ export function createConfigurationsService (options = {}) {
82
+ const app = this
83
+ return app.createService('configurations', Object.assign({
84
+ servicesPath,
85
+ modelsPath
86
+ }, options))
87
+ }
88
+
89
+ export async function createDefaultConfigurations (context) {
90
+ const app = this
91
+ const defaultConfigurations = app.get('defaultConfigurations')
92
+ if (!defaultConfigurations) return
93
+ const configurationsService = app.getService('configurations', context)
94
+ // Create default configurations if not already done
95
+ const configurations = await configurationsService.find({ paginate: false })
96
+ for (let i = 0; i < defaultConfigurations.length; i++) {
97
+ const defaultConfiguration = defaultConfigurations[i]
98
+ const createdConfiguration = _.find(configurations, { name: defaultConfiguration.name })
99
+ if (!createdConfiguration) {
100
+ app.logger.info('Initializing default configuration (name = ' + defaultConfiguration.name + ')')
101
+ await configurationsService.create(defaultConfiguration)
102
+ }
103
+ }
104
+ }
105
+
106
+ export function removeConfigurationsService (options = {}) {
107
+ const app = this
108
+ return app.removeService(app.getService('configurations', options.context))
109
+ }
110
+
83
111
  export function createDatabasesService (options = {}) {
84
112
  const app = this
85
113
 
@@ -101,11 +129,11 @@ export function createTagsService (options = {}) {
101
129
  }, options))
102
130
  }
103
131
 
104
- export async function createDefaultTags () {
132
+ export async function createDefaultTags (context) {
105
133
  const app = this
106
134
  const defaultTags = app.get('tags').defaultTags
107
135
  if (!defaultTags) return
108
- const tagsService = app.getService('tags')
136
+ const tagsService = app.getService('tags', context)
109
137
  // Create default tags if not already done
110
138
  const tags = await tagsService.find({ paginate: false })
111
139
  for (let i = 0; i < defaultTags.length; i++) {
@@ -177,4 +205,10 @@ export default async function () {
177
205
  await createTagsService.call(app, tagsConfig)
178
206
  debug('\'tags\' service created')
179
207
  }
208
+
209
+ const configurationsConfig = app.get('configurations')
210
+ if (configurationsConfig) {
211
+ await createConfigurationsService.call(app, configurationsConfig)
212
+ debug('\'configurations\' service created')
213
+ }
180
214
  }
@@ -11,9 +11,15 @@ export default {
11
11
  marshallComparisonQuery
12
12
  ],
13
13
  get: [],
14
- create: [commonHooks.setNow('createdAt')],
15
- update: [],
16
- patch: [],
14
+ create: [commonHooks.setNow('createdAt', 'updatedAt')],
15
+ update: [
16
+ commonHooks.discard('createdAt', 'updatedAt'),
17
+ commonHooks.setNow('updatedAt')
18
+ ],
19
+ patch: [
20
+ commonHooks.discard('createdAt', 'updatedAt'),
21
+ commonHooks.setNow('updatedAt')
22
+ ],
17
23
  remove: []
18
24
  },
19
25
 
@@ -9,6 +9,7 @@ import { rx as reactive } from 'feathers-reactive'
9
9
  import createOfflineService from '@kalisio/feathers-localforage'
10
10
  import configuration from 'config'
11
11
  import { permissions } from '../common/index.js'
12
+ import { Context } from './context.js'
12
13
  import { Store } from './store.js'
13
14
  import { LocalCache } from './local-cache.js'
14
15
  import { Events } from './events.js'
@@ -103,10 +104,14 @@ export async function createClient (config) {
103
104
  let service
104
105
  // If a context is given use it
105
106
  if (!_.isEmpty(context)) {
107
+ // The reserved 'global' context actually means no context.
108
+ // It can be used to force access to a global service even if a context is set in store
109
+ // as by default it will otherwise retrieve the contextual service if no context is provided
110
+ if (context === 'global') context = null
106
111
  const servicePath = api.getServicePath(name, context)
107
112
  service = (options.create ? api.service(servicePath) : api.services[servicePath])
108
113
  } else { // Otherwise check for a potential current context to be used
109
- const currentContext = Store.get('context')
114
+ const currentContext = Context.get()
110
115
  const contextualPath = api.getServicePath(name, currentContext)
111
116
  const contextualService = api.services[contextualPath]
112
117
  const globalPath = api.getServicePath(name)
@@ -152,6 +157,9 @@ export async function createClient (config) {
152
157
  }
153
158
  return service
154
159
  }
160
+ api.hasService = function (name, context) {
161
+ return !_.isNil(api.getServiceInstance(name, context))
162
+ }
155
163
  // Used to create a frontend only service with its options
156
164
  api.createService = function (name, options = {}) {
157
165
  const servicePath = api.getServicePath(name, options.context)
@@ -261,6 +269,11 @@ export async function createClient (config) {
261
269
  let result
262
270
  // If no service we have a single generic operation
263
271
  if (service) {
272
+ if (!_.isEmpty(context)) {
273
+ if (context === 'global') context = null
274
+ } else if (context === undefined) {
275
+ context = Context.get()
276
+ }
264
277
  // Check for access to service fisrt
265
278
  const path = api.getServicePath(service, context, false)
266
279
  result = permissions.hasServiceAbilities(abilities, path)
@@ -17,12 +17,7 @@ export const Capabilities = {
17
17
  const capabilities = await window.fetch(api.getConfig('domain') + _.get(config, 'apiPath') + '/capabilities')
18
18
  this.content = await capabilities.json()
19
19
  // Store latest capabilities data for offline mode
20
- // Avoid blocking on eg QuotaExceededError
21
- try {
22
- await LocalCache.setItem('capabilities', this.content)
23
- } catch (error) {
24
- logger.error(error)
25
- }
20
+ await LocalCache.setItem('capabilities', this.content)
26
21
  }
27
22
  logger.debug('[KDK] Capabilities initialized with content:', this.content)
28
23
  if (!this.content) return
@@ -1,21 +1,23 @@
1
1
  <template>
2
- <q-avatar v-if="avatar" :size="size">
3
- <q-img :src="avatar" />
4
- <q-tooltip v-if="tooltip">
5
- {{ name }}
6
- </q-tooltip>
7
- </q-avatar>
8
- <q-avatar v-else-if="icon" :size="size" :color="color" text-color="white" :icon="icon">
9
- <q-tooltip v-if="tooltip">
10
- {{ name }}
11
- </q-tooltip>
12
- </q-avatar>
13
- <q-avatar v-else-if="initials" :size="size" color="primary" text-color="white">
14
- {{ initials }}
15
- <q-tooltip v-if="tooltip">
16
- {{ name }}
17
- </q-tooltip>
18
- </q-avatar>
2
+ <div>
3
+ <q-avatar v-if="avatar" :size="size">
4
+ <q-img :src="avatar" />
5
+ <q-tooltip v-if="tooltip">
6
+ {{ name }}
7
+ </q-tooltip>
8
+ </q-avatar>
9
+ <q-avatar v-else-if="icon" :size="size" :color="color" text-color="white" :icon="icon">
10
+ <q-tooltip v-if="tooltip">
11
+ {{ name }}
12
+ </q-tooltip>
13
+ </q-avatar>
14
+ <q-avatar v-else-if="initials" :size="size" color="primary" text-color="white">
15
+ {{ initials }}
16
+ <q-tooltip v-if="tooltip">
17
+ {{ name }}
18
+ </q-tooltip>
19
+ </q-avatar>
20
+ </div>
19
21
  </template>
20
22
 
21
23
  <script>
@@ -75,13 +77,15 @@ export default {
75
77
  avatar.uri = data.uri
76
78
  this.avatar = avatar.uri
77
79
  */
78
- this.avatar = await Storage.getObjectUrl({
80
+ const options = {
79
81
  file: _.get(avatar, 'name'),
80
82
  key: avatarId,
81
83
  query: {
82
84
  timestamp: Date.now()
83
- }
84
- })
85
+ },
86
+ ...(!_.isNil(_.get(this, 'options.context')) && { context: this.options.context })
87
+ }
88
+ this.avatar = await Storage.getObjectUrl(options)
85
89
  return
86
90
  }
87
91
  this.avatar = null
@@ -1,18 +1,13 @@
1
1
  <template>
2
2
  <div v-if="User" class="full-width column">
3
3
  <!-- Header -->
4
- <KPanel
5
- id="profile-header"
6
- :content="header"
7
- :context="User"
8
- class="q-py-sm full-width justify-end no-wrap"
9
- @triggered="onTriggered"
10
- />
4
+ <component v-if="hasHeader" :is="computedHeaderComponent" class="q-py-sm full-width justify-end no-wrap" />
11
5
  <!-- Avatar -->
12
6
  <div v-if="avatar && userAvatar" class="q-py-sm column items-center">
13
7
  <KAvatar
14
8
  :subject="userAvatar"
15
9
  size="5rem"
10
+ :options="options"
16
11
  />
17
12
  </div>
18
13
  <!-- Information -->
@@ -41,20 +36,13 @@
41
36
  import _ from 'lodash'
42
37
  import { computed } from 'vue'
43
38
  import { useUser } from '../../composables'
39
+ import { loadComponent } from '../../utils/index.js'
40
+ import config from 'config'
44
41
  import KAvatar from '../KAvatar.vue'
45
- import KPanel from '../KPanel.vue'
46
42
  import KChip from '../KChip.vue'
47
43
 
48
44
  // Props
49
- const props = defineProps({
50
- editable: {
51
- type: Boolean,
52
- default: true
53
- },
54
- manageable: {
55
- type: Boolean,
56
- default: true
57
- },
45
+ defineProps({
58
46
  avatar: {
59
47
  type: Boolean,
60
48
  default: true
@@ -69,63 +57,14 @@ const props = defineProps({
69
57
  }
70
58
  })
71
59
 
72
- // Emit
73
- const emit = defineEmits(['triggered'])
74
-
75
60
  // Data
76
61
  const { User, name: userName, description: userDescription, avatar: userAvatar, role: userRole } = useUser()
62
+ const headerComponent = _.get(config, 'profile.header')
63
+ const hasHeader = !_.isNil(headerComponent)
64
+ const options = { context: 'global' }
77
65
 
78
66
  // Computed
79
- const header = computed(() => {
80
- const actions = []
81
- if (props.editable) {
82
- actions.push({
83
- id: 'edit-profile',
84
- icon: 'las la-edit',
85
- size: '0.75rem',
86
- tooltip: 'KProfile.EDIT_PROFILE',
87
- dialog: {
88
- component: 'editor/KEditor',
89
- service: 'users',
90
- objectId: User.value._id,
91
- perspective: 'profile',
92
- hideButtons: true,
93
- cancelAction: 'CANCEL',
94
- okAction: {
95
- id: 'ok-button',
96
- label: 'APPLY',
97
- handler: 'apply'
98
- }
99
- }
100
- })
101
- }
102
- if (props.manageable) {
103
- const manageAccountAction = {
104
- id: 'manage-account',
105
- icon: 'las la-cog',
106
- size: '0.75rem',
107
- tooltip: 'KProfile.MANAGE_ACCOUNT',
108
- dialog: {
109
- component: 'account/KAccount',
110
- okAction: 'CLOSE'
111
- }
112
- }
113
- if (_.has(User.value, 'isVerified') && !User.value.isVerified) {
114
- manageAccountAction.badge = {
115
- rounded: true,
116
- floating: true,
117
- class: 'q-ma-sm',
118
- color: 'red',
119
- icon: { name: 'fas fa-exclamation', size: '8px' }
120
- }
121
- }
122
- actions.push(manageAccountAction)
123
- }
124
- return actions
67
+ const computedHeaderComponent = computed(() => {
68
+ return loadComponent(headerComponent)
125
69
  })
126
-
127
- // Functions
128
- function onTriggered (args) {
129
- emit('triggered', args)
130
- }
131
70
  </script>