@kalisio/kdk 1.6.0 → 1.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 (188) hide show
  1. package/.travis.test.sh +1 -1
  2. package/CHANGELOG.md +63 -13
  3. package/extras/tours/map/catalog-panel.js +61 -10
  4. package/extras/tours/map/create-view.js +25 -0
  5. package/extras/tours/map/fab.js +10 -1
  6. package/extras/tours/map/navigation-bar.js +7 -9
  7. package/lib/core/api/application.js +9 -1
  8. package/lib/core/api/application.js.map +1 -1
  9. package/lib/core/client/components/chart/KChart.vue +115 -0
  10. package/lib/core/client/components/chart/KStatsChart.vue +76 -0
  11. package/lib/core/client/components/chart/index.js +20 -0
  12. package/lib/core/client/components/chart/index.js.map +1 -0
  13. package/lib/core/client/components/collection/KFilter.vue +6 -0
  14. package/lib/core/client/components/collection/KHistoryEntry.vue +1 -1
  15. package/lib/core/client/components/collection/KItem.vue +4 -4
  16. package/lib/core/client/components/form/KChipsField.vue +4 -4
  17. package/lib/core/client/components/form/KView.vue +1 -1
  18. package/lib/core/client/components/frame/KAction.vue +40 -5
  19. package/lib/core/client/components/frame/KBlock.vue +7 -7
  20. package/lib/core/client/components/frame/KContent.vue +1 -1
  21. package/lib/core/client/components/frame/KOpener.vue +1 -1
  22. package/lib/core/client/components/frame/KPanel.vue +8 -7
  23. package/lib/core/client/components/frame/KPopupAction.vue +6 -0
  24. package/lib/core/client/components/frame/KScreen.vue +1 -1
  25. package/lib/core/client/components/frame/KStamp.vue +4 -2
  26. package/lib/core/client/components/frame/index.js +1 -6
  27. package/lib/core/client/components/frame/index.js.map +1 -1
  28. package/lib/core/client/components/input/KIconChooser.vue +5 -2
  29. package/lib/core/client/components/input/KPalette.vue +1 -1
  30. package/lib/core/client/components/input/index.js +14 -4
  31. package/lib/core/client/components/input/index.js.map +1 -1
  32. package/lib/core/client/components/layout/KFab.vue +1 -1
  33. package/lib/core/client/components/layout/KLayout.vue +10 -2
  34. package/lib/core/client/components/layout/KPage.vue +19 -18
  35. package/lib/core/client/components/layout/KTour.vue +5 -3
  36. package/lib/core/client/components/layout/KWindow.vue +211 -59
  37. package/lib/core/client/components/media/KMediaBrowser.vue +6 -6
  38. package/lib/core/client/components/menu/KMenu.vue +13 -5
  39. package/lib/core/client/components/menu/KRadialFab.vue +22 -24
  40. package/lib/core/client/components/menu/KRadialFabItem.vue +17 -18
  41. package/lib/core/client/components/team/KGroupsActivity.vue +1 -1
  42. package/lib/core/client/components/team/KJoinGroup.vue +2 -2
  43. package/lib/core/client/components/time/KAbsoluteTimeRange.vue +190 -0
  44. package/lib/core/client/components/time/KRelativeTimeRanges.vue +192 -0
  45. package/lib/core/client/components/time/index.js +20 -0
  46. package/lib/core/client/components/time/index.js.map +1 -0
  47. package/lib/core/client/i18n/core_en.json +35 -12
  48. package/lib/core/client/i18n/core_fr.json +36 -13
  49. package/lib/core/client/index.js +1 -1
  50. package/lib/core/client/index.js.map +1 -1
  51. package/lib/core/client/mixins/mixin.base-collection.js +11 -1
  52. package/lib/core/client/mixins/mixin.base-collection.js.map +1 -1
  53. package/lib/core/client/mixins/mixin.base-widget.js +25 -13
  54. package/lib/core/client/mixins/mixin.base-widget.js.map +1 -1
  55. package/lib/core/client/services/index.js +2 -1
  56. package/lib/core/client/services/index.js.map +1 -1
  57. package/lib/core/client/services/local-settings.service.js +4 -0
  58. package/lib/core/client/services/local-settings.service.js.map +1 -1
  59. package/lib/core/client/time.js +25 -15
  60. package/lib/core/client/time.js.map +1 -1
  61. package/lib/core/client/units.js +12 -0
  62. package/lib/core/client/units.js.map +1 -1
  63. package/lib/core/client/utils.js +11 -0
  64. package/lib/core/client/utils.js.map +1 -1
  65. package/lib/core/common/schemas/settings.update.json +14 -4
  66. package/lib/map/api/hooks/hooks.catalog.js +20 -0
  67. package/lib/map/api/hooks/hooks.catalog.js.map +1 -1
  68. package/lib/map/api/models/catalog.model.mongodb.js +6 -1
  69. package/lib/map/api/models/catalog.model.mongodb.js.map +1 -1
  70. package/lib/map/api/models/features.model.mongodb.js +5 -0
  71. package/lib/map/api/models/features.model.mongodb.js.map +1 -1
  72. package/lib/map/api/services/catalog/catalog.hooks.js +3 -1
  73. package/lib/map/api/services/catalog/catalog.hooks.js.map +1 -1
  74. package/lib/map/client/components/KColorLegend.vue +22 -21
  75. package/lib/map/client/components/KFeaturesChart.vue +81 -110
  76. package/lib/map/client/components/KLayerStyleForm.vue +119 -47
  77. package/lib/map/client/components/KLevelSlider.vue +30 -29
  78. package/lib/map/client/components/KLocationMap.vue +2 -2
  79. package/lib/map/client/components/KMeasureTool.vue +30 -6
  80. package/lib/map/client/components/KPositionIndicator.vue +4 -4
  81. package/lib/map/client/components/KTimeline.vue +25 -27
  82. package/lib/map/client/components/KTimezoneMap.vue +156 -0
  83. package/lib/map/client/components/KUrlLegend.vue +11 -10
  84. package/lib/map/client/components/catalog/KBaseLayersSelector.vue +1 -1
  85. package/lib/map/client/components/catalog/KCatalogLayersPanel.vue +56 -0
  86. package/lib/map/client/components/catalog/KCreateView.vue +91 -0
  87. package/lib/map/client/components/catalog/KLayerCategories.vue +2 -1
  88. package/lib/map/client/components/catalog/{KCatalog.vue → KLayersPanel.vue} +19 -37
  89. package/lib/map/client/components/catalog/KUserLayersPanel.vue +40 -0
  90. package/lib/map/client/components/catalog/KViewSelector.vue +46 -0
  91. package/lib/map/client/components/catalog/KViewsPanel.vue +110 -0
  92. package/lib/map/client/components/catalog/KWeatherLayersSelector.vue +4 -13
  93. package/lib/map/client/components/form/KTimezoneField.vue +135 -0
  94. package/lib/map/client/components/widget/KElevationProfile.vue +488 -0
  95. package/lib/map/client/components/widget/KInformationBox.vue +48 -23
  96. package/lib/map/client/components/widget/KMapillaryViewer.vue +26 -20
  97. package/lib/map/client/components/widget/KTimeSeries.vue +267 -347
  98. package/lib/map/client/i18n/map_en.json +63 -40
  99. package/lib/map/client/i18n/map_fr.json +65 -42
  100. package/lib/map/client/leaflet/GradientPath.js +40 -19
  101. package/lib/map/client/leaflet/GradientPath.js.map +1 -1
  102. package/lib/map/client/leaflet/TiledFeatureLayer.js +527 -93
  103. package/lib/map/client/leaflet/TiledFeatureLayer.js.map +1 -1
  104. package/lib/map/client/leaflet/TiledMeshLayer.js +58 -35
  105. package/lib/map/client/leaflet/TiledMeshLayer.js.map +1 -1
  106. package/lib/map/client/leaflet/utils.js +44 -3
  107. package/lib/map/client/leaflet/utils.js.map +1 -1
  108. package/lib/map/client/mixins/globe/mixin.base-globe.js +16 -1
  109. package/lib/map/client/mixins/globe/mixin.base-globe.js.map +1 -1
  110. package/lib/map/client/mixins/globe/mixin.file-layers.js +12 -2
  111. package/lib/map/client/mixins/globe/mixin.file-layers.js.map +1 -1
  112. package/lib/map/client/mixins/globe/mixin.geojson-layers.js +7 -6
  113. package/lib/map/client/mixins/globe/mixin.geojson-layers.js.map +1 -1
  114. package/lib/map/client/mixins/globe/mixin.popup.js +4 -2
  115. package/lib/map/client/mixins/globe/mixin.popup.js.map +1 -1
  116. package/lib/map/client/mixins/globe/mixin.style.js +8 -4
  117. package/lib/map/client/mixins/globe/mixin.style.js.map +1 -1
  118. package/lib/map/client/mixins/globe/mixin.tooltip.js +4 -2
  119. package/lib/map/client/mixins/globe/mixin.tooltip.js.map +1 -1
  120. package/lib/map/client/mixins/index.js +23 -18
  121. package/lib/map/client/mixins/index.js.map +1 -1
  122. package/lib/map/client/mixins/map/mixin.base-map.js +20 -2
  123. package/lib/map/client/mixins/map/mixin.base-map.js.map +1 -1
  124. package/lib/map/client/mixins/map/mixin.edit-layers.js +8 -4
  125. package/lib/map/client/mixins/map/mixin.edit-layers.js.map +1 -1
  126. package/lib/map/client/mixins/map/mixin.geojson-layers.js +27 -5
  127. package/lib/map/client/mixins/map/mixin.geojson-layers.js.map +1 -1
  128. package/lib/map/client/mixins/map/mixin.heatmap-layers.js +6 -1
  129. package/lib/map/client/mixins/map/mixin.heatmap-layers.js.map +1 -1
  130. package/lib/map/client/mixins/map/mixin.popup.js +1 -1
  131. package/lib/map/client/mixins/map/mixin.popup.js.map +1 -1
  132. package/lib/map/client/mixins/map/mixin.style.js +8 -4
  133. package/lib/map/client/mixins/map/mixin.style.js.map +1 -1
  134. package/lib/map/client/mixins/map/mixin.tiled-mesh-layers.js +4 -11
  135. package/lib/map/client/mixins/map/mixin.tiled-mesh-layers.js.map +1 -1
  136. package/lib/map/client/mixins/map/mixin.tiled-wind-layers.js +0 -11
  137. package/lib/map/client/mixins/map/mixin.tiled-wind-layers.js.map +1 -1
  138. package/lib/map/client/mixins/map/mixin.tooltip.js +1 -1
  139. package/lib/map/client/mixins/map/mixin.tooltip.js.map +1 -1
  140. package/lib/map/client/mixins/mixin.activity.js +150 -150
  141. package/lib/map/client/mixins/mixin.activity.js.map +1 -1
  142. package/lib/map/client/mixins/mixin.catalog-panel.js +36 -0
  143. package/lib/map/client/mixins/mixin.catalog-panel.js.map +1 -0
  144. package/lib/map/client/mixins/mixin.feature-selection.js +17 -8
  145. package/lib/map/client/mixins/mixin.feature-selection.js.map +1 -1
  146. package/lib/map/client/mixins/mixin.feature-service.js +36 -16
  147. package/lib/map/client/mixins/mixin.feature-service.js.map +1 -1
  148. package/lib/map/client/mixins/mixin.infobox.js +1 -1
  149. package/lib/map/client/mixins/mixin.infobox.js.map +1 -1
  150. package/lib/map/client/mixins/mixin.levels.js +26 -12
  151. package/lib/map/client/mixins/mixin.levels.js.map +1 -1
  152. package/lib/map/client/mixins/mixin.style.js +1 -0
  153. package/lib/map/client/mixins/mixin.style.js.map +1 -1
  154. package/lib/map/client/mixins/mixin.weacast.js +15 -23
  155. package/lib/map/client/mixins/mixin.weacast.js.map +1 -1
  156. package/lib/map/client/pixi-utils.js +8 -177
  157. package/lib/map/client/pixi-utils.js.map +1 -1
  158. package/lib/map/client/utils.js +1 -0
  159. package/lib/map/client/utils.js.map +1 -1
  160. package/lib/map/common/grid.js +131 -0
  161. package/lib/map/common/grid.js.map +1 -1
  162. package/lib/map/common/index.js +22 -11
  163. package/lib/map/common/index.js.map +1 -1
  164. package/lib/map/common/meteo-model-grid-source.js +5 -2
  165. package/lib/map/common/meteo-model-grid-source.js.map +1 -1
  166. package/lib/map/common/time-based-grid-source.js +5 -2
  167. package/lib/map/common/time-based-grid-source.js.map +1 -1
  168. package/lib/test/client/core/collection.js +31 -13
  169. package/lib/test/client/core/collection.js.map +1 -1
  170. package/lib/test/client/core/layout.js +137 -49
  171. package/lib/test/client/core/layout.js.map +1 -1
  172. package/lib/test/client/core/utils.js +89 -22
  173. package/lib/test/client/core/utils.js.map +1 -1
  174. package/lib/test/client/map/catalog.js +134 -41
  175. package/lib/test/client/map/catalog.js.map +1 -1
  176. package/lib/test/client/map/controls.js +7 -4
  177. package/lib/test/client/map/controls.js.map +1 -1
  178. package/lib/test/client/map/index.js +12 -0
  179. package/lib/test/client/map/index.js.map +1 -1
  180. package/lib/test/client/map/utils.js +67 -0
  181. package/lib/test/client/map/utils.js.map +1 -0
  182. package/package.json +5 -5
  183. package/extras/tours/map/favorite-views.js +0 -53
  184. package/lib/core/client/components/frame/KChart.vue +0 -60
  185. package/lib/core/client/components/input/KCodeInput.vue +0 -50
  186. package/lib/core/client/components/input/KTimeRangeChooser.vue +0 -109
  187. package/lib/core/client/components/time/KTimeRange.vue +0 -144
  188. package/lib/map/client/components/KFavoriteViews.vue +0 -217
@@ -49,12 +49,17 @@ let updateLayerReferences = exports.updateLayerReferences = (() => {
49
49
  };
50
50
  })();
51
51
 
52
+ exports.getDefaultCategories = getDefaultCategories;
52
53
  exports.filterLayers = filterLayers;
53
54
 
54
55
  var _lodash = require('lodash');
55
56
 
56
57
  var _lodash2 = _interopRequireDefault(_lodash);
57
58
 
59
+ var _sift = require('sift');
60
+
61
+ var _sift2 = _interopRequireDefault(_sift);
62
+
58
63
  var _feathersHooksCommon = require('feathers-hooks-common');
59
64
 
60
65
  var _debug = require('debug');
@@ -67,6 +72,21 @@ function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, a
67
72
 
68
73
  const debug = (0, _debug2.default)('kdk:map:catalog:hooks');
69
74
 
75
+ // By default we only return layers and not other objects in catalog
76
+ function getDefaultCategories(hook) {
77
+ const query = _lodash2.default.get(hook, 'params.query', {});
78
+ if (query.type === 'Category') {
79
+ const catalog = hook.app.get('catalog');
80
+ let defaultCategories = catalog ? catalog.categories || [] : [];
81
+ // Add implicit type
82
+ defaultCategories = defaultCategories.map(category => Object.assign(category, { type: 'Category' }));
83
+ // Then filter according to query
84
+ defaultCategories = defaultCategories.filter((0, _sift2.default)(_lodash2.default.omit(query, ['$sort', '$limit', '$skip'])));
85
+ const item = (0, _feathersHooksCommon.getItems)(hook);
86
+ (0, _feathersHooksCommon.replaceItems)(hook, item.concat(defaultCategories.map(category => Object.assign(category, { type: 'Category' }))));
87
+ }
88
+ }
89
+
70
90
  // By default we only return layers and not other objects in catalog
71
91
  function filterLayers(hook) {
72
92
  const query = _lodash2.default.get(hook, 'params.query', {});
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../map/api/hooks/hooks.catalog.js"],"names":["hook","type","_","get","params","endsWith","previousLayer","layer","contexts","service","find","query","$in","layers","name","paginate","length","debug","Promise","all","map","context","method","remove","layerName","patch","_id","updateLayerReferences","filterLayers","$nin","set"],"mappings":";;;;;;;AAaA;;+BACO,WAAsCA,IAAtC,EAA4C;AACjD;AACA,UAAMC,OAAOC,iBAAEC,GAAF,CAAMH,KAAKI,MAAX,EAAmB,mBAAnB,EAAwC,EAAxC,CAAb;AACA,QAAI,CAACH,KAAKI,QAAL,CAAc,OAAd,CAAL,EAA6B,OAAOL,IAAP;AAC7B,UAAMM,gBAAgBJ,iBAAEC,GAAF,CAAMH,KAAKI,MAAX,EAAmB,cAAnB,CAAtB;AACA,UAAMG,QAAQ,mCAASP,IAAT,CAAd;;AAEA;AACA,UAAMQ,WAAW,MAAMR,KAAKS,OAAL,CAAaC,IAAb,CAAkB;AACvCC,aAAO,EAAEV,MAAM,EAAEW,KAAK,CAAC,SAAD,EAAY,UAAZ,CAAP,EAAR,EAA0CC,QAAQP,cAAcQ,IAAhE,EADgC;AAEvCC,gBAAU;AAF6B,KAAlB,CAAvB;AAIA;AACA,QAAIP,SAASQ,MAAT,KAAoB,CAAxB,EAA2B;AACzBC,YAAO,qEAAoEV,MAAMO,IAAK,GAAtF;AACA,aAAOd,IAAP;AACD;AACD;AACA,UAAMkB,QAAQC,GAAR,CAAYX,SAASY,GAAT,CAAa,mBAAW;AACxC;AACA,UAAIP,SAASQ,QAAQR,MAArB;AACA,UAAIb,KAAKsB,MAAL,KAAgB,QAApB,EAA8B;AAC5BpB,yBAAEqB,MAAF,CAASV,MAAT,EAAiB;AAAA,iBAAaW,cAAclB,cAAcQ,IAAzC;AAAA,SAAjB;AACD,OAFD,MAEO;AACLD,iBAASA,OAAOO,GAAP,CAAW;AAAA,iBAAcI,cAAclB,cAAcQ,IAA5B,GAAmCP,MAAMO,IAAzC,GAAgDU,SAA9D;AAAA,SAAX,CAAT;AACD;AACD,aAAOxB,KAAKS,OAAL,CAAagB,KAAb,CAAmBJ,QAAQK,GAA3B,EAAgC,EAAEb,MAAF,EAAhC,CAAP;AACD,KATiB,CAAZ,CAAN;;AAWAI,UAAO,WAAUT,SAASQ,MAAO,6DAA4DT,MAAMO,IAAK,GAAxG;AACA,WAAOd,IAAP;AACD,G;;kBA/BqB2B,qB;;;;;QAPNC,Y,GAAAA,Y;;AAPhB;;;;AACA;;AACA;;;;;;;;AAEA,MAAMX,QAAQ,qBAAU,uBAAV,CAAd;;AAEA;AACO,SAASW,YAAT,CAAuB5B,IAAvB,EAA6B;AAClC,QAAMW,QAAQT,iBAAEC,GAAF,CAAMH,IAAN,EAAY,cAAZ,EAA4B,EAA5B,CAAd;AACA,MAAI,CAACW,MAAMV,IAAX,EAAiBU,MAAMV,IAAN,GAAa,EAAE4B,MAAM,CAAC,SAAD,EAAY,SAAZ,EAAuB,UAAvB,CAAR,EAAb;AACjB3B,mBAAE4B,GAAF,CAAM9B,IAAN,EAAY,cAAZ,EAA4BW,KAA5B;AACD","file":"hooks.catalog.js","sourcesContent":["import _ from 'lodash'\r\nimport { getItems } from 'feathers-hooks-common'\r\nimport makeDebug from 'debug'\r\n\r\nconst debug = makeDebug('kdk:map:catalog:hooks')\r\n\r\n// By default we only return layers and not other objects in catalog\r\nexport function filterLayers (hook) {\r\n const query = _.get(hook, 'params.query', {})\r\n if (!query.type) query.type = { $nin: ['Context', 'Service', 'Category'] }\r\n _.set(hook, 'params.query', query)\r\n}\r\n\r\n// Update layer name in all contexts, categories, etc. when renamed/removed\r\nexport async function updateLayerReferences (hook) {\r\n // Check if it's a layer renaming first\r\n const type = _.get(hook.params, 'previousItem.type', '')\r\n if (!type.endsWith('Layer')) return hook\r\n const previousLayer = _.get(hook.params, 'previousItem')\r\n const layer = getItems(hook)\r\n\r\n // Retrieve the list of all contexts, categories, etc. involving the layer\r\n const contexts = await hook.service.find({\r\n query: { type: { $in: ['Context', 'Category'] }, layers: previousLayer.name },\r\n paginate: false\r\n })\r\n // Stop when non found\r\n if (contexts.length === 0) {\r\n debug(`No context or category to update after renaming or removing layer ${layer.name} `)\r\n return hook\r\n }\r\n // Update each context otherwise\r\n await Promise.all(contexts.map(context => {\r\n // Update/Remove layer name in layer list\r\n let layers = context.layers\r\n if (hook.method === 'remove') {\r\n _.remove(layers, layerName => layerName === previousLayer.name)\r\n } else {\r\n layers = layers.map(layerName => (layerName === previousLayer.name ? layer.name : layerName))\r\n }\r\n return hook.service.patch(context._id, { layers })\r\n }))\r\n\r\n debug(`Updated ${contexts.length} contexts and categories after renaming or removing layer ${layer.name} `)\r\n return hook\r\n}\r\n"]}
1
+ {"version":3,"sources":["../../../../map/api/hooks/hooks.catalog.js"],"names":["hook","type","_","get","params","endsWith","previousLayer","layer","contexts","service","find","query","$in","layers","name","paginate","length","debug","Promise","all","map","context","method","remove","layerName","patch","_id","updateLayerReferences","getDefaultCategories","filterLayers","catalog","app","defaultCategories","categories","category","Object","assign","filter","omit","item","concat","$nin","set"],"mappings":"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","file":"hooks.catalog.js","sourcesContent":["import _ from 'lodash'\r\nimport sift from 'sift'\r\nimport { getItems, replaceItems } from 'feathers-hooks-common'\r\nimport makeDebug from 'debug'\r\n\r\nconst debug = makeDebug('kdk:map:catalog:hooks')\r\n\r\n// By default we only return layers and not other objects in catalog\r\nexport function getDefaultCategories (hook) {\r\n const query = _.get(hook, 'params.query', {})\r\n if (query.type === 'Category') {\r\n const catalog = hook.app.get('catalog')\r\n let defaultCategories = catalog ? catalog.categories || [] : []\r\n // Add implicit type\r\n defaultCategories = defaultCategories.map(category => Object.assign(category, { type: 'Category' }))\r\n // Then filter according to query\r\n defaultCategories = defaultCategories.filter(sift(_.omit(query, ['$sort', '$limit', '$skip'])))\r\n const item = getItems(hook)\r\n replaceItems(hook, item.concat(defaultCategories.map(category => Object.assign(category, { type: 'Category' }))))\r\n }\r\n}\r\n\r\n// By default we only return layers and not other objects in catalog\r\nexport function filterLayers (hook) {\r\n const query = _.get(hook, 'params.query', {})\r\n if (!query.type) query.type = { $nin: ['Context', 'Service', 'Category'] }\r\n _.set(hook, 'params.query', query)\r\n}\r\n\r\n// Update layer name in all contexts, categories, etc. when renamed/removed\r\nexport async function updateLayerReferences (hook) {\r\n // Check if it's a layer renaming first\r\n const type = _.get(hook.params, 'previousItem.type', '')\r\n if (!type.endsWith('Layer')) return hook\r\n const previousLayer = _.get(hook.params, 'previousItem')\r\n const layer = getItems(hook)\r\n\r\n // Retrieve the list of all contexts, categories, etc. involving the layer\r\n const contexts = await hook.service.find({\r\n query: { type: { $in: ['Context', 'Category'] }, layers: previousLayer.name },\r\n paginate: false\r\n })\r\n // Stop when non found\r\n if (contexts.length === 0) {\r\n debug(`No context or category to update after renaming or removing layer ${layer.name} `)\r\n return hook\r\n }\r\n // Update each context otherwise\r\n await Promise.all(contexts.map(context => {\r\n // Update/Remove layer name in layer list\r\n let layers = context.layers\r\n if (hook.method === 'remove') {\r\n _.remove(layers, layerName => layerName === previousLayer.name)\r\n } else {\r\n layers = layers.map(layerName => (layerName === previousLayer.name ? layer.name : layerName))\r\n }\r\n return hook.service.patch(context._id, { layers })\r\n }))\r\n\r\n debug(`Updated ${contexts.length} contexts and categories after renaming or removing layer ${layer.name} `)\r\n return hook\r\n}\r\n"]}
@@ -7,6 +7,11 @@ module.exports = function (app, options) {
7
7
  // different object types stored and we'd like a unique constraint per type
8
8
  options.Model.indexExists('name_1').then(() => options.Model.dropIndex('name_1')).catch(() => {});
9
9
  options.Model.indexExists('type_1').then(() => options.Model.dropIndex('type_1')).catch(() => {});
10
- options.Model.createIndex({ name: 1, type: 1 }, { unique: true });
10
+ // We also previously not take collation into account
11
+ options.Model.indexExists('name_1_type_1').then(() => options.Model.dropIndex('name_1_type_1')).catch(() => {});
12
+ // Collation provided in query ensure sorting to be case insensitive w.r.t. user's language
13
+ // We built indices with collation to cover the most used languages, it requires different naming...
14
+ options.Model.createIndex({ name: 1, type: 1 }, { unique: true, name: 'name-type-en', collation: { locale: 'en', strength: 1 } });
15
+ options.Model.createIndex({ name: 1, type: 1 }, { unique: true, name: 'name-type-fr', collation: { locale: 'fr', strength: 1 } });
11
16
  };
12
17
  //# sourceMappingURL=catalog.model.mongodb.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../map/api/models/catalog.model.mongodb.js"],"names":["module","exports","app","options","db","Model","collection","indexExists","then","dropIndex","catch","createIndex","name","type","unique"],"mappings":";;AAAAA,OAAOC,OAAP,GAAiB,UAAUC,GAAV,EAAeC,OAAf,EAAwB;AACvC,QAAMC,KAAKD,QAAQC,EAAR,IAAcF,IAAIE,EAA7B;AACAD,UAAQE,KAAR,GAAgBD,GAAGE,UAAH,CAAc,SAAd,CAAhB;AACA;AACA;AACAH,UAAQE,KAAR,CAAcE,WAAd,CAA0B,QAA1B,EAAoCC,IAApC,CAAyC,MAAML,QAAQE,KAAR,CAAcI,SAAd,CAAwB,QAAxB,CAA/C,EAAkFC,KAAlF,CAAwF,MAAM,CAAE,CAAhG;AACAP,UAAQE,KAAR,CAAcE,WAAd,CAA0B,QAA1B,EAAoCC,IAApC,CAAyC,MAAML,QAAQE,KAAR,CAAcI,SAAd,CAAwB,QAAxB,CAA/C,EAAkFC,KAAlF,CAAwF,MAAM,CAAE,CAAhG;AACAP,UAAQE,KAAR,CAAcM,WAAd,CAA0B,EAAEC,MAAM,CAAR,EAAWC,MAAM,CAAjB,EAA1B,EAAgD,EAAEC,QAAQ,IAAV,EAAhD;AACD,CARD","file":"catalog.model.mongodb.js","sourcesContent":["module.exports = function (app, options) {\r\n const db = options.db || app.db\r\n options.Model = db.collection('catalog')\r\n // We previously had a unique constraint on name but we now have\r\n // different object types stored and we'd like a unique constraint per type\r\n options.Model.indexExists('name_1').then(() => options.Model.dropIndex('name_1')).catch(() => {})\r\n options.Model.indexExists('type_1').then(() => options.Model.dropIndex('type_1')).catch(() => {})\r\n options.Model.createIndex({ name: 1, type: 1 }, { unique: true })\r\n}\r\n"]}
1
+ {"version":3,"sources":["../../../../map/api/models/catalog.model.mongodb.js"],"names":["module","exports","app","options","db","Model","collection","indexExists","then","dropIndex","catch","createIndex","name","type","unique","collation","locale","strength"],"mappings":";;AAAAA,OAAOC,OAAP,GAAiB,UAAUC,GAAV,EAAeC,OAAf,EAAwB;AACvC,QAAMC,KAAKD,QAAQC,EAAR,IAAcF,IAAIE,EAA7B;AACAD,UAAQE,KAAR,GAAgBD,GAAGE,UAAH,CAAc,SAAd,CAAhB;AACA;AACA;AACAH,UAAQE,KAAR,CAAcE,WAAd,CAA0B,QAA1B,EAAoCC,IAApC,CAAyC,MAAML,QAAQE,KAAR,CAAcI,SAAd,CAAwB,QAAxB,CAA/C,EAAkFC,KAAlF,CAAwF,MAAM,CAAE,CAAhG;AACAP,UAAQE,KAAR,CAAcE,WAAd,CAA0B,QAA1B,EAAoCC,IAApC,CAAyC,MAAML,QAAQE,KAAR,CAAcI,SAAd,CAAwB,QAAxB,CAA/C,EAAkFC,KAAlF,CAAwF,MAAM,CAAE,CAAhG;AACA;AACAP,UAAQE,KAAR,CAAcE,WAAd,CAA0B,eAA1B,EAA2CC,IAA3C,CAAgD,MAAML,QAAQE,KAAR,CAAcI,SAAd,CAAwB,eAAxB,CAAtD,EAAgGC,KAAhG,CAAsG,MAAM,CAAE,CAA9G;AACA;AACA;AACAP,UAAQE,KAAR,CAAcM,WAAd,CAA0B,EAAEC,MAAM,CAAR,EAAWC,MAAM,CAAjB,EAA1B,EAAgD,EAAEC,QAAQ,IAAV,EAAgBF,MAAM,cAAtB,EAAsCG,WAAW,EAAEC,QAAQ,IAAV,EAAgBC,UAAU,CAA1B,EAAjD,EAAhD;AACAd,UAAQE,KAAR,CAAcM,WAAd,CAA0B,EAAEC,MAAM,CAAR,EAAWC,MAAM,CAAjB,EAA1B,EAAgD,EAAEC,QAAQ,IAAV,EAAgBF,MAAM,cAAtB,EAAsCG,WAAW,EAAEC,QAAQ,IAAV,EAAgBC,UAAU,CAA1B,EAAjD,EAAhD;AACD,CAbD","file":"catalog.model.mongodb.js","sourcesContent":["module.exports = function (app, options) {\r\n const db = options.db || app.db\r\n options.Model = db.collection('catalog')\r\n // We previously had a unique constraint on name but we now have\r\n // different object types stored and we'd like a unique constraint per type\r\n options.Model.indexExists('name_1').then(() => options.Model.dropIndex('name_1')).catch(() => {})\r\n options.Model.indexExists('type_1').then(() => options.Model.dropIndex('type_1')).catch(() => {})\r\n // We also previously not take collation into account\r\n options.Model.indexExists('name_1_type_1').then(() => options.Model.dropIndex('name_1_type_1')).catch(() => {})\r\n // Collation provided in query ensure sorting to be case insensitive w.r.t. user's language\r\n // We built indices with collation to cover the most used languages, it requires different naming...\r\n options.Model.createIndex({ name: 1, type: 1 }, { unique: true, name: 'name-type-en', collation: { locale: 'en', strength: 1 } })\r\n options.Model.createIndex({ name: 1, type: 1 }, { unique: true, name: 'name-type-fr', collation: { locale: 'fr', strength: 1 } })\r\n}\r\n"]}
@@ -8,6 +8,11 @@ module.exports = function (app, options) {
8
8
  if (options.featureId) {
9
9
  options.Model.createIndex({ ['properties.' + options.featureId]: 1 });
10
10
  }
11
+ try {
12
+ options.Model.createIndex({ 'properties.$**': 1 });
13
+ } catch (_) {
14
+ // Fail silently as it might not be supported under v4
15
+ }
11
16
  if (options.expireAfter || options.ttl) {
12
17
  options.Model.createIndex({ time: 1 }, { expireAfterSeconds: options.expireAfter || options.ttl });
13
18
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../map/api/models/features.model.mongodb.js"],"names":["module","exports","app","options","db","Model","collection","createIndex","geometry","layer","featureId","expireAfter","ttl","time","expireAfterSeconds"],"mappings":";;AAAAA,OAAOC,OAAP,GAAiB,UAAUC,GAAV,EAAeC,OAAf,EAAwB;AACvC,QAAMC,KAAKD,QAAQC,EAAR,IAAcF,IAAIE,EAA7B;AACAD,UAAQE,KAAR,GAAgBD,GAAGE,UAAH,CAAcH,QAAQG,UAAtB,CAAhB;AACAH,UAAQE,KAAR,CAAcE,WAAd,CAA0B,EAAEC,UAAU,UAAZ,EAA1B;AACAL,UAAQE,KAAR,CAAcE,WAAd,CAA0B,EAAEE,OAAO,CAAT,EAA1B;AACA,MAAIN,QAAQO,SAAZ,EAAuB;AACrBP,YAAQE,KAAR,CAAcE,WAAd,CAA0B,EAAE,CAAC,gBAAgBJ,QAAQO,SAAzB,GAAqC,CAAvC,EAA1B;AACD;AACD,MAAIP,QAAQQ,WAAR,IAAuBR,QAAQS,GAAnC,EAAwC;AACtCT,YAAQE,KAAR,CAAcE,WAAd,CAA0B,EAAEM,MAAM,CAAR,EAA1B,EAAuC,EAAEC,oBAAoBX,QAAQQ,WAAR,IAAuBR,QAAQS,GAArD,EAAvC;AACD;AACF,CAXD","file":"features.model.mongodb.js","sourcesContent":["module.exports = function (app, options) {\r\n const db = options.db || app.db\r\n options.Model = db.collection(options.collection)\r\n options.Model.createIndex({ geometry: '2dsphere' })\r\n options.Model.createIndex({ layer: 1 })\r\n if (options.featureId) {\r\n options.Model.createIndex({ ['properties.' + options.featureId]: 1 })\r\n }\r\n if (options.expireAfter || options.ttl) {\r\n options.Model.createIndex({ time: 1 }, { expireAfterSeconds: options.expireAfter || options.ttl })\r\n }\r\n}\r\n"]}
1
+ {"version":3,"sources":["../../../../map/api/models/features.model.mongodb.js"],"names":["module","exports","app","options","db","Model","collection","createIndex","geometry","layer","featureId","_","expireAfter","ttl","time","expireAfterSeconds"],"mappings":";;AAAAA,OAAOC,OAAP,GAAiB,UAAUC,GAAV,EAAeC,OAAf,EAAwB;AACvC,QAAMC,KAAKD,QAAQC,EAAR,IAAcF,IAAIE,EAA7B;AACAD,UAAQE,KAAR,GAAgBD,GAAGE,UAAH,CAAcH,QAAQG,UAAtB,CAAhB;AACAH,UAAQE,KAAR,CAAcE,WAAd,CAA0B,EAAEC,UAAU,UAAZ,EAA1B;AACAL,UAAQE,KAAR,CAAcE,WAAd,CAA0B,EAAEE,OAAO,CAAT,EAA1B;AACA,MAAIN,QAAQO,SAAZ,EAAuB;AACrBP,YAAQE,KAAR,CAAcE,WAAd,CAA0B,EAAE,CAAC,gBAAgBJ,QAAQO,SAAzB,GAAqC,CAAvC,EAA1B;AACD;AACD,MAAI;AACFP,YAAQE,KAAR,CAAcE,WAAd,CAA0B,EAAE,kBAAkB,CAApB,EAA1B;AACD,GAFD,CAEE,OAAOI,CAAP,EAAU;AACV;AACD;AACD,MAAIR,QAAQS,WAAR,IAAuBT,QAAQU,GAAnC,EAAwC;AACtCV,YAAQE,KAAR,CAAcE,WAAd,CAA0B,EAAEO,MAAM,CAAR,EAA1B,EAAuC,EAAEC,oBAAoBZ,QAAQS,WAAR,IAAuBT,QAAQU,GAArD,EAAvC;AACD;AACF,CAhBD","file":"features.model.mongodb.js","sourcesContent":["module.exports = function (app, options) {\r\n const db = options.db || app.db\r\n options.Model = db.collection(options.collection)\r\n options.Model.createIndex({ geometry: '2dsphere' })\r\n options.Model.createIndex({ layer: 1 })\r\n if (options.featureId) {\r\n options.Model.createIndex({ ['properties.' + options.featureId]: 1 })\r\n }\r\n try {\r\n options.Model.createIndex({ 'properties.$**': 1 })\r\n } catch (_) {\r\n // Fail silently as it might not be supported under v4\r\n }\r\n if (options.expireAfter || options.ttl) {\r\n options.Model.createIndex({ time: 1 }, { expireAfterSeconds: options.expireAfter || options.ttl })\r\n }\r\n}\r\n"]}
@@ -31,7 +31,9 @@ module.exports = {
31
31
 
32
32
  after: {
33
33
  all: [_api.hooks.convertToJson(['schema.content'])],
34
- find: [],
34
+ find: [
35
+ // Merge built-in categories with user-defined ones
36
+ _hooks.getDefaultCategories],
35
37
  get: [],
36
38
  create: [],
37
39
  update: [_hooks.updateLayerReferences],
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../map/api/services/catalog/catalog.hooks.js"],"names":["module","exports","before","all","find","filterLayers","get","create","coreHooks","checkUnique","field","query","hook","type","_","convertObjectIDs","convertToString","update","populatePreviousObject","patch","remove","after","convertToJson","updateLayerReferences","error"],"mappings":";;AAAA;;;;AACA;;AACA;;AACA;;;;AAEAA,OAAOC,OAAP,GAAiB;AACfC,UAAQ;AACNC,SAAK,EADC;AAENC,UAAM,CACJC,mBADI,CAFA;AAKNC,SAAK,EALC;AAMNC,YAAQ,CACNC,WAAUC,WAAV,CAAsB,EAAEC,OAAO,MAAT,EAAiBC,OAAO,CAACA,KAAD,EAAQC,IAAR,KAAiB;AAAED,cAAME,IAAN,GAAaC,iBAAER,GAAF,CAAMM,IAAN,EAAY,WAAZ,CAAb;AAAuC,OAAlF,EAAtB,CADM,EAENJ,WAAUO,gBAAV,CAA2B,CAAC,iBAAD,CAA3B,CAFM,EAGNP,WAAUQ,eAAV,CAA0B,CAAC,gBAAD,CAA1B,CAHM,EAIN,iCAAO,WAAP,EAAoB,WAApB,CAJM,CANF;AAYNC,YAAQ,CACNT,WAAUU,sBADJ,EAENV,WAAUC,WAAV,CAAsB,EAAEC,OAAO,MAAT,EAAiBC,OAAO,CAACA,KAAD,EAAQC,IAAR,KAAiB;AAAED,cAAME,IAAN,GAAaC,iBAAER,GAAF,CAAMM,IAAN,EAAY,0BAAZ,CAAb;AAAsD,OAAjG,EAAtB,CAFM,EAGNJ,WAAUO,gBAAV,CAA2B,CAAC,iBAAD,CAA3B,CAHM,EAINP,WAAUQ,eAAV,CAA0B,CAAC,gBAAD,CAA1B,CAJM,EAKN,kCAAQ,WAAR,EAAqB,WAArB,CALM,EAMN,iCAAO,WAAP,CANM,CAZF;AAoBNG,WAAO,CACLX,WAAUU,sBADL,EAELV,WAAUC,WAAV,CAAsB,EAAEC,OAAO,MAAT,EAAiBC,OAAO,CAACA,KAAD,EAAQC,IAAR,KAAiB;AAAED,cAAME,IAAN,GAAaC,iBAAER,GAAF,CAAMM,IAAN,EAAY,0BAAZ,CAAb;AAAsD,OAAjG,EAAtB,CAFK,EAGLJ,WAAUO,gBAAV,CAA2B,CAAC,iBAAD,CAA3B,CAHK,EAILP,WAAUQ,eAAV,CAA0B,CAAC,gBAAD,CAA1B,CAJK,EAKL,kCAAQ,WAAR,EAAqB,WAArB,CALK,EAML,iCAAO,WAAP,CANK,CApBD;AA4BNI,YAAQ,CACNZ,WAAUU,sBADJ;AA5BF,GADO;;AAkCfG,SAAO;AACLlB,SAAK,CACHK,WAAUc,aAAV,CAAwB,CAAC,gBAAD,CAAxB,CADG,CADA;AAILlB,UAAM,EAJD;AAKLE,SAAK,EALA;AAMLC,YAAQ,EANH;AAOLU,YAAQ,CACNM,4BADM,CAPH;AAULJ,WAAO,CACLI,4BADK,CAVF;AAaLH,YAAQ,CACN,iCAAO,WAAP,CADM,EAENG,4BAFM;AAbH,GAlCQ;;AAqDfC,SAAO;AACLrB,SAAK,EADA;AAELC,UAAM,EAFD;AAGLE,SAAK,EAHA;AAILC,YAAQ,EAJH;AAKLU,YAAQ,EALH;AAMLE,WAAO,EANF;AAOLC,YAAQ;AAPH;AArDQ,CAAjB","file":"catalog.hooks.js","sourcesContent":["import _ from 'lodash'\r\nimport { setNow, discard } from 'feathers-hooks-common'\r\nimport { hooks as coreHooks } from '../../../../core/api'\r\nimport { filterLayers, updateLayerReferences } from '../../hooks'\r\n\r\nmodule.exports = {\r\n before: {\r\n all: [],\r\n find: [\r\n filterLayers\r\n ],\r\n get: [],\r\n create: [\r\n coreHooks.checkUnique({ field: 'name', query: (query, hook) => { query.type = _.get(hook, 'data.type') } }),\r\n coreHooks.convertObjectIDs(['baseQuery.layer']),\r\n coreHooks.convertToString(['schema.content']),\r\n setNow('createdAt', 'updatedAt')\r\n ],\r\n update: [\r\n coreHooks.populatePreviousObject,\r\n coreHooks.checkUnique({ field: 'name', query: (query, hook) => { query.type = _.get(hook, 'params.previousItem.type') } }),\r\n coreHooks.convertObjectIDs(['baseQuery.layer']),\r\n coreHooks.convertToString(['schema.content']),\r\n discard('createdAt', 'updatedAt'),\r\n setNow('updatedAt')\r\n ],\r\n patch: [\r\n coreHooks.populatePreviousObject,\r\n coreHooks.checkUnique({ field: 'name', query: (query, hook) => { query.type = _.get(hook, 'params.previousItem.type') } }),\r\n coreHooks.convertObjectIDs(['baseQuery.layer']),\r\n coreHooks.convertToString(['schema.content']),\r\n discard('createdAt', 'updatedAt'),\r\n setNow('updatedAt')\r\n ],\r\n remove: [\r\n coreHooks.populatePreviousObject\r\n ]\r\n },\r\n\r\n after: {\r\n all: [\r\n coreHooks.convertToJson(['schema.content'])\r\n ],\r\n find: [],\r\n get: [],\r\n create: [],\r\n update: [\r\n updateLayerReferences\r\n ],\r\n patch: [\r\n updateLayerReferences\r\n ],\r\n remove: [\r\n setNow('updatedAt'),\r\n updateLayerReferences\r\n ]\r\n },\r\n\r\n error: {\r\n all: [],\r\n find: [],\r\n get: [],\r\n create: [],\r\n update: [],\r\n patch: [],\r\n remove: []\r\n }\r\n}\r\n"]}
1
+ {"version":3,"sources":["../../../../../map/api/services/catalog/catalog.hooks.js"],"names":["module","exports","before","all","find","filterLayers","get","create","coreHooks","checkUnique","field","query","hook","type","_","convertObjectIDs","convertToString","update","populatePreviousObject","patch","remove","after","convertToJson","getDefaultCategories","updateLayerReferences","error"],"mappings":";;AAAA;;;;AACA;;AACA;;AACA;;;;AAEAA,OAAOC,OAAP,GAAiB;AACfC,UAAQ;AACNC,SAAK,EADC;AAENC,UAAM,CACJC,mBADI,CAFA;AAKNC,SAAK,EALC;AAMNC,YAAQ,CACNC,WAAUC,WAAV,CAAsB,EAAEC,OAAO,MAAT,EAAiBC,OAAO,CAACA,KAAD,EAAQC,IAAR,KAAiB;AAAED,cAAME,IAAN,GAAaC,iBAAER,GAAF,CAAMM,IAAN,EAAY,WAAZ,CAAb;AAAuC,OAAlF,EAAtB,CADM,EAENJ,WAAUO,gBAAV,CAA2B,CAAC,iBAAD,CAA3B,CAFM,EAGNP,WAAUQ,eAAV,CAA0B,CAAC,gBAAD,CAA1B,CAHM,EAIN,iCAAO,WAAP,EAAoB,WAApB,CAJM,CANF;AAYNC,YAAQ,CACNT,WAAUU,sBADJ,EAENV,WAAUC,WAAV,CAAsB,EAAEC,OAAO,MAAT,EAAiBC,OAAO,CAACA,KAAD,EAAQC,IAAR,KAAiB;AAAED,cAAME,IAAN,GAAaC,iBAAER,GAAF,CAAMM,IAAN,EAAY,0BAAZ,CAAb;AAAsD,OAAjG,EAAtB,CAFM,EAGNJ,WAAUO,gBAAV,CAA2B,CAAC,iBAAD,CAA3B,CAHM,EAINP,WAAUQ,eAAV,CAA0B,CAAC,gBAAD,CAA1B,CAJM,EAKN,kCAAQ,WAAR,EAAqB,WAArB,CALM,EAMN,iCAAO,WAAP,CANM,CAZF;AAoBNG,WAAO,CACLX,WAAUU,sBADL,EAELV,WAAUC,WAAV,CAAsB,EAAEC,OAAO,MAAT,EAAiBC,OAAO,CAACA,KAAD,EAAQC,IAAR,KAAiB;AAAED,cAAME,IAAN,GAAaC,iBAAER,GAAF,CAAMM,IAAN,EAAY,0BAAZ,CAAb;AAAsD,OAAjG,EAAtB,CAFK,EAGLJ,WAAUO,gBAAV,CAA2B,CAAC,iBAAD,CAA3B,CAHK,EAILP,WAAUQ,eAAV,CAA0B,CAAC,gBAAD,CAA1B,CAJK,EAKL,kCAAQ,WAAR,EAAqB,WAArB,CALK,EAML,iCAAO,WAAP,CANK,CApBD;AA4BNI,YAAQ,CACNZ,WAAUU,sBADJ;AA5BF,GADO;;AAkCfG,SAAO;AACLlB,SAAK,CACHK,WAAUc,aAAV,CAAwB,CAAC,gBAAD,CAAxB,CADG,CADA;AAILlB,UAAM;AACJ;AACAmB,+BAFI,CAJD;AAQLjB,SAAK,EARA;AASLC,YAAQ,EATH;AAULU,YAAQ,CACNO,4BADM,CAVH;AAaLL,WAAO,CACLK,4BADK,CAbF;AAgBLJ,YAAQ,CACN,iCAAO,WAAP,CADM,EAENI,4BAFM;AAhBH,GAlCQ;;AAwDfC,SAAO;AACLtB,SAAK,EADA;AAELC,UAAM,EAFD;AAGLE,SAAK,EAHA;AAILC,YAAQ,EAJH;AAKLU,YAAQ,EALH;AAMLE,WAAO,EANF;AAOLC,YAAQ;AAPH;AAxDQ,CAAjB","file":"catalog.hooks.js","sourcesContent":["import _ from 'lodash'\r\nimport { setNow, discard } from 'feathers-hooks-common'\r\nimport { hooks as coreHooks } from '../../../../core/api'\r\nimport { filterLayers, updateLayerReferences, getDefaultCategories } from '../../hooks'\r\n\r\nmodule.exports = {\r\n before: {\r\n all: [],\r\n find: [\r\n filterLayers\r\n ],\r\n get: [],\r\n create: [\r\n coreHooks.checkUnique({ field: 'name', query: (query, hook) => { query.type = _.get(hook, 'data.type') } }),\r\n coreHooks.convertObjectIDs(['baseQuery.layer']),\r\n coreHooks.convertToString(['schema.content']),\r\n setNow('createdAt', 'updatedAt')\r\n ],\r\n update: [\r\n coreHooks.populatePreviousObject,\r\n coreHooks.checkUnique({ field: 'name', query: (query, hook) => { query.type = _.get(hook, 'params.previousItem.type') } }),\r\n coreHooks.convertObjectIDs(['baseQuery.layer']),\r\n coreHooks.convertToString(['schema.content']),\r\n discard('createdAt', 'updatedAt'),\r\n setNow('updatedAt')\r\n ],\r\n patch: [\r\n coreHooks.populatePreviousObject,\r\n coreHooks.checkUnique({ field: 'name', query: (query, hook) => { query.type = _.get(hook, 'params.previousItem.type') } }),\r\n coreHooks.convertObjectIDs(['baseQuery.layer']),\r\n coreHooks.convertToString(['schema.content']),\r\n discard('createdAt', 'updatedAt'),\r\n setNow('updatedAt')\r\n ],\r\n remove: [\r\n coreHooks.populatePreviousObject\r\n ]\r\n },\r\n\r\n after: {\r\n all: [\r\n coreHooks.convertToJson(['schema.content'])\r\n ],\r\n find: [\r\n // Merge built-in categories with user-defined ones\r\n getDefaultCategories\r\n ],\r\n get: [],\r\n create: [],\r\n update: [\r\n updateLayerReferences\r\n ],\r\n patch: [\r\n updateLayerReferences\r\n ],\r\n remove: [\r\n setNow('updatedAt'),\r\n updateLayerReferences\r\n ]\r\n },\r\n\r\n error: {\r\n all: [],\r\n find: [],\r\n get: [],\r\n create: [],\r\n update: [],\r\n patch: [],\r\n remove: []\r\n }\r\n}\r\n"]}
@@ -323,26 +323,27 @@ export default {
323
323
  }
324
324
  </script>
325
325
 
326
- <style lang="stylus">
327
- .k-legend
326
+ <style lang="scss">
327
+ .k-legend {
328
328
  position: relative;
329
- cursor: pointer;
330
- border: none
331
-
332
- .k-unit-box
333
- position: absolute;
334
- top: 0;
335
- display: flex;
336
- align-items: center;
337
- justify-content: center;
338
-
339
- .k-value-step
340
- position: absolute;
341
- display: flex;
342
- align-items: center;
343
- justify-content: center;
344
-
345
- .k-gradient-step
346
- position: absolute;
347
- display: inline-block;
329
+ cursor: pointer;
330
+ border: none;
331
+ }
332
+ .k-unit-box {
333
+ position: absolute;
334
+ top: 0;
335
+ display: flex;
336
+ align-items: center;
337
+ justify-content: center;
338
+ }
339
+ .k-value-step {
340
+ position: absolute;
341
+ display: flex;
342
+ align-items: center;
343
+ justify-content: center;
344
+ }
345
+ .k-gradient-step {
346
+ position: absolute;
347
+ display: inline-block;
348
+ }
348
349
  </style>
@@ -10,14 +10,21 @@
10
10
  @opened="$emit('opened')"
11
11
  @closed="$emit('closed')"
12
12
  >
13
- <div class="row justify-center text-center q-ma-none q-pa-none">
14
- <div style="width: 90vw">
15
- <canvas v-show="chartData.length > 0" class="chart" ref="chart"></canvas>
16
- </div>
17
- <q-btn v-show="currentChart > 1" size="1rem" flat round color="primary"
18
- icon="las la-chevron-left" class="absolute-left" @click="onPreviousChart"/>
19
- <q-btn v-show="currentChart < nbCharts" size="1rem" flat round color="primary"
20
- icon="las la-chevron-right" class="absolute-right" @click="onNextChart" />
13
+ <div class="row justify-around items-center q-ma-none q-pa-none">
14
+ <!-- Previsious chart -->
15
+ <q-btn
16
+ v-show="currentChart > 1"
17
+ size="1rem" flat round color="primary"
18
+ icon="las la-chevron-left"
19
+ @click="onPreviousChart"/>
20
+ <!-- Current chart --->
21
+ <k-stats-chart ref="chart" :style="chartStyle" />
22
+ <!-- Netx chart -->
23
+ <q-btn
24
+ v-show="currentChart < nbCharts"
25
+ size="1rem" flat round color="primary"
26
+ icon="las la-chevron-right"
27
+ @click="onNextChart" />
21
28
  </div>
22
29
  </k-modal>
23
30
  <k-modal
@@ -26,14 +33,29 @@
26
33
  :title="$t('KFeaturesChart.CHART_SETTINGS_LABEL')"
27
34
  :buttons="[{ id: 'close-action', label: 'CLOSE', renderer: 'form-button', handler: () => this.$refs.chartSettings.close() }]">
28
35
  <div>
29
- <q-select v-model="property" :label="$t('KFeaturesChart.PROPERTY_LABEL')"
30
- :options="properties" @input="refreshChart"/>
31
- <q-select v-model="chartType" :label="$t('KFeaturesChart.CHART_LABEL')"
32
- :options="chartOptions" @input="refreshChart"/>
33
- <q-select v-model="nbValuesPerChart" :label="$t('KFeaturesChart.PAGINATION_LABEL')"
34
- :options="paginationOptions" @input="refreshChartAndPagination"/>
35
- <q-select v-model="render" :label="$t('KFeaturesChart.RENDER_LABEL')"
36
- :options="renderOptions" @input="refreshChart"/>
36
+ <q-select
37
+ v-model="selectedProperty"
38
+ :label="$t('KFeaturesChart.PROPERTY_LABEL')"
39
+ :options="properties"
40
+ @input="refreshChart"/>
41
+ <q-select
42
+ :disable="selectedProperty ? false: true"
43
+ v-model="selectedChartType"
44
+ :label="$t('KFeaturesChart.CHART_LABEL')"
45
+ :options="availableChartTypes"
46
+ @input="refreshChart"/>
47
+ <q-select
48
+ :disable="selectedProperty ? false: true"
49
+ v-model="nbValuesPerChart"
50
+ :label="$t('KFeaturesChart.PAGINATION_LABEL')"
51
+ :options="paginationOptions"
52
+ @input="refreshChartAndPagination"/>
53
+ <!-- TODO q-select
54
+ :disable="selectedProperty ? false: true"
55
+ v-model="render"
56
+ :label="$t('KFeaturesChart.RENDER_LABEL')"
57
+ :options="renderOptions"
58
+ @input="refreshChart"/-->
37
59
  </div>
38
60
  </k-modal>
39
61
  </div>
@@ -44,9 +66,6 @@ import _ from 'lodash'
44
66
  import logger from 'loglevel'
45
67
  import Papa from 'papaparse'
46
68
  import { Loading } from 'quasar'
47
- import chroma from 'chroma-js'
48
- import Chart from 'chart.js'
49
- import 'chartjs-plugin-labels'
50
69
  import { mixins as kCoreMixins, utils as kCoreUtils } from '../../../core/client'
51
70
 
52
71
  export default {
@@ -79,14 +98,17 @@ export default {
79
98
  // if (properties.length) this.property = properties[0]
80
99
  return properties
81
100
  },
101
+ chartStyle () {
102
+ const min = Math.min(this.$q.screen.width, this.$q.screen.height)
103
+ return `maxWidth: ${min * 0.75}px;`
104
+ },
82
105
  nbCharts () {
83
106
  if (!this.chartData.length || (this.nbValuesPerChart.value === 0)) return 1
84
107
  else return Math.ceil(this.chartData.length / this.nbValuesPerChart.value)
85
108
  }
86
109
  },
87
110
  data () {
88
- const chartTypes = ['pie', 'polarArea', 'radar', 'bar']
89
- const chartOptions = chartTypes.map(
111
+ const availableChartTypes = ['pie', 'polarArea', 'radar', 'bar'].map(
90
112
  type => ({ value: type, label: this.$i18n.t(`KFeaturesChart.CHART_LABEL_${type.toUpperCase()}`) }))
91
113
  const paginationOptions = [{
92
114
  value: 0, label: this.$i18n.t('KFeaturesChart.ALL_VALUES')
@@ -102,7 +124,6 @@ export default {
102
124
  }, {
103
125
  value: 'percentage', label: this.$i18n.t('KFeaturesChart.PERCENTAGE_LABEL')
104
126
  }]
105
-
106
127
  return {
107
128
  toolbar: [
108
129
  { id: 'settings', icon: 'las la-cog', tooltip: 'KFeaturesChart.CHART_SETTINGS_LABEL', handler: () => this.$refs.chartSettings.open() },
@@ -111,15 +132,15 @@ export default {
111
132
  buttons: [
112
133
  { id: 'close-acation', label: 'CLOSE', renderer: 'form-button', handler: () => this.closeModal() }
113
134
  ],
114
- property: null,
115
- chartType: _.find(chartOptions, { value: 'pie' }),
116
- chartOptions,
135
+ selectedProperty: null,
136
+ availableChartTypes,
137
+ selectedChartType: _.find(availableChartTypes, { value: 'pie' }),
138
+ chartData: [],
117
139
  currentChart: 1,
118
140
  nbValuesPerChart: _.find(paginationOptions, { value: 10 }),
119
141
  paginationOptions,
120
142
  renderOptions,
121
- render: _.find(renderOptions, { value: 'value' }),
122
- chartData: []
143
+ render: _.find(renderOptions, { value: 'value' })
123
144
  }
124
145
  },
125
146
  methods: {
@@ -128,13 +149,13 @@ export default {
128
149
  },
129
150
  async getPropertyValues () {
130
151
  // For enumeration we directly get the values
131
- let values = _.get(this.layer, `schema.content.properties.${this.property.value}.field.options`)
152
+ let values = _.get(this.layer, `schema.content.properties.${this.selectedProperty.value}.field.options`)
132
153
  if (!values) {
133
154
  // Otherwise we need to make a DB query
134
155
  values = await this.$api.getService(this.layer.service, this.contextId)
135
- .find({ query: Object.assign({ $distinct: `properties.${this.property.value}` }, this.layer.baseQuery) })
156
+ .find({ query: Object.assign({ $distinct: `properties.${this.selectedProperty.value}` }, this.layer.baseQuery) })
136
157
  // We don't have label in that case
137
- values = values.map(value => ({ value, label: (value || this.$t('KFeaturesChart.NULL_VALUE_LABEL')) }))
158
+ values = _.map(values, value => ({ value, label: (value || this.$t('KFeaturesChart.NULL_VALUE_LABEL')) }))
138
159
  }
139
160
  return values
140
161
  },
@@ -142,9 +163,9 @@ export default {
142
163
  // Get possible values
143
164
  this.values = await this.getPropertyValues()
144
165
  // Then count features for each value
145
- let data = await Promise.all(this.values.map(async value => {
166
+ let data = await Promise.all(_.map(this.values, async value => {
146
167
  const response = await this.$api.getService(this.layer.service, this.contextId)
147
- .find({ query: Object.assign({ $limit: 0, [`properties.${this.property.value}`]: value.value }, this.layer.baseQuery) })
168
+ .find({ query: Object.assign({ $limit: 0, [`properties.${this.selectedProperty.value}`]: value.value }, this.layer.baseQuery) })
148
169
  return { value, count: response.total }
149
170
  }))
150
171
  // Sort data so that we don't have charts mixin large and small numbers when paginating, go large first
@@ -152,64 +173,6 @@ export default {
152
173
  this.values = data.map(item => item.value)
153
174
  this.chartData = data.map(item => item.count)
154
175
  },
155
- getChartOptions (type) {
156
- const start = (this.currentChart - 1) * this.nbValuesPerChart.value
157
- const end = (this.nbValuesPerChart.value > 0 ? start + this.nbValuesPerChart.value : this.chartData.length)
158
- const colors = _.shuffle(chroma.scale('Spectral').colors(end - start))
159
- // const title = this.property.label + ' - ' + this.$t(`KFeaturesChart.CHART_LABEL_${type.toUpperCase()}`)
160
- let title = this.property.label
161
- if (this.nbCharts > 1) title += ` (${this.currentChart}/${this.nbCharts})`
162
- const config = {
163
- type,
164
- data: {
165
- labels: this.values.map(value => value.label).slice(start, end),
166
- datasets: [{
167
- data: this.chartData.slice(start, end)
168
- }]
169
- },
170
- options: {
171
- responsive: true,
172
- title: {
173
- display: true,
174
- text: title
175
- }
176
- }
177
- }
178
- // ticks.precision = 0 means round displayed values to integers
179
- if (type === 'radar') {
180
- _.set(config, 'options.legend.display', false)
181
- _.set(config, 'data.datasets[0].fill', true)
182
- _.set(config, 'data.datasets[0].borderColor', colors[0])
183
- _.set(config, 'data.datasets[0].backgroundColor', chroma(colors[0]).alpha(0.5).hex())
184
- _.set(config, 'data.datasets[0].pointBorderColor', '#fff')
185
- _.set(config, 'data.datasets[0].pointBackgroundColor', colors[0])
186
- _.set(config, 'options.scale.ticks.beginAtZero', true)
187
- _.set(config, 'options.scale.ticks.precision', 0)
188
- } else {
189
- _.set(config, 'data.datasets[0].backgroundColor', colors)
190
- _.set(config, 'options.plugins.labels.render', this.render.value)
191
- _.set(config, 'options.plugins.labels.position', 'border')
192
- _.set(config, 'options.plugins.labels.overlap', false)
193
- _.set(config, 'options.plugins.labels.showActualPercentages', true)
194
- _.set(config, 'options.plugins.labels.precision', 0)
195
- _.set(config, 'options.plugins.labels.textShadow', true)
196
- _.set(config, 'options.plugins.labels.fontSize', 24)
197
- _.set(config, 'options.plugins.labels.fontColor', (type === 'bar' ? '#000' : '#fff'))
198
- }
199
- if (type === 'bar') {
200
- _.set(config, 'options.legend.display', false)
201
- _.set(config, 'options.scales.xAxes[0].ticks.maxRotation', 90)
202
- _.set(config, 'options.scales.xAxes[0].ticks.minRotation', 70)
203
- _.set(config, 'options.scales.yAxes[0].ticks.beginAtZero', true)
204
- _.set(config, 'options.scales.yAxes[0].ticks.precision', 0)
205
- // _.set(config, 'options.plugins.labels.fontSize', 0)
206
- } else if (type === 'polarArea') {
207
- // FIXME: does not work in this case
208
- // _.set(config, 'options.scale.display', false)
209
- }
210
-
211
- return config
212
- },
213
176
  async refreshChart () {
214
177
  // As we have async operations during the whole chart creation process avoid reentrance
215
178
  // otherwise we might have interleaved calls leading to multiple charts being created
@@ -218,14 +181,32 @@ export default {
218
181
  // Try/Catch required to ensure we reset the build flag
219
182
  try {
220
183
  this.buildingChart = true
221
- // Destroy previous graph if any
222
- if (this.chart) this.chart.destroy()
223
- // Retrieve data
184
+ // Retrieve chart data
224
185
  await this.getChartData()
225
- // We need to force a refresh so that the computed props are correctly updated by Vuejs
226
- await this.$nextTick()
227
- this.chart = new Chart(this.$refs.chart.getContext('2d'),
228
- this.getChartOptions(this.chartType.value))
186
+ // Update chart options
187
+ const start = (this.currentChart - 1) * this.nbValuesPerChart.value
188
+ const end = (this.nbValuesPerChart.value > 0 ? start + this.nbValuesPerChart.value : this.chartData.length)
189
+ let title = this.selectedProperty.label
190
+ if (this.nbCharts > 1) title += ` (${this.currentChart}/${this.nbCharts})`
191
+ // Update the chart
192
+ this.$refs.chart.update({
193
+ type: this.selectedChartType.value,
194
+ data: {
195
+ labels: _.map(this.values, value => value.label).slice(start, end),
196
+ datasets: [{
197
+ data: this.chartData.slice(start, end),
198
+ colorScale: 'Dark2'
199
+ }]
200
+ },
201
+ options: {
202
+ plugins: {
203
+ title: {
204
+ display: true,
205
+ text: title
206
+ }
207
+ }
208
+ }
209
+ })
229
210
  } catch (error) {
230
211
  // User error message on operation should be raised by error hook, otherwise this is more a coding error
231
212
  logger.error(error)
@@ -247,31 +228,21 @@ export default {
247
228
  },
248
229
  downloadChartData () {
249
230
  const json = this.values.map((value, index) => ({
250
- [this.property.label]: value.label,
231
+ [this.selectedProperty.label]: value.label,
251
232
  [this.$t('KFeaturesChart.CHART_COUNT_LABEL')]: this.chartData[index]
252
233
  }))
253
234
  const csv = Papa.unparse(json)
254
235
  kCoreUtils.downloadAsBlob(csv, this.$t('KFeaturesChart.CHART_EXPORT_FILE', { layer: this.layer.name }), 'text/csv;charset=utf-8;')
255
236
  }
256
237
  },
257
- created () {
238
+ beforeCreate () {
258
239
  // laod the required components
259
240
  this.$options.components['k-modal'] = this.$load('frame/KModal')
241
+ this.$options.components['k-stats-chart'] = this.$load('chart/KStatsChart')
260
242
  },
261
243
  async mounted () {
262
244
  await this.loadRefs()
263
245
  this.$refs.chartSettings.open()
264
- },
265
- beforeDestroy () {
266
- if (this.chart) this.chart.destroy()
267
246
  }
268
247
  }
269
248
  </script>
270
-
271
- <style lang="stylus">
272
- .chart {
273
- border: solid 1px lightgrey;
274
- border-radius: 8px;
275
- background: #ffffff
276
- }
277
- </style>