@collabdt/core 0.0.41 → 0.0.43

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 (265) hide show
  1. package/README.md +1 -1
  2. package/dist/core/components/Toolbar.d.ts.map +1 -1
  3. package/dist/core/components/Toolbar.js.map +1 -1
  4. package/dist/core/components/ToolbarBody.js.map +1 -1
  5. package/dist/core/components/TopNavigationBar.js.map +1 -1
  6. package/dist/core/components/authentication/ForgotPassword.js.map +1 -1
  7. package/dist/core/components/authentication/Signin.js.map +1 -1
  8. package/dist/core/components/authentication/Signup.js.map +1 -1
  9. package/dist/core/components/settings/src/OrganizationSkeleton.js.map +1 -1
  10. package/dist/core/components/settings/src/SettingsSkeleton.js.map +1 -1
  11. package/dist/core/components/ui/Comments/CollapsibleCommentItem.d.ts.map +1 -1
  12. package/dist/core/components/ui/Comments/CollapsibleCommentItem.js.map +1 -1
  13. package/dist/core/components/ui/Comments/CommentsSection.d.ts.map +1 -1
  14. package/dist/core/components/ui/Comments/CommentsSection.js.map +1 -1
  15. package/dist/core/components/ui/DataTable.d.ts.map +1 -1
  16. package/dist/core/components/ui/DataTable.js +7 -0
  17. package/dist/core/components/ui/DataTable.js.map +1 -1
  18. package/dist/core/components/ui/FilesManager/src/FileItemComponent.d.ts.map +1 -1
  19. package/dist/core/components/ui/FilesManager/src/FileItemComponent.js.map +1 -1
  20. package/dist/core/components/ui/FilesManager/src/FileMarker.d.ts +5 -2
  21. package/dist/core/components/ui/FilesManager/src/FileMarker.d.ts.map +1 -1
  22. package/dist/core/components/ui/FilesManager/src/FileMarker.js +84 -21
  23. package/dist/core/components/ui/FilesManager/src/FileMarker.js.map +1 -1
  24. package/dist/core/components/ui/FilesManager/src/convertIfcToFragmentsFile.d.ts.map +1 -1
  25. package/dist/core/components/ui/FilesManager/src/convertIfcToFragmentsFile.js.map +1 -1
  26. package/dist/core/components/ui/FilesManager/src/useFileUploadHandler.d.ts.map +1 -1
  27. package/dist/core/components/ui/FilesManager/src/useFileUploadHandler.js.map +1 -1
  28. package/dist/core/components/ui/Icons/IfcIcon.d.ts.map +1 -1
  29. package/dist/core/components/ui/Icons/IfcIcon.js.map +1 -1
  30. package/dist/core/components/ui/InfoSidebar/index.d.ts.map +1 -1
  31. package/dist/core/components/ui/InfoSidebar/index.js.map +1 -1
  32. package/dist/core/components/ui/Navbar.d.ts.map +1 -1
  33. package/dist/core/components/ui/Navbar.js.map +1 -1
  34. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts.map +1 -1
  35. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js.map +1 -1
  36. package/dist/core/components/ui/Sensors/SensorTagsSection.d.ts.map +1 -1
  37. package/dist/core/components/ui/Sensors/SensorTagsSection.js.map +1 -1
  38. package/dist/core/components/ui/Sensors/SensorsSection.d.ts.map +1 -1
  39. package/dist/core/components/ui/Sensors/SensorsSection.js.map +1 -1
  40. package/dist/core/components/ui/ShareFeature/ShareToolSubmenu.d.ts.map +1 -1
  41. package/dist/core/components/ui/ShareFeature/ShareToolSubmenu.js.map +1 -1
  42. package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js +2 -2
  43. package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js.map +1 -1
  44. package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.js +2 -2
  45. package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.js.map +1 -1
  46. package/dist/core/components/viewers/Viewer.d.ts.map +1 -1
  47. package/dist/core/components/viewers/Viewer.js +5 -1
  48. package/dist/core/components/viewers/Viewer.js.map +1 -1
  49. package/dist/core/components/viewers/bim/BimToolbar.d.ts.map +1 -1
  50. package/dist/core/components/viewers/bim/BimToolbar.js.map +1 -1
  51. package/dist/core/components/viewers/bim/BimViewer.d.ts.map +1 -1
  52. package/dist/core/components/viewers/bim/BimViewer.js +14 -5
  53. package/dist/core/components/viewers/bim/BimViewer.js.map +1 -1
  54. package/dist/core/components/viewers/bim/src/BimLoadingState/index.d.ts.map +1 -1
  55. package/dist/core/components/viewers/bim/src/BimLoadingState/index.js +6 -0
  56. package/dist/core/components/viewers/bim/src/BimLoadingState/index.js.map +1 -1
  57. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
  58. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js +168 -39
  59. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js.map +1 -1
  60. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
  61. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
  62. package/dist/core/components/viewers/bim/src/BimSidebar/src/LayersTab/src/FloorplanSection.d.ts.map +1 -1
  63. package/dist/core/components/viewers/bim/src/BimSidebar/src/LayersTab/src/FloorplanSection.js +1 -1
  64. package/dist/core/components/viewers/bim/src/BimSidebar/src/LayersTab/src/FloorplanSection.js.map +1 -1
  65. package/dist/core/components/viewers/bim/src/DXFLoader/index.d.ts +14 -37
  66. package/dist/core/components/viewers/bim/src/DXFLoader/index.d.ts.map +1 -1
  67. package/dist/core/components/viewers/bim/src/DXFLoader/index.js +31 -318
  68. package/dist/core/components/viewers/bim/src/DXFLoader/index.js.map +1 -1
  69. package/dist/core/components/viewers/bim/src/FloorplanTool/index.d.ts +66 -7
  70. package/dist/core/components/viewers/bim/src/FloorplanTool/index.d.ts.map +1 -1
  71. package/dist/core/components/viewers/bim/src/FloorplanTool/index.js +253 -21
  72. package/dist/core/components/viewers/bim/src/FloorplanTool/index.js.map +1 -1
  73. package/dist/core/components/viewers/bim/src/ModelManager/index.d.ts.map +1 -1
  74. package/dist/core/components/viewers/bim/src/ModelManager/index.js +9 -0
  75. package/dist/core/components/viewers/bim/src/ModelManager/index.js.map +1 -1
  76. package/dist/core/components/viewers/bim/src/SimpleBimViewer.d.ts.map +1 -1
  77. package/dist/core/components/viewers/bim/src/SimpleBimViewer.js.map +1 -1
  78. package/dist/core/components/viewers/bim/src/lib/TrueNorthPopover.d.ts +3 -2
  79. package/dist/core/components/viewers/bim/src/lib/TrueNorthPopover.d.ts.map +1 -1
  80. package/dist/core/components/viewers/bim/src/lib/TrueNorthPopover.js.map +1 -1
  81. package/dist/core/components/viewers/bim/src/lib/useFriendlyIfcClassName.d.ts.map +1 -1
  82. package/dist/core/components/viewers/bim/src/lib/useFriendlyIfcClassName.js +3 -4
  83. package/dist/core/components/viewers/bim/src/lib/useFriendlyIfcClassName.js.map +1 -1
  84. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts.map +1 -1
  85. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js +40 -18
  86. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js.map +1 -1
  87. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.d.ts +2 -5
  88. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.d.ts.map +1 -1
  89. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.js +45 -59
  90. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.js.map +1 -1
  91. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js +1 -0
  92. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js.map +1 -1
  93. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.d.ts +10 -1
  94. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.d.ts.map +1 -1
  95. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.js +25 -73
  96. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.js.map +1 -1
  97. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.d.ts +7 -3
  98. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.d.ts.map +1 -1
  99. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.js +42 -78
  100. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.js.map +1 -1
  101. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/Position3DCard.d.ts.map +1 -1
  102. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/Position3DCard.js +52 -75
  103. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/Position3DCard.js.map +1 -1
  104. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.d.ts +15 -3
  105. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.d.ts.map +1 -1
  106. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.js +165 -105
  107. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.js.map +1 -1
  108. package/dist/core/components/viewers/index.d.ts.map +1 -1
  109. package/dist/core/components/viewers/index.js.map +1 -1
  110. package/dist/core/components/viewers/map/MapViewer.d.ts.map +1 -1
  111. package/dist/core/components/viewers/map/MapViewer.js +1 -0
  112. package/dist/core/components/viewers/map/MapViewer.js.map +1 -1
  113. package/dist/core/components/viewers/map/datasets/DatasetManager/index.d.ts.map +1 -1
  114. package/dist/core/components/viewers/map/datasets/DatasetManager/index.js +4 -3
  115. package/dist/core/components/viewers/map/datasets/DatasetManager/index.js.map +1 -1
  116. package/dist/core/components/viewers/map/datasets/RowActions.d.ts.map +1 -1
  117. package/dist/core/components/viewers/map/datasets/RowActions.js +148 -0
  118. package/dist/core/components/viewers/map/datasets/RowActions.js.map +1 -1
  119. package/dist/core/components/viewers/map/datasets/index.d.ts.map +1 -1
  120. package/dist/core/components/viewers/map/datasets/index.js +32 -15
  121. package/dist/core/components/viewers/map/datasets/index.js.map +1 -1
  122. package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.d.ts +4 -0
  123. package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.d.ts.map +1 -0
  124. package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.js +43 -0
  125. package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.js.map +1 -0
  126. package/dist/core/components/viewers/map/datasets/src/localDatasets.d.ts.map +1 -1
  127. package/dist/core/components/viewers/map/datasets/src/localDatasets.js +39 -3
  128. package/dist/core/components/viewers/map/datasets/src/localDatasets.js.map +1 -1
  129. package/dist/core/components/viewers/map/datasets/src/minioDatasets.d.ts +1 -1
  130. package/dist/core/components/viewers/map/datasets/src/minioDatasets.d.ts.map +1 -1
  131. package/dist/core/components/viewers/map/datasets/src/minioDatasets.js +2 -1
  132. package/dist/core/components/viewers/map/datasets/src/minioDatasets.js.map +1 -1
  133. package/dist/core/components/viewers/map/datasets/src/publishedTiles.d.ts +47 -0
  134. package/dist/core/components/viewers/map/datasets/src/publishedTiles.d.ts.map +1 -0
  135. package/dist/core/components/viewers/map/datasets/src/publishedTiles.js +114 -0
  136. package/dist/core/components/viewers/map/datasets/src/publishedTiles.js.map +1 -0
  137. package/dist/core/components/viewers/map/datasets/src/wmsTime.d.ts +49 -0
  138. package/dist/core/components/viewers/map/datasets/src/wmsTime.d.ts.map +1 -0
  139. package/dist/core/components/viewers/map/datasets/src/wmsTime.js +100 -0
  140. package/dist/core/components/viewers/map/datasets/src/wmsTime.js.map +1 -0
  141. package/dist/core/components/viewers/map/src/Geocoder.d.ts.map +1 -1
  142. package/dist/core/components/viewers/map/src/Geocoder.js +9 -9
  143. package/dist/core/components/viewers/map/src/Geocoder.js.map +1 -1
  144. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.d.ts.map +1 -1
  145. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js +25 -43
  146. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js.map +1 -1
  147. package/dist/core/components/viewers/map/src/MapLayers/index.d.ts.map +1 -1
  148. package/dist/core/components/viewers/map/src/MapLayers/index.js.map +1 -1
  149. package/dist/core/components/viewers/map/src/MapLayers/src/BimLayer/index.d.ts.map +1 -1
  150. package/dist/core/components/viewers/map/src/MapLayers/src/BimLayer/index.js +19 -2
  151. package/dist/core/components/viewers/map/src/MapLayers/src/BimLayer/index.js.map +1 -1
  152. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.d.ts +9 -0
  153. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.d.ts.map +1 -0
  154. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.js +28 -0
  155. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.js.map +1 -0
  156. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.d.ts.map +1 -1
  157. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js +1 -16
  158. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js.map +1 -1
  159. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/FileModelLayer/FileModelLayer.d.ts.map +1 -1
  160. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/FileModelLayer/FileModelLayer.js.map +1 -1
  161. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.d.ts.map +1 -1
  162. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.js +31 -2
  163. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.js.map +1 -1
  164. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.d.ts +21 -0
  165. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.d.ts.map +1 -0
  166. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.js +111 -0
  167. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.js.map +1 -0
  168. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.d.ts.map +1 -1
  169. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.js +77 -2
  170. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.js.map +1 -1
  171. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
  172. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.js.map +1 -1
  173. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
  174. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
  175. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.d.ts.map +1 -1
  176. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js +10 -3
  177. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js.map +1 -1
  178. package/dist/core/components/viewers/map/utils/geocoder.d.ts +6 -2
  179. package/dist/core/components/viewers/map/utils/geocoder.d.ts.map +1 -1
  180. package/dist/core/components/viewers/map/utils/geocoder.js +10 -62
  181. package/dist/core/components/viewers/map/utils/geocoder.js.map +1 -1
  182. package/dist/core/components/viewers/map/utils/geocoding/adapters.d.ts +5 -0
  183. package/dist/core/components/viewers/map/utils/geocoding/adapters.d.ts.map +1 -0
  184. package/dist/core/components/viewers/map/utils/geocoding/adapters.js +192 -0
  185. package/dist/core/components/viewers/map/utils/geocoding/adapters.js.map +1 -0
  186. package/dist/core/components/viewers/map/utils/geocoding/config.d.ts +6 -0
  187. package/dist/core/components/viewers/map/utils/geocoding/config.d.ts.map +1 -0
  188. package/dist/core/components/viewers/map/utils/geocoding/config.js +14 -0
  189. package/dist/core/components/viewers/map/utils/geocoding/config.js.map +1 -0
  190. package/dist/core/components/viewers/map/utils/geocoding/index.d.ts +8 -0
  191. package/dist/core/components/viewers/map/utils/geocoding/index.d.ts.map +1 -0
  192. package/dist/core/components/viewers/map/utils/geocoding/index.js +44 -0
  193. package/dist/core/components/viewers/map/utils/geocoding/index.js.map +1 -0
  194. package/dist/core/components/viewers/map/utils/geocoding/osm.d.ts +6 -0
  195. package/dist/core/components/viewers/map/utils/geocoding/osm.d.ts.map +1 -0
  196. package/dist/core/components/viewers/map/utils/geocoding/osm.js +39 -0
  197. package/dist/core/components/viewers/map/utils/geocoding/osm.js.map +1 -0
  198. package/dist/core/components/viewers/map/utils/geocoding/pelias.d.ts +8 -0
  199. package/dist/core/components/viewers/map/utils/geocoding/pelias.d.ts.map +1 -0
  200. package/dist/core/components/viewers/map/utils/geocoding/pelias.js +35 -0
  201. package/dist/core/components/viewers/map/utils/geocoding/pelias.js.map +1 -0
  202. package/dist/core/components/viewers/pointcloud/PointCloudToolbar.d.ts.map +1 -1
  203. package/dist/core/components/viewers/pointcloud/PointCloudToolbar.js.map +1 -1
  204. package/dist/core/components/viewers/pointcloud/PointCloudViewer.js +1 -3
  205. package/dist/core/components/viewers/pointcloud/PointCloudViewer.js.map +1 -1
  206. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.d.ts.map +1 -1
  207. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js +2 -3
  208. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js.map +1 -1
  209. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
  210. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/FilesSection.js +8 -2
  211. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/FilesSection.js.map +1 -1
  212. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.d.ts.map +1 -1
  213. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.js.map +1 -1
  214. package/dist/core/components/viewers/pointcloud/src/tools/PerformanceSettingsTools/NodeSizeSelectionTool.js +9 -9
  215. package/dist/core/components/viewers/pointcloud/src/tools/PerformanceSettingsTools/NodeSizeSelectionTool.js.map +1 -1
  216. package/dist/core/hooks/provider.js.map +1 -1
  217. package/dist/core/plugins/host/provider.d.ts.map +1 -1
  218. package/dist/core/plugins/host/provider.js.map +1 -1
  219. package/dist/core/store/AppConfig/context.d.ts.map +1 -1
  220. package/dist/core/store/AppConfig/context.js.map +1 -1
  221. package/dist/core/store/BIM/context.d.ts.map +1 -1
  222. package/dist/core/store/BIM/context.js.map +1 -1
  223. package/dist/core/store/BIM/reducer.d.ts +0 -1
  224. package/dist/core/store/BIM/reducer.d.ts.map +1 -1
  225. package/dist/core/store/BIM/reducer.js +0 -4
  226. package/dist/core/store/BIM/reducer.js.map +1 -1
  227. package/dist/core/store/Buildings/context.d.ts.map +1 -1
  228. package/dist/core/store/Buildings/context.js.map +1 -1
  229. package/dist/core/store/Content/context.d.ts.map +1 -1
  230. package/dist/core/store/Content/context.js.map +1 -1
  231. package/dist/core/store/Datasets/context.d.ts.map +1 -1
  232. package/dist/core/store/Datasets/context.js +2 -1
  233. package/dist/core/store/Datasets/context.js.map +1 -1
  234. package/dist/core/store/Datasets/reducer.d.ts +2 -0
  235. package/dist/core/store/Datasets/reducer.d.ts.map +1 -1
  236. package/dist/core/store/Datasets/reducer.js +9 -4
  237. package/dist/core/store/Datasets/reducer.js.map +1 -1
  238. package/dist/core/store/Files/context.d.ts.map +1 -1
  239. package/dist/core/store/Files/context.js.map +1 -1
  240. package/dist/core/store/Map/context.d.ts.map +1 -1
  241. package/dist/core/store/Map/context.js.map +1 -1
  242. package/dist/core/store/Menus/context.d.ts.map +1 -1
  243. package/dist/core/store/Menus/context.js.map +1 -1
  244. package/dist/core/store/Permissions/context.d.ts.map +1 -1
  245. package/dist/core/store/Permissions/context.js.map +1 -1
  246. package/dist/core/store/PointCloud/context.d.ts.map +1 -1
  247. package/dist/core/store/PointCloud/context.js.map +1 -1
  248. package/dist/core/store/Tools/context.d.ts.map +1 -1
  249. package/dist/core/store/Tools/context.js.map +1 -1
  250. package/dist/core/types/datasetTypes.d.ts +8 -1
  251. package/dist/core/types/datasetTypes.d.ts.map +1 -1
  252. package/dist/core/types/dbTypes.d.ts +13 -13
  253. package/dist/core/types/dbTypes.d.ts.map +1 -1
  254. package/dist/core/types/dbTypes.js +13 -13
  255. package/dist/core/types/dbTypes.js.map +1 -1
  256. package/dist/core/types/index.d.ts +1 -1
  257. package/dist/core/types/index.d.ts.map +1 -1
  258. package/dist/core/types/index.js.map +1 -1
  259. package/dist/core/utils/imageUtils.js +1 -1
  260. package/dist/core/utils/imageUtils.js.map +1 -1
  261. package/package.json +2 -1
  262. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.d.ts +0 -3
  263. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.d.ts.map +0 -1
  264. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.js +0 -173
  265. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/core/components/viewers/map/datasets/index.tsx"],"sourcesContent":["'use client'\r\n\r\n// Icons\r\nimport * as LR from 'lucide-react'\r\n// Dependencies\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\nimport { usePermissions } from '../../../../store'\r\nimport { usePathname } from 'next/navigation'\r\n\r\nimport type { Dataset } from '../../../../types/datasetTypes'\r\nimport { useOpenDataPortalsByCountrySubdivision, useOpenDataPortalsByGroup, useOpenDataPortalsByMunicipality } from '../../../../hooks/openDataPortals/openDataPortals'\r\nimport { DatasetsContext, MenusContext, useMapContext } from '../../../../store'\r\nimport { useAppConfigContext } from '../../../../store/AppConfig/context'\r\nimport { Badge } from '../../../../components/ui/Badge'\r\nimport {\r\n Breadcrumb,\r\n BreadcrumbItem,\r\n BreadcrumbLink,\r\n BreadcrumbList,\r\n BreadcrumbPage,\r\n BreadcrumbSeparator,\r\n} from '../../../../components/ui/Breadcrumb'\r\nimport { Button } from '../../../../components/ui/Button'\r\nimport { DataTable } from '../../../../components/ui/DataTable'\r\nimport {\r\n Dialog,\r\n DialogClose,\r\n DialogContent,\r\n DialogDescription,\r\n DialogHeader,\r\n DialogTitle,\r\n} from '../../../../components/ui/Dialog'\r\nimport { Input } from '../../../../components/ui/Input'\r\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '../../../../components/ui/Tabs'\r\n// Data\r\nimport { useColumns } from './data'\r\nimport DatasetDetails from './DatasetDetails'\r\n// Custom components\r\nimport { AddPortalDialog } from './AddPortalDialog'\r\nimport DatasetSkeleton from './DatasetSkeleton'\r\nimport Filters from './Filters'\r\nimport RowActions from './RowActions'\r\nimport { useDatasetsForPortals } from './src/useDatasetsForPortals'\r\nimport { handleFavouriteDataset } from './utils'\r\nimport { fetchLocalDatasets } from './src/localDatasets'\r\nimport { fetchOrganizationalMinioDatasets } from './src/minioDatasets'\r\nimport { useFastDatasetCache } from './src/useFastDatasetCache'\r\nimport { DatasetGroup } from '../../../../types/dbTypes'\r\n\r\ntype OrgVisibility = {\r\n isAdmin: boolean\r\n currentOrgId: number\r\n allowedOrgIds: number[]\r\n}\r\n\r\nconst ADMIN_ALLOWED_ORGS = [1, 2, 3, 4, 5, 6]\r\nconst ORG_BY_PATH_PREFIX: Record<string, number> = {\r\n '/envirocentre': 1,\r\n '/dnd': 3,\r\n '/canada': 4,\r\n '/gac': 5,\r\n '/carleton': 6,\r\n}\r\n\r\nfunction normalizeOrgId(org?: number | string | null) {\r\n if (org === null || org === undefined) return undefined\r\n const parsed = typeof org === 'number' ? org : Number.parseInt(String(org), 10)\r\n return Number.isFinite(parsed) ? parsed : undefined\r\n}\r\n\r\nfunction getOrgVisibilityFromPath(pathname?: string | null): OrgVisibility {\r\n const normalizedPath = (pathname || '').toLowerCase()\r\n const firstSegment = normalizedPath.split('/').filter(Boolean)[0]\r\n const prefix = firstSegment ? `/${firstSegment}` : ''\r\n\r\n if (prefix === '/cdt') {\r\n return {\r\n isAdmin: true,\r\n currentOrgId: 1,\r\n allowedOrgIds: ADMIN_ALLOWED_ORGS,\r\n }\r\n }\r\n\r\n const currentOrgId = ORG_BY_PATH_PREFIX[prefix] ?? 2\r\n const allowedOrgIds = Array.from(new Set([2, currentOrgId]))\r\n\r\n return {\r\n isAdmin: false,\r\n currentOrgId,\r\n allowedOrgIds,\r\n }\r\n}\r\n\r\nfunction datasetVisibleForOrg(dataset: Dataset, visibility: OrgVisibility) {\r\n if (visibility.isAdmin) return true\r\n if (dataset.group !== DatasetGroup.Organizational) return true\r\n\r\n const orgId = normalizeOrgId(dataset.organization)\r\n if (orgId === undefined) return false\r\n\r\n return visibility.allowedOrgIds.includes(orgId)\r\n}\r\n\r\n\r\ntype DatasetsProps = {\r\n isOpen: boolean\r\n setIsOpenAction: (open: boolean) => void\r\n}\r\n\r\nexport default function Datasets({ isOpen, setIsOpenAction }: DatasetsProps) {\r\n // Translation\r\n const t = useTranslations('Datasets')\r\n\r\n // Permissions\r\n const { ability } = usePermissions()\r\n\r\n const datasetColumns = useColumns()\r\n\r\n // Contexts\r\n const { state: mapState } = useMapContext()\r\n const { currentLocation } = mapState.map\r\n const { state: appConfigState } = useAppConfigContext()\r\n const orgCountry = (appConfigState.appConfig.organization?.country || '').toUpperCase()\r\n const org = appConfigState.appConfig.organization\r\n // Fall back to org fixed location when currentLocation hasn't been set yet (e.g. before map hover)\r\n const municipality = currentLocation?.municipality ?? org?.municipality ?? null\r\n const countrySubdivision = currentLocation?.countrySubdivision ?? org?.countrySubdivision ?? null\r\n const { state: datasetState, dispatch: datasetDispatch } = React.useContext(DatasetsContext)\r\n const { addedDatasets } = datasetState.datasets\r\n const { state: menusState } = React.useContext(MenusContext)\r\n const { rowsPerPage } = menusState.menus\r\n\r\n const pathname = usePathname()\r\n const orgVisibility = React.useMemo(() => getOrgVisibilityFromPath(pathname), [pathname])\r\n\r\n // UI State\r\n const [view, setView] = React.useState<'table' | 'detail'>('table')\r\n const [selectedDataset, setSelectedDataset] = React.useState<Dataset | null>(null)\r\n const [favouriteDatasets, setFavouriteDatasets] = React.useState<Dataset[]>([])\r\n const [searchTerm, setSearchTerm] = React.useState('')\r\n const [appliedFilters, setAppliedFilters] = React.useState<{ countrySubdivisions: string[], municipalities: string[], types: string[], sources: string[] }>({ countrySubdivisions: [], municipalities: [], types: [], sources: [] })\r\n const [currentTab, setCurrentTab] = React.useState('all')\r\n const [isAddPortalOpen, setIsAddPortalOpen] = React.useState(false)\r\n const showMunicipalTab = React.useMemo(() => Boolean(municipality), [municipality])\r\n\r\n const { openDataPortals: municipalPortals } = useOpenDataPortalsByMunicipality(municipality)\r\n const { openDataPortals: subdivisionPortals } = useOpenDataPortalsByCountrySubdivision(countrySubdivision)\r\n const { openDataPortals: nationalPortals } = useOpenDataPortalsByGroup(DatasetGroup.National)\r\n\r\n // Belt-and-suspenders country guard: portal.country must match org, or be unset (legacy/global)\r\n const matchesOrgCountry = React.useCallback(\r\n (portalCountry: string | null | undefined) => {\r\n if (!orgCountry) return true // org country unknown — show everything\r\n if (!portalCountry) return true // portal has no country set — treat as global\r\n return portalCountry.toUpperCase() === orgCountry\r\n },\r\n [orgCountry],\r\n )\r\n\r\n const filteredMunicipalPortals = React.useMemo(() => {\r\n if (!Array.isArray(municipalPortals)) return []\r\n const filtered = municipalPortals.filter(p => matchesOrgCountry(p.country))\r\n return filtered\r\n }, [municipalPortals, matchesOrgCountry, municipality])\r\n const filteredSubdivisionPortals = React.useMemo(\r\n () => (Array.isArray(subdivisionPortals)\r\n ? subdivisionPortals.filter(p => p.municipality == null && matchesOrgCountry(p.country))\r\n : []),\r\n [subdivisionPortals, matchesOrgCountry],\r\n )\r\n const filteredNationalPortals = React.useMemo(() => {\r\n if (!Array.isArray(nationalPortals)) return []\r\n const filtered = nationalPortals.filter(p => matchesOrgCountry(p.country))\r\n return filtered\r\n }, [nationalPortals, orgCountry, matchesOrgCountry])\r\n\r\n const municipal = useDatasetsForPortals(filteredMunicipalPortals, { rowsPerPage })\r\n const subdivision = useDatasetsForPortals(filteredSubdivisionPortals, { rowsPerPage })\r\n const national = useDatasetsForPortals(filteredNationalPortals, { rowsPerPage })\r\n React.useEffect(() => {\r\n const loadOrganizationalDatasets = async () => {\r\n // Two parallel sources: Martin vector tiles (if configured) and MinIO-\r\n // backed GeoJSON uploads (the \"Add Dataset\" path). Errors from either\r\n // are isolated so a failure on one side does not block the other.\r\n const martinBaseUrl = process.env.NEXT_PUBLIC_MARTIN_SERVER_URL?.replace(/\\/+$/, '')\r\n\r\n const martinPromise: Promise<Dataset[]> = martinBaseUrl\r\n ? (async () => {\r\n const datasetsUrl = martinBaseUrl.includes('/tiles/index.json')\r\n ? martinBaseUrl\r\n : `${martinBaseUrl}/tiles/index.json`\r\n\r\n const localPortal = {\r\n id: -1,\r\n name: 'Organizational Datasets',\r\n apiUrl: datasetsUrl,\r\n dataManagementSystem: 'Other' as const,\r\n countrySubdivision: null,\r\n municipality: null,\r\n group: 'Organizational' as const,\r\n }\r\n\r\n try {\r\n return await fetchLocalDatasets(localPortal as any)\r\n }\r\n catch (err) {\r\n console.error('Failed to load Martin organizational datasets:', err)\r\n return []\r\n }\r\n })()\r\n : Promise.resolve([])\r\n\r\n if (!martinBaseUrl) {\r\n console.warn('NEXT_PUBLIC_MARTIN_SERVER_URL not configured — skipping Martin pre-load')\r\n }\r\n\r\n // The MinIO key prefix is the *session* organization (set server-side\r\n // by the upload route), not orgVisibility.currentOrgId (which is\r\n // path-derived and hardcoded for admin routes like /cdt).\r\n const sessionOrgId = typeof org?.id === 'number'\r\n ? org.id\r\n : Number.parseInt(String(org?.id ?? ''), 10)\r\n const minioPromise: Promise<Dataset[]> = Number.isFinite(sessionOrgId)\r\n ? fetchOrganizationalMinioDatasets(sessionOrgId).catch((err) => {\r\n console.error('Failed to load MinIO organizational datasets:', err)\r\n return []\r\n })\r\n : Promise.resolve([])\r\n\r\n const [martinDatasets, minioDatasets] = await Promise.all([martinPromise, minioPromise])\r\n const combined = [...martinDatasets, ...minioDatasets]\r\n const visibleOrgDatasets = combined.filter(ds => datasetVisibleForOrg(ds, orgVisibility))\r\n\r\n if (visibleOrgDatasets.length > 0) {\r\n datasetDispatch({\r\n type: 'SET_DATASETS',\r\n payload: { datasets: visibleOrgDatasets },\r\n })\r\n }\r\n else {\r\n console.warn('No organizational datasets found')\r\n }\r\n }\r\n\r\n loadOrganizationalDatasets()\r\n }, [datasetDispatch, orgVisibility, org?.id])\r\n\r\n const nationalDatasets = national.datasets\r\n const subdivisionDatasets = subdivision.datasets\r\n const municipalDatasets = municipal.datasets\r\n\r\n const isLoadingNational = national.isLoading && nationalDatasets.length === 0\r\n const isLoadingSubdivision = subdivision.isLoading && subdivisionDatasets.length === 0\r\n const isLoadingMunicipal = municipal.isLoading && municipalDatasets.length === 0\r\n\r\n const datasetsError = React.useMemo(() => {\r\n if (currentTab === 'municipal' && municipal.isError && municipalDatasets.length === 0) return t('failedFetchError')\r\n if (currentTab === 'countrySubdivision' && subdivision.isError && subdivisionDatasets.length === 0) return t('failedFetchError')\r\n if (currentTab === 'national' && national.isError && nationalDatasets.length === 0) return t('failedFetchError')\r\n return null\r\n }, [currentTab, municipal.isError, municipalDatasets.length, subdivision.isError, subdivisionDatasets.length, national.isError, nationalDatasets.length, t])\r\n\r\n const allDatasets = React.useMemo(() => {\r\n const unfiltered = [\r\n ...nationalDatasets,\r\n ...subdivisionDatasets,\r\n ...municipalDatasets,\r\n ...addedDatasets,\r\n ...(datasetState.datasets.datasets || []),\r\n ]\r\n\r\n const filtered = unfiltered.filter(ds => datasetVisibleForOrg(ds, orgVisibility))\r\n\r\n return filtered\r\n }, [nationalDatasets, subdivisionDatasets, municipalDatasets, datasetState.datasets.datasets, addedDatasets, orgVisibility])\r\n\r\n const currentTabLoading = React.useMemo(() => {\r\n switch (currentTab) {\r\n case 'national':\r\n return isLoadingNational\r\n case 'countrySubdivision':\r\n return isLoadingSubdivision\r\n case 'municipal':\r\n return isLoadingMunicipal\r\n case 'all':\r\n // Show loading for \"all\" if any datasets are loading and we have no data yet\r\n return (isLoadingNational || isLoadingSubdivision || isLoadingMunicipal) && \r\n allDatasets.length === 0\r\n case 'organizational':\r\n // Show loading for \"organizational\" if any datasets are loading and we have no organizational data yet\r\n return (isLoadingNational || isLoadingSubdivision || isLoadingMunicipal) && \r\n allDatasets.filter(ds => ds.group === 'Organizational').length === 0\r\n default:\r\n return false\r\n }\r\n }, [currentTab, isLoadingNational, isLoadingSubdivision, isLoadingMunicipal, allDatasets])\r\n\r\n React.useEffect(() => {\r\n if (!showMunicipalTab && currentTab === 'municipal') {\r\n setCurrentTab('all')\r\n }\r\n }, [showMunicipalTab, currentTab])\r\n\r\n // Memoized datasets for current tab\r\n const currentTabDatasets = React.useMemo(() => {\r\n switch (currentTab) {\r\n case 'applied':\r\n return allDatasets.filter(ds => addedDatasets.some(d => d.name === ds.name))\r\n case 'favourites':\r\n return allDatasets.filter(ds => favouriteDatasets.some(fav => fav.name === ds.name))\r\n case 'organizational':\r\n return allDatasets.filter(ds => ds.group === 'Organizational')\r\n case 'liveData':\r\n return allDatasets.filter(ds => ds.portal?.live === true)\r\n case 'national':\r\n return nationalDatasets\r\n case 'countrySubdivision':\r\n return subdivisionDatasets\r\n case 'municipal':\r\n return municipalDatasets\r\n case 'all':\r\n default:\r\n return allDatasets\r\n }\r\n }, [currentTab, allDatasets, addedDatasets, favouriteDatasets, nationalDatasets, subdivisionDatasets, municipalDatasets])\r\n\r\n // Memoized filtered data\r\n const filteredData = React.useMemo(() => {\r\n return currentTabDatasets.filter((dataset) => {\r\n // Search filter\r\n const matchesSearch = Object.values(dataset).some(value =>\r\n String(value).toLowerCase().includes(searchTerm.toLowerCase()),\r\n )\r\n if (!matchesSearch)\r\n return false\r\n\r\n // Country subdivision filter\r\n const matchesSubdivision\r\n = appliedFilters.countrySubdivisions.length === 0\r\n || !dataset.countrySubdivision\r\n || appliedFilters.countrySubdivisions.includes(dataset.countrySubdivision)\r\n\r\n // Municipality filter\r\n const matchesMunicipality\r\n = appliedFilters.municipalities.length === 0\r\n || !dataset.municipality\r\n || appliedFilters.municipalities.includes(dataset.municipality)\r\n\r\n // Type filter\r\n const matchesType\r\n = appliedFilters.types.length === 0\r\n || appliedFilters.types.includes(dataset.type)\r\n\r\n // Source filter (dataset.portal?.name, falling back to publisher)\r\n const datasetSource = dataset.portal?.name ?? dataset.publisher\r\n const matchesSource\r\n = appliedFilters.sources.length === 0\r\n || (datasetSource ? appliedFilters.sources.includes(datasetSource) : false)\r\n\r\n return matchesSubdivision && matchesMunicipality && matchesType && matchesSource\r\n })\r\n }, [currentTabDatasets, searchTerm, appliedFilters])\r\n\r\n const sortedFilteredData = React.useMemo(() => {\r\n // Remove duplicates by name\r\n const uniqueByName = new Map<string, Dataset>()\r\n for (const ds of filteredData) {\r\n const name = ds.name?.toLowerCase() || ''\r\n if (!uniqueByName.has(name)) {\r\n uniqueByName.set(name, ds)\r\n }\r\n }\r\n\r\n // Filter out unwanted names/types\r\n const filtered = [...uniqueByName.values()].filter((ds) => {\r\n const name = ds.name?.toLowerCase() || ''\r\n const type = ds.type?.toLowerCase() || ''\r\n return !name.includes('basemap') && !type.includes('geocoding')\r\n })\r\n\r\n // HARD CODE BLOCK LIST\r\n const blocklisted = (ds: Dataset) => {\r\n const url = (ds.url || '').toLowerCase()\r\n const name = (ds.name || '').toLowerCase()\r\n return (\r\n url.includes('/2021_statistics_canada_boundaries/featureserver')\r\n || name.includes('2021 statistics canada boundaries')\r\n || url.includes('/limites_du_recensement_de_statistique_canada_(2021)/featureserver')\r\n || name.includes('limites du recensement de statistique canada (2021)')\r\n )\r\n }\r\n\r\n const safe = filtered.filter(ds => !blocklisted(ds))\r\n\r\n // Sort by name\r\n return safe.sort((a, b) =>\r\n (a.name || '').localeCompare(b.name || ''),\r\n )\r\n }, [filteredData])\r\n\r\n const { prefetch } = useFastDatasetCache()\r\n\r\n React.useEffect(() => {\r\n if (isOpen && sortedFilteredData.length > 0) {\r\n const datasetsToPreload = sortedFilteredData.slice(0, 10)\r\n datasetsToPreload.forEach((dataset, index) => {\r\n setTimeout(() => {\r\n prefetch(dataset)\r\n }, index * 200)\r\n })\r\n }\r\n }, [isOpen, sortedFilteredData, prefetch])\r\n\r\n // Handlers\r\n const handleTabChange = React.useCallback((value: string) => setCurrentTab(value), [])\r\n const handleRowClick = React.useCallback((dataset: Dataset) => {\r\n setSelectedDataset(dataset)\r\n setView('detail')\r\n }, [])\r\n const handleRowHover = React.useCallback((dataset: Dataset) => {\r\n prefetch(dataset)\r\n \r\n const currentIndex = sortedFilteredData.indexOf(dataset)\r\n if (currentIndex >= 0 && currentIndex < sortedFilteredData.length - 2) {\r\n setTimeout(() => {\r\n if (sortedFilteredData[currentIndex + 1]) {\r\n prefetch(sortedFilteredData[currentIndex + 1])\r\n }\r\n }, 100)\r\n }\r\n }, [prefetch, sortedFilteredData])\r\n const handleBackToTable = React.useCallback(() => {\r\n setView('table')\r\n setSelectedDataset(null)\r\n }, [])\r\n const handleAddDatasetToMap = React.useCallback(() => {\r\n if (selectedDataset) {\r\n datasetDispatch({ type: 'ADD_DATASET_TO_MAP', payload: { dataset: selectedDataset } })\r\n }\r\n }, [selectedDataset, datasetDispatch])\r\n const handleRemoveDatasetFromMap = React.useCallback(() => {\r\n if (selectedDataset) {\r\n datasetDispatch({ type: 'REMOVE_DATASET_FROM_MAP', payload: { datasetId: selectedDataset.id } })\r\n }\r\n }, [selectedDataset, datasetDispatch])\r\n const handleFavourite = handleFavouriteDataset(selectedDataset, favouriteDatasets, setFavouriteDatasets)\r\n\r\n const handleAddDataset = () => {\r\n // Logic to add a new dataset\r\n }\r\n\r\n // UI\r\n return (\r\n <Dialog open={isOpen} onOpenChange={setIsOpenAction}>\r\n <DialogContent className=\"h-screen sm:h-[90vh] sm:max-h-[90vh] w-full max-w-full sm:w-[88vw] sm:max-w-[88vw] p-0 gap-0 overflow-hidden flex flex-col\">\r\n {view === 'table' ? (\r\n <>\r\n <DialogHeader className=\"bg-background z-50 sticky top-0 p-6 flex flex-row flex-wrap justify-between items-end gap-2 text-left\">\r\n <div className=\"flex flex-col justify-end p-0\">\r\n <DialogTitle className=\"text-2xl\">{t('dialogTitle')}</DialogTitle>\r\n <DialogDescription className=\"text-sm\">\r\n {t('dialogDescription')}\r\n </DialogDescription>\r\n </div>\r\n <div className=\"flex flex-row flex-wrap justify-between items-center\">\r\n <div className=\"flex flex-wrap gap-2 font-medium\">\r\n <div className=\"relative\">\r\n <LR.Search className=\"absolute left-3 top-2.5 h-4 w-4 text-muted-foreground\" />\r\n <Input\r\n placeholder=\"Search\"\r\n className=\"pl-8 w-[250px]\"\r\n value={searchTerm}\r\n onChange={e => setSearchTerm(e.target.value)}\r\n disabled={!ability.can('read', 'File')}\r\n />\r\n </div>\r\n <div className=\"flex gap-2\">\r\n <Filters\r\n datasets={currentTabDatasets}\r\n appliedFilters={appliedFilters}\r\n onFiltersChange={setAppliedFilters}\r\n />\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n onClick={() => setIsAddPortalOpen(true)}\r\n title=\"Register a new open data portal\"\r\n >\r\n <LR.Plus className=\"h-4 w-4 mr-1\" />\r\n Add Portal\r\n </Button>\r\n </div>\r\n </div>\r\n </div>\r\n <DialogClose className=\"absolute right-2 top-2 h-5 w-5 rounded-xl text-muted-foreground hover:bg-transparent focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-background focus:ring-primary\">\r\n <LR.X className=\"!h-4 !w-4\" />\r\n </DialogClose>\r\n </DialogHeader>\r\n <div className=\"relative flex flex-col flex-1 min-h-0\">\r\n <Tabs value={currentTab} className=\"flex flex-col gap-0 h-full\" onValueChange={handleTabChange}>\r\n <div className=\"hidden md:!flex justify-between px-3 flex-shrink-0\">\r\n {' '}\r\n {/* Prevent tabs from shrinking */}\r\n <TabsList className=\"pointer-events-auto sticky flex z-40 top-[100px] bg-transparent\">\r\n <TabsTrigger className=\"hover:text-foreground gap-2\" value=\"applied\">\r\n <Badge variant=\"outline\">{addedDatasets.length}</Badge>\r\n {t('appliedTab')}\r\n </TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground gap-2\" value=\"favourites\">\r\n {t('favoritesTab')}\r\n </TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"organizational\">{t('organizationalTab')}</TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"all\">{t('allDataTab')}</TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"national\">{t('nationalTab')}</TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"countrySubdivision\">{t('countrySubdivisionTab')}</TabsTrigger>\r\n {showMunicipalTab && (\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"municipal\">{t('municipalTab')}</TabsTrigger>\r\n )}\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"liveData\">{t('liveDataTab')}</TabsTrigger>\r\n </TabsList>\r\n </div>\r\n <TabsContent\r\n value={currentTab}\r\n className=\"flex-1 pointer-events-auto mt-0 min-h-0\" // min-h-0 is crucial for flex children\r\n >\r\n {currentTabLoading ? (\r\n <DatasetSkeleton />\r\n ) : (datasetsError ? (\r\n <div className=\"flex flex-col justify-center items-center h-32 text-muted-foreground\">\r\n <LR.AlertCircle className=\"h-6 w-6 mb-2\" />\r\n <span>{datasetsError}</span>\r\n <Button variant=\"outline\" size=\"sm\" onClick={() => window.location.reload()} className=\"mt-2\">\r\n <LR.RefreshCw className=\"h-4 w-4 mr-2\" />\r\n {t('refreshButton')}\r\n </Button>\r\n </div>\r\n ) : (\r\n <DataTable\r\n showPagination={true}\r\n columns={datasetColumns}\r\n data={sortedFilteredData}\r\n tab={currentTab}\r\n onRowClick={handleRowClick}\r\n onRowHover={handleRowHover}\r\n className=\"rounded-none w-auto h-full\" \r\n paginationClasses=\"bg-background z-20 w-full border-t\" \r\n isLoading={currentTabLoading}\r\n leadingCell={props => (\r\n <RowActions\r\n {...props}\r\n favouriteDatasets={favouriteDatasets}\r\n setFavouriteDatasets={setFavouriteDatasets}\r\n />\r\n )}\r\n trailingCell={({ row, index }) => (\r\n <div>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"pointer-events-none\"\r\n >\r\n <LR.ChevronRight />\r\n </Button>\r\n </div>\r\n )}\r\n />\r\n ))}\r\n </TabsContent>\r\n </Tabs>\r\n </div>\r\n </>\r\n ) : (\r\n // Detail View Content\r\n <>\r\n <DialogHeader className=\"px-6 pt-6\">\r\n <div>\r\n <Breadcrumb>\r\n <BreadcrumbList>\r\n <BreadcrumbItem>\r\n <BreadcrumbLink\r\n href=\"#\"\r\n onClick={() => {\r\n handleBackToTable()\r\n setCurrentTab('all')\r\n }}\r\n >\r\n {t('breadcrumbTitle')}\r\n </BreadcrumbLink>\r\n </BreadcrumbItem>\r\n <BreadcrumbSeparator />\r\n <BreadcrumbItem>\r\n <BreadcrumbLink\r\n href=\"#\"\r\n onClick={() => {\r\n setCurrentTab(currentTab)\r\n handleBackToTable()\r\n }}\r\n >\r\n {currentTab.charAt(0).toUpperCase() + currentTab.slice(1)}\r\n </BreadcrumbLink>\r\n </BreadcrumbItem>\r\n <BreadcrumbSeparator />\r\n <BreadcrumbItem>\r\n <BreadcrumbPage>{selectedDataset?.name}</BreadcrumbPage>\r\n </BreadcrumbItem>\r\n </BreadcrumbList>\r\n </Breadcrumb>\r\n </div>\r\n <div className=\"flex flex-row justify-between\">\r\n <div className=\"flex items-center\">\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className={`opacity-70 hover:opacity-100 transition-opacity duration-200 hover:bg-transparent ${selectedDataset && favouriteDatasets.includes(selectedDataset) ? 'opacity-100' : ''}`}\r\n onClick={handleFavourite}\r\n >\r\n <LR.Star\r\n className=\"!h-5 !w-5\"\r\n size={24}\r\n color={`${selectedDataset && favouriteDatasets.includes(selectedDataset) ? 'hsl(var(--chart-5))' : 'black'} `}\r\n fill={`${selectedDataset && favouriteDatasets.includes(selectedDataset) ? 'hsl(var(--chart-5))' : 'none'} `}\r\n />\r\n </Button>\r\n <DialogTitle>{selectedDataset?.name}</DialogTitle>\r\n </div>\r\n <div className=\"flex gap-2\">\r\n <Button\r\n variant=\"secondary\"\r\n onClick={handleBackToTable}\r\n >\r\n <LR.ArrowLeft />\r\n {t('backToDataButton')}\r\n </Button>\r\n {selectedDataset && addedDatasets.some(d => d.name === selectedDataset.name)\r\n ? (\r\n <Button onClick={handleRemoveDatasetFromMap} disabled={!ability.can('read', 'File')}>\r\n <LR.Minus />\r\n {t('removeButton')}\r\n </Button>\r\n )\r\n : (\r\n <Button onClick={handleAddDatasetToMap} disabled={!ability.can('read', 'File')}>\r\n <LR.Plus />\r\n {t('applyButton')}\r\n </Button>\r\n )}\r\n </div>\r\n </div>\r\n </DialogHeader>\r\n <DatasetDetails selectedDataset={selectedDataset} />\r\n </>\r\n )}\r\n </DialogContent>\r\n <AddPortalDialog open={isAddPortalOpen} onOpenChange={setIsAddPortalOpen} />\r\n </Dialog>\r\n )\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAycU,mBAGM,KADF,YAFJ;AAtcV,YAAY,QAAQ;AAEpB,YAAa,WAAW;AACxB,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAC/B,SAAS,mBAAmB;AAG5B,SAAS,wCAAwC,2BAA2B,wCAAwC;AACpH,SAAS,iBAAiB,cAAc,qBAAqB;AAC7D,SAAS,2BAA2B;AACpC,SAAS,aAAa;AACtB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,cAAc;AACvB,SAAS,iBAAiB;AAC1B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,aAAa;AACtB,SAAS,MAAM,aAAa,UAAU,mBAAmB;AAEzD,SAAS,kBAAkB;AAC3B,OAAO,oBAAoB;AAE3B,SAAS,uBAAuB;AAChC,OAAO,qBAAqB;AAC5B,OAAO,aAAa;AACpB,OAAO,gBAAgB;AACvB,SAAS,6BAA6B;AACtC,SAAS,8BAA8B;AACvC,SAAS,0BAA0B;AACnC,SAAS,wCAAwC;AACjD,SAAS,2BAA2B;AACpC,SAAS,oBAAoB;AAQ7B,MAAM,qBAAqB,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAC5C,MAAM,qBAA6C;AAAA,EACjD,iBAAiB;AAAA,EACjB,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,aAAa;AACf;AAEA,SAAS,eAAe,KAA8B;AACpD,MAAI,QAAQ,QAAQ,QAAQ,OAAW,QAAO;AAC9C,QAAM,SAAS,OAAO,QAAQ,WAAW,MAAM,OAAO,SAAS,OAAO,GAAG,GAAG,EAAE;AAC9E,SAAO,OAAO,SAAS,MAAM,IAAI,SAAS;AAC5C;AAEA,SAAS,yBAAyB,UAAyC;AAvE3E;AAwEE,QAAM,kBAAkB,YAAY,IAAI,YAAY;AACpD,QAAM,eAAe,eAAe,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,CAAC;AAChE,QAAM,SAAS,eAAe,IAAI,YAAY,KAAK;AAEnD,MAAI,WAAW,QAAQ;AACrB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,cAAc;AAAA,MACd,eAAe;AAAA,IACjB;AAAA,EACF;AAEA,QAAM,gBAAe,wBAAmB,MAAM,MAAzB,YAA8B;AACnD,QAAM,gBAAgB,MAAM,KAAK,oBAAI,IAAI,CAAC,GAAG,YAAY,CAAC,CAAC;AAE3D,SAAO;AAAA,IACL,SAAS;AAAA,IACT;AAAA,IACA;AAAA,EACF;AACF;AAEA,SAAS,qBAAqB,SAAkB,YAA2B;AACzE,MAAI,WAAW,QAAS,QAAO;AAC/B,MAAI,QAAQ,UAAU,aAAa,eAAgB,QAAO;AAE1D,QAAM,QAAQ,eAAe,QAAQ,YAAY;AACjD,MAAI,UAAU,OAAW,QAAO;AAEhC,SAAO,WAAW,cAAc,SAAS,KAAK;AAChD;AAQe,SAAR,SAA0B,EAAE,QAAQ,gBAAgB,GAAkB;AA9G7E;AAgHE,QAAM,IAAI,gBAAgB,UAAU;AAGpC,QAAM,EAAE,QAAQ,IAAI,eAAe;AAEnC,QAAM,iBAAiB,WAAW;AAGlC,QAAM,EAAE,OAAO,SAAS,IAAI,cAAc;AAC1C,QAAM,EAAE,gBAAgB,IAAI,SAAS;AACrC,QAAM,EAAE,OAAO,eAAe,IAAI,oBAAoB;AACtD,QAAM,gBAAc,oBAAe,UAAU,iBAAzB,mBAAuC,YAAW,IAAI,YAAY;AACtF,QAAM,MAAM,eAAe,UAAU;AAErC,QAAM,gBAAe,8DAAiB,iBAAjB,YAAiC,2BAAK,iBAAtC,YAAsD;AAC3E,QAAM,sBAAqB,8DAAiB,uBAAjB,YAAuC,2BAAK,uBAA5C,YAAkE;AAC7F,QAAM,EAAE,OAAO,cAAc,UAAU,gBAAgB,IAAI,MAAM,WAAW,eAAe;AAC3F,QAAM,EAAE,cAAc,IAAI,aAAa;AACvC,QAAM,EAAE,OAAO,WAAW,IAAI,MAAM,WAAW,YAAY;AAC3D,QAAM,EAAE,YAAY,IAAI,WAAW;AAEnC,QAAM,WAAW,YAAY;AAC7B,QAAM,gBAAgB,MAAM,QAAQ,MAAM,yBAAyB,QAAQ,GAAG,CAAC,QAAQ,CAAC;AAGxF,QAAM,CAAC,MAAM,OAAO,IAAI,MAAM,SAA6B,OAAO;AAClE,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,MAAM,SAAyB,IAAI;AACjF,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,MAAM,SAAoB,CAAC,CAAC;AAC9E,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,EAAE;AACrD,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAA0G,EAAE,qBAAqB,CAAC,GAAG,gBAAgB,CAAC,GAAG,OAAO,CAAC,GAAG,SAAS,CAAC,EAAE,CAAC;AACnO,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AACxD,QAAM,CAAC,iBAAiB,kBAAkB,IAAI,MAAM,SAAS,KAAK;AAClE,QAAM,mBAAmB,MAAM,QAAQ,MAAM,QAAQ,YAAY,GAAG,CAAC,YAAY,CAAC;AAElF,QAAM,EAAE,iBAAiB,iBAAiB,IAAI,iCAAiC,YAAY;AAC3F,QAAM,EAAE,iBAAiB,mBAAmB,IAAI,uCAAuC,kBAAkB;AACzG,QAAM,EAAE,iBAAiB,gBAAgB,IAAI,0BAA0B,aAAa,QAAQ;AAG5F,QAAM,oBAAoB,MAAM;AAAA,IAC9B,CAAC,kBAA6C;AAC5C,UAAI,CAAC,WAAY,QAAO;AACxB,UAAI,CAAC,cAAe,QAAO;AAC3B,aAAO,cAAc,YAAY,MAAM;AAAA,IACzC;AAAA,IACA,CAAC,UAAU;AAAA,EACb;AAEA,QAAM,2BAA2B,MAAM,QAAQ,MAAM;AACnD,QAAI,CAAC,MAAM,QAAQ,gBAAgB,EAAG,QAAO,CAAC;AAC9C,UAAM,WAAW,iBAAiB,OAAO,OAAK,kBAAkB,EAAE,OAAO,CAAC;AAC1E,WAAO;AAAA,EACT,GAAG,CAAC,kBAAkB,mBAAmB,YAAY,CAAC;AACtD,QAAM,6BAA6B,MAAM;AAAA,IACvC,MAAO,MAAM,QAAQ,kBAAkB,IACnC,mBAAmB,OAAO,OAAK,EAAE,gBAAgB,QAAQ,kBAAkB,EAAE,OAAO,CAAC,IACrF,CAAC;AAAA,IACL,CAAC,oBAAoB,iBAAiB;AAAA,EACxC;AACA,QAAM,0BAA0B,MAAM,QAAQ,MAAM;AAClD,QAAI,CAAC,MAAM,QAAQ,eAAe,EAAG,QAAO,CAAC;AAC7C,UAAM,WAAW,gBAAgB,OAAO,OAAK,kBAAkB,EAAE,OAAO,CAAC;AACzE,WAAO;AAAA,EACT,GAAG,CAAC,iBAAiB,YAAY,iBAAiB,CAAC;AAEnD,QAAM,YAAY,sBAAsB,0BAA0B,EAAE,YAAY,CAAC;AACjF,QAAM,cAAc,sBAAsB,4BAA4B,EAAE,YAAY,CAAC;AACrF,QAAM,WAAW,sBAAsB,yBAAyB,EAAE,YAAY,CAAC;AAC/E,QAAM,UAAU,MAAM;AACpB,UAAM,6BAA6B,YAAY;AArLnD,UAAAA,KAAAC;AAyLM,YAAM,iBAAgBD,MAAA,QAAQ,IAAI,kCAAZ,gBAAAA,IAA2C,QAAQ,QAAQ;AAEjF,YAAM,gBAAoC,iBACrC,YAAY;AACX,cAAM,cAAc,cAAc,SAAS,mBAAmB,IAC1D,gBACA,GAAG,aAAa;AAEpB,cAAM,cAAc;AAAA,UAClB,IAAI;AAAA,UACJ,MAAM;AAAA,UACN,QAAQ;AAAA,UACR,sBAAsB;AAAA,UACtB,oBAAoB;AAAA,UACpB,cAAc;AAAA,UACd,OAAO;AAAA,QACT;AAEA,YAAI;AACF,iBAAO,MAAM,mBAAmB,WAAkB;AAAA,QACpD,SACO,KAAK;AACV,kBAAQ,MAAM,kDAAkD,GAAG;AACnE,iBAAO,CAAC;AAAA,QACV;AAAA,MACF,GAAG,IACH,QAAQ,QAAQ,CAAC,CAAC;AAEtB,UAAI,CAAC,eAAe;AAClB,gBAAQ,KAAK,8EAAyE;AAAA,MACxF;AAKA,YAAM,eAAe,QAAO,2BAAK,QAAO,WACpC,IAAI,KACJ,OAAO,SAAS,QAAOC,MAAA,2BAAK,OAAL,OAAAA,MAAW,EAAE,GAAG,EAAE;AAC7C,YAAM,eAAmC,OAAO,SAAS,YAAY,IACjE,iCAAiC,YAAY,EAAE,MAAM,CAAC,QAAQ;AAC5D,gBAAQ,MAAM,iDAAiD,GAAG;AAClE,eAAO,CAAC;AAAA,MACV,CAAC,IACD,QAAQ,QAAQ,CAAC,CAAC;AAEtB,YAAM,CAAC,gBAAgB,aAAa,IAAI,MAAM,QAAQ,IAAI,CAAC,eAAe,YAAY,CAAC;AACvF,YAAM,WAAW,CAAC,GAAG,gBAAgB,GAAG,aAAa;AACrD,YAAM,qBAAqB,SAAS,OAAO,QAAM,qBAAqB,IAAI,aAAa,CAAC;AAExF,UAAI,mBAAmB,SAAS,GAAG;AACjC,wBAAgB;AAAA,UACd,MAAM;AAAA,UACN,SAAS,EAAE,UAAU,mBAAmB;AAAA,QAC1C,CAAC;AAAA,MACH,OACK;AACH,gBAAQ,KAAK,kCAAkC;AAAA,MACjD;AAAA,IACF;AAEA,+BAA2B;AAAA,EAC7B,GAAG,CAAC,iBAAiB,eAAe,2BAAK,EAAE,CAAC;AAE5C,QAAM,mBAAmB,SAAS;AAClC,QAAM,sBAAsB,YAAY;AACxC,QAAM,oBAAoB,UAAU;AAEpC,QAAM,oBAAoB,SAAS,aAAa,iBAAiB,WAAW;AAC5E,QAAM,uBAAuB,YAAY,aAAa,oBAAoB,WAAW;AACrF,QAAM,qBAAqB,UAAU,aAAa,kBAAkB,WAAW;AAE/E,QAAM,gBAAgB,MAAM,QAAQ,MAAM;AACxC,QAAI,eAAe,eAAe,UAAU,WAAW,kBAAkB,WAAW,EAAG,QAAO,EAAE,kBAAkB;AAClH,QAAI,eAAe,wBAAwB,YAAY,WAAW,oBAAoB,WAAW,EAAG,QAAO,EAAE,kBAAkB;AAC/H,QAAI,eAAe,cAAc,SAAS,WAAW,iBAAiB,WAAW,EAAG,QAAO,EAAE,kBAAkB;AAC/G,WAAO;AAAA,EACT,GAAG,CAAC,YAAY,UAAU,SAAS,kBAAkB,QAAQ,YAAY,SAAS,oBAAoB,QAAQ,SAAS,SAAS,iBAAiB,QAAQ,CAAC,CAAC;AAE3J,QAAM,cAAc,MAAM,QAAQ,MAAM;AACtC,UAAM,aAAa;AAAA,MACjB,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAG;AAAA,MACH,GAAI,aAAa,SAAS,YAAY,CAAC;AAAA,IACzC;AAEA,UAAM,WAAW,WAAW,OAAO,QAAM,qBAAqB,IAAI,aAAa,CAAC;AAEhF,WAAO;AAAA,EACT,GAAG,CAAC,kBAAkB,qBAAqB,mBAAmB,aAAa,SAAS,UAAU,eAAe,aAAa,CAAC;AAE3H,QAAM,oBAAoB,MAAM,QAAQ,MAAM;AAC5C,YAAQ,YAAY;AAAA,MAClB,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AAEH,gBAAQ,qBAAqB,wBAAwB,uBAC9C,YAAY,WAAW;AAAA,MAChC,KAAK;AAEH,gBAAQ,qBAAqB,wBAAwB,uBAC9C,YAAY,OAAO,QAAM,GAAG,UAAU,gBAAgB,EAAE,WAAW;AAAA,MAC5E;AACE,eAAO;AAAA,IACX;AAAA,EACF,GAAG,CAAC,YAAY,mBAAmB,sBAAsB,oBAAoB,WAAW,CAAC;AAEzF,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,oBAAoB,eAAe,aAAa;AACnD,oBAAc,KAAK;AAAA,IACrB;AAAA,EACF,GAAG,CAAC,kBAAkB,UAAU,CAAC;AAGjC,QAAM,qBAAqB,MAAM,QAAQ,MAAM;AAC7C,YAAQ,YAAY;AAAA,MAClB,KAAK;AACH,eAAO,YAAY,OAAO,QAAM,cAAc,KAAK,OAAK,EAAE,SAAS,GAAG,IAAI,CAAC;AAAA,MAC7E,KAAK;AACH,eAAO,YAAY,OAAO,QAAM,kBAAkB,KAAK,SAAO,IAAI,SAAS,GAAG,IAAI,CAAC;AAAA,MACrF,KAAK;AACH,eAAO,YAAY,OAAO,QAAM,GAAG,UAAU,gBAAgB;AAAA,MAC/D,KAAK;AACH,eAAO,YAAY,OAAO,QAAG;AA1TrC,cAAAD;AA0TwC,mBAAAA,MAAA,GAAG,WAAH,gBAAAA,IAAW,UAAS;AAAA,SAAI;AAAA,MAC1D,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AAAA,MACL;AACE,eAAO;AAAA,IACX;AAAA,EACF,GAAG,CAAC,YAAY,aAAa,eAAe,mBAAmB,kBAAkB,qBAAqB,iBAAiB,CAAC;AAGxH,QAAM,eAAe,MAAM,QAAQ,MAAM;AACvC,WAAO,mBAAmB,OAAO,CAAC,YAAY;AAzUlD,UAAAA,KAAAC;AA2UM,YAAM,gBAAgB,OAAO,OAAO,OAAO,EAAE;AAAA,QAAK,WAChD,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,WAAW,YAAY,CAAC;AAAA,MAC/D;AACA,UAAI,CAAC;AACH,eAAO;AAGT,YAAM,qBACF,eAAe,oBAAoB,WAAW,KAC3C,CAAC,QAAQ,sBACT,eAAe,oBAAoB,SAAS,QAAQ,kBAAkB;AAG7E,YAAM,sBACF,eAAe,eAAe,WAAW,KACtC,CAAC,QAAQ,gBACT,eAAe,eAAe,SAAS,QAAQ,YAAY;AAGlE,YAAM,cACF,eAAe,MAAM,WAAW,KAC7B,eAAe,MAAM,SAAS,QAAQ,IAAI;AAGjD,YAAM,iBAAgBA,OAAAD,MAAA,QAAQ,WAAR,gBAAAA,IAAgB,SAAhB,OAAAC,MAAwB,QAAQ;AACtD,YAAM,gBACF,eAAe,QAAQ,WAAW,MAC9B,gBAAgB,eAAe,QAAQ,SAAS,aAAa,IAAI;AAEzE,aAAO,sBAAsB,uBAAuB,eAAe;AAAA,IACrE,CAAC;AAAA,EACH,GAAG,CAAC,oBAAoB,YAAY,cAAc,CAAC;AAEnD,QAAM,qBAAqB,MAAM,QAAQ,MAAM;AA5WjD,QAAAD;AA8WI,UAAM,eAAe,oBAAI,IAAqB;AAC9C,eAAW,MAAM,cAAc;AAC7B,YAAM,SAAOA,MAAA,GAAG,SAAH,gBAAAA,IAAS,kBAAiB;AACvC,UAAI,CAAC,aAAa,IAAI,IAAI,GAAG;AAC3B,qBAAa,IAAI,MAAM,EAAE;AAAA,MAC3B;AAAA,IACF;AAGA,UAAM,WAAW,CAAC,GAAG,aAAa,OAAO,CAAC,EAAE,OAAO,CAAC,OAAO;AAvX/D,UAAAA,KAAAC;AAwXM,YAAM,SAAOD,MAAA,GAAG,SAAH,gBAAAA,IAAS,kBAAiB;AACvC,YAAM,SAAOC,MAAA,GAAG,SAAH,gBAAAA,IAAS,kBAAiB;AACvC,aAAO,CAAC,KAAK,SAAS,SAAS,KAAK,CAAC,KAAK,SAAS,WAAW;AAAA,IAChE,CAAC;AAGD,UAAM,cAAc,CAAC,OAAgB;AACnC,YAAM,OAAO,GAAG,OAAO,IAAI,YAAY;AACvC,YAAM,QAAQ,GAAG,QAAQ,IAAI,YAAY;AACzC,aACE,IAAI,SAAS,kDAAkD,KAC5D,KAAK,SAAS,mCAAmC,KACjD,IAAI,SAAS,oEAAoE,KACjF,KAAK,SAAS,qDAAqD;AAAA,IAE1E;AAEA,UAAM,OAAO,SAAS,OAAO,QAAM,CAAC,YAAY,EAAE,CAAC;AAGnD,WAAO,KAAK;AAAA,MAAK,CAAC,GAAG,OAClB,EAAE,QAAQ,IAAI,cAAc,EAAE,QAAQ,EAAE;AAAA,IAC3C;AAAA,EACF,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,EAAE,SAAS,IAAI,oBAAoB;AAEzC,QAAM,UAAU,MAAM;AACpB,QAAI,UAAU,mBAAmB,SAAS,GAAG;AAC3C,YAAM,oBAAoB,mBAAmB,MAAM,GAAG,EAAE;AACxD,wBAAkB,QAAQ,CAAC,SAAS,UAAU;AAC5C,mBAAW,MAAM;AACf,mBAAS,OAAO;AAAA,QAClB,GAAG,QAAQ,GAAG;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,QAAQ,oBAAoB,QAAQ,CAAC;AAGzC,QAAM,kBAAkB,MAAM,YAAY,CAAC,UAAkB,cAAc,KAAK,GAAG,CAAC,CAAC;AACrF,QAAM,iBAAiB,MAAM,YAAY,CAAC,YAAqB;AAC7D,uBAAmB,OAAO;AAC1B,YAAQ,QAAQ;AAAA,EAClB,GAAG,CAAC,CAAC;AACL,QAAM,iBAAiB,MAAM,YAAY,CAAC,YAAqB;AAC7D,aAAS,OAAO;AAEhB,UAAM,eAAe,mBAAmB,QAAQ,OAAO;AACvD,QAAI,gBAAgB,KAAK,eAAe,mBAAmB,SAAS,GAAG;AACrE,iBAAW,MAAM;AACf,YAAI,mBAAmB,eAAe,CAAC,GAAG;AACxC,mBAAS,mBAAmB,eAAe,CAAC,CAAC;AAAA,QAC/C;AAAA,MACF,GAAG,GAAG;AAAA,IACR;AAAA,EACF,GAAG,CAAC,UAAU,kBAAkB,CAAC;AACjC,QAAM,oBAAoB,MAAM,YAAY,MAAM;AAChD,YAAQ,OAAO;AACf,uBAAmB,IAAI;AAAA,EACzB,GAAG,CAAC,CAAC;AACL,QAAM,wBAAwB,MAAM,YAAY,MAAM;AACpD,QAAI,iBAAiB;AACnB,sBAAgB,EAAE,MAAM,sBAAsB,SAAS,EAAE,SAAS,gBAAgB,EAAE,CAAC;AAAA,IACvF;AAAA,EACF,GAAG,CAAC,iBAAiB,eAAe,CAAC;AACrC,QAAM,6BAA6B,MAAM,YAAY,MAAM;AACzD,QAAI,iBAAiB;AACnB,sBAAgB,EAAE,MAAM,2BAA2B,SAAS,EAAE,WAAW,gBAAgB,GAAG,EAAE,CAAC;AAAA,IACjG;AAAA,EACF,GAAG,CAAC,iBAAiB,eAAe,CAAC;AACrC,QAAM,kBAAkB,uBAAuB,iBAAiB,mBAAmB,oBAAoB;AAEvG,QAAM,mBAAmB,MAAM;AAAA,EAE/B;AAGA,SACE,qBAAC,UAAO,MAAM,QAAQ,cAAc,iBAClC;AAAA,wBAAC,iBAAc,WAAU,8HACtB,mBAAS,UACR,iCACE;AAAA,2BAAC,gBAAa,WAAU,yGACtB;AAAA,6BAAC,SAAI,WAAU,iCACb;AAAA,8BAAC,eAAY,WAAU,YAAY,YAAE,aAAa,GAAE;AAAA,UACpD,oBAAC,qBAAkB,WAAU,WAC1B,YAAE,mBAAmB,GACxB;AAAA,WACF;AAAA,QACA,oBAAC,SAAI,WAAU,wDACb,+BAAC,SAAI,WAAU,oCACb;AAAA,+BAAC,SAAI,WAAU,YACb;AAAA,gCAAC,GAAG,QAAH,EAAU,WAAU,yDAAwD;AAAA,YAC7E;AAAA,cAAC;AAAA;AAAA,gBACC,aAAY;AAAA,gBACZ,WAAU;AAAA,gBACV,OAAO;AAAA,gBACP,UAAU,OAAK,cAAc,EAAE,OAAO,KAAK;AAAA,gBAC3C,UAAU,CAAC,QAAQ,IAAI,QAAQ,MAAM;AAAA;AAAA,YACvC;AAAA,aACF;AAAA,UACA,qBAAC,SAAI,WAAU,cACb;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,UAAU;AAAA,gBACV;AAAA,gBACA,iBAAiB;AAAA;AAAA,YACnB;AAAA,YACA;AAAA,cAAC;AAAA;AAAA,gBACC,SAAQ;AAAA,gBACR,MAAK;AAAA,gBACL,SAAS,MAAM,mBAAmB,IAAI;AAAA,gBACtC,OAAM;AAAA,gBAEN;AAAA,sCAAC,GAAG,MAAH,EAAQ,WAAU,gBAAe;AAAA,kBAAE;AAAA;AAAA;AAAA,YAEtC;AAAA,aACF;AAAA,WACF,GACF;AAAA,QACA,oBAAC,eAAY,WAAU,4LACrB,8BAAC,GAAG,GAAH,EAAK,WAAU,aAAY,GAC9B;AAAA,SACF;AAAA,MACA,oBAAC,SAAI,WAAU,yCACb,+BAAC,QAAK,OAAO,YAAY,WAAU,8BAA6B,eAAe,iBAC7E;AAAA,6BAAC,SAAI,WAAU,sDACZ;AAAA;AAAA,UAED,qBAAC,YAAS,WAAU,mEAClB;AAAA,iCAAC,eAAY,WAAU,+BAA8B,OAAM,WACzD;AAAA,kCAAC,SAAM,SAAQ,WAAW,wBAAc,QAAO;AAAA,cAC9C,EAAE,YAAY;AAAA,eACjB;AAAA,YACA,oBAAC,eAAY,WAAU,+BAA8B,OAAM,cACxD,YAAE,cAAc,GACnB;AAAA,YACA,oBAAC,eAAY,WAAU,yBAAwB,OAAM,kBAAkB,YAAE,mBAAmB,GAAE;AAAA,YAC9F,oBAAC,eAAY,WAAU,yBAAwB,OAAM,OAAO,YAAE,YAAY,GAAE;AAAA,YAC5E,oBAAC,eAAY,WAAU,yBAAwB,OAAM,YAAY,YAAE,aAAa,GAAE;AAAA,YAClF,oBAAC,eAAY,WAAU,yBAAwB,OAAM,sBAAsB,YAAE,uBAAuB,GAAE;AAAA,YACrG,oBACC,oBAAC,eAAY,WAAU,yBAAwB,OAAM,aAAa,YAAE,cAAc,GAAE;AAAA,YAEtF,oBAAC,eAAY,WAAU,yBAAwB,OAAM,YAAY,YAAE,aAAa,GAAE;AAAA,aACpF;AAAA,WACF;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,YACP,WAAU;AAAA,YAET,8BACC,oBAAC,mBAAgB,IACd,gBACH,qBAAC,SAAI,WAAU,wEACb;AAAA,kCAAC,GAAG,aAAH,EAAe,WAAU,gBAAe;AAAA,cACzC,oBAAC,UAAM,yBAAc;AAAA,cACrB,qBAAC,UAAO,SAAQ,WAAU,MAAK,MAAK,SAAS,MAAM,OAAO,SAAS,OAAO,GAAG,WAAU,QACrF;AAAA,oCAAC,GAAG,WAAH,EAAa,WAAU,gBAAe;AAAA,gBACtC,EAAE,eAAe;AAAA,iBACpB;AAAA,eACF,IAEA;AAAA,cAAC;AAAA;AAAA,gBACC,gBAAgB;AAAA,gBAChB,SAAS;AAAA,gBACT,MAAM;AAAA,gBACN,KAAK;AAAA,gBACL,YAAY;AAAA,gBACZ,YAAY;AAAA,gBACZ,WAAU;AAAA,gBACV,mBAAkB;AAAA,gBAClB,WAAW;AAAA,gBACX,aAAa,WACX;AAAA,kBAAC;AAAA,mDACK,QADL;AAAA,oBAEC;AAAA,oBACA;AAAA;AAAA,gBACF;AAAA,gBAEF,cAAc,CAAC,EAAE,KAAK,MAAM,MAC1B,oBAAC,SACC;AAAA,kBAAC;AAAA;AAAA,oBACC,SAAQ;AAAA,oBACR,MAAK;AAAA,oBACL,WAAU;AAAA,oBAEV,8BAAC,GAAG,cAAH,EAAgB;AAAA;AAAA,gBACnB,GACF;AAAA;AAAA,YAEJ;AAAA;AAAA,QAEJ;AAAA,SACF,GACF;AAAA,OACF;AAAA;AAAA,MAGA,iCACE;AAAA,6BAAC,gBAAa,WAAU,aACtB;AAAA,8BAAC,SACC,8BAAC,cACC,+BAAC,kBACC;AAAA,gCAAC,kBACC;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,MAAM;AACb,oCAAkB;AAClB,gCAAc,KAAK;AAAA,gBACrB;AAAA,gBAEC,YAAE,iBAAiB;AAAA;AAAA,YACtB,GACF;AAAA,YACA,oBAAC,uBAAoB;AAAA,YACrB,oBAAC,kBACC;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS,MAAM;AACb,gCAAc,UAAU;AACxB,oCAAkB;AAAA,gBACpB;AAAA,gBAEC,qBAAW,OAAO,CAAC,EAAE,YAAY,IAAI,WAAW,MAAM,CAAC;AAAA;AAAA,YAC1D,GACF;AAAA,YACA,oBAAC,uBAAoB;AAAA,YACrB,oBAAC,kBACC,8BAAC,kBAAgB,6DAAiB,MAAK,GACzC;AAAA,aACF,GACF,GACF;AAAA,UACA,qBAAC,SAAI,WAAU,iCACb;AAAA,iCAAC,SAAI,WAAU,qBACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,WAAW,qFAAqF,mBAAmB,kBAAkB,SAAS,eAAe,IAAI,gBAAgB,EAAE;AAAA,kBACnL,SAAS;AAAA,kBAET;AAAA,oBAAC,GAAG;AAAA,oBAAH;AAAA,sBACC,WAAU;AAAA,sBACV,MAAM;AAAA,sBACN,OAAO,GAAG,mBAAmB,kBAAkB,SAAS,eAAe,IAAI,wBAAwB,OAAO;AAAA,sBAC1G,MAAM,GAAG,mBAAmB,kBAAkB,SAAS,eAAe,IAAI,wBAAwB,MAAM;AAAA;AAAA,kBAC1G;AAAA;AAAA,cACF;AAAA,cACA,oBAAC,eAAa,6DAAiB,MAAK;AAAA,eACtC;AAAA,YACA,qBAAC,SAAI,WAAU,cACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAQ;AAAA,kBACR,SAAS;AAAA,kBAET;AAAA,wCAAC,GAAG,WAAH,EAAa;AAAA,oBACb,EAAE,kBAAkB;AAAA;AAAA;AAAA,cACvB;AAAA,cACC,mBAAmB,cAAc,KAAK,OAAK,EAAE,SAAS,gBAAgB,IAAI,IAErE,qBAAC,UAAO,SAAS,4BAA4B,UAAU,CAAC,QAAQ,IAAI,QAAQ,MAAM,GAChF;AAAA,oCAAC,GAAG,OAAH,EAAS;AAAA,gBACT,EAAE,cAAc;AAAA,iBACnB,IAGA,qBAAC,UAAO,SAAS,uBAAuB,UAAU,CAAC,QAAQ,IAAI,QAAQ,MAAM,GAC3E;AAAA,oCAAC,GAAG,MAAH,EAAQ;AAAA,gBACR,EAAE,aAAa;AAAA,iBAClB;AAAA,eAER;AAAA,aACF;AAAA,WACF;AAAA,QACA,oBAAC,kBAAe,iBAAkC;AAAA,SACpD;AAAA,OAEJ;AAAA,IACA,oBAAC,mBAAgB,MAAM,iBAAiB,cAAc,oBAAoB;AAAA,KAC5E;AAEJ;","names":["_a","_b"]}
1
+ {"version":3,"sources":["../../../../../../src/core/components/viewers/map/datasets/index.tsx"],"sourcesContent":["'use client'\r\n\r\n// Icons\r\nimport * as LR from 'lucide-react'\r\n// Dependencies\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\nimport { usePermissions } from '../../../../store'\r\nimport { usePathname } from 'next/navigation'\r\n\r\nimport type { Dataset } from '../../../../types/datasetTypes'\r\nimport { useOpenDataPortalsByCountrySubdivision, useOpenDataPortalsByGroup, useOpenDataPortalsByMunicipality } from '../../../../hooks/openDataPortals/openDataPortals'\r\nimport { DatasetsContext, MenusContext, useMapContext } from '../../../../store'\r\nimport { useAppConfigContext } from '../../../../store/AppConfig/context'\r\nimport { Badge } from '../../../../components/ui/Badge'\r\nimport {\r\n Breadcrumb,\r\n BreadcrumbItem,\r\n BreadcrumbLink,\r\n BreadcrumbList,\r\n BreadcrumbPage,\r\n BreadcrumbSeparator,\r\n} from '../../../../components/ui/Breadcrumb'\r\nimport { Button } from '../../../../components/ui/Button'\r\nimport { DataTable } from '../../../../components/ui/DataTable'\r\nimport {\r\n Dialog,\r\n DialogClose,\r\n DialogContent,\r\n DialogDescription,\r\n DialogHeader,\r\n DialogTitle,\r\n} from '../../../../components/ui/Dialog'\r\nimport { Input } from '../../../../components/ui/Input'\r\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '../../../../components/ui/Tabs'\r\n// Data\r\nimport { useColumns } from './data'\r\nimport DatasetDetails from './DatasetDetails'\r\n// Custom components\r\nimport { AddPortalDialog } from './AddPortalDialog'\r\nimport DatasetSkeleton from './DatasetSkeleton'\r\nimport Filters from './Filters'\r\nimport RowActions from './RowActions'\r\nimport { useDatasetsForPortals } from './src/useDatasetsForPortals'\r\nimport { handleFavouriteDataset } from './utils'\r\nimport { fetchLocalDatasets } from './src/localDatasets'\r\nimport { fetchOrganizationalMinioDatasets } from './src/minioDatasets'\r\nimport { buildPublishedCatalogMap, stampPublished, type PublishedCatalogEntry } from './src/publishedTiles'\r\nimport { builtinLiveDatasets } from './src/builtinLiveDatasets'\r\nimport { useFastDatasetCache } from './src/useFastDatasetCache'\r\nimport { DatasetGroup } from '../../../../types/dbTypes'\r\n\r\ntype OrgVisibility = {\r\n isAdmin: boolean\r\n currentOrgId: number\r\n allowedOrgIds: number[]\r\n}\r\n\r\nconst ADMIN_ALLOWED_ORGS = [1, 2, 3, 4, 5, 6]\r\nconst ORG_BY_PATH_PREFIX: Record<string, number> = {\r\n '/envirocentre': 1,\r\n '/dnd': 3,\r\n '/canada': 4,\r\n '/gac': 5,\r\n '/carleton': 6,\r\n}\r\n\r\nfunction normalizeOrgId(org?: number | string | null) {\r\n if (org === null || org === undefined) return undefined\r\n const parsed = typeof org === 'number' ? org : Number.parseInt(String(org), 10)\r\n return Number.isFinite(parsed) ? parsed : undefined\r\n}\r\n\r\nfunction getOrgVisibilityFromPath(pathname?: string | null): OrgVisibility {\r\n const normalizedPath = (pathname || '').toLowerCase()\r\n const firstSegment = normalizedPath.split('/').filter(Boolean)[0]\r\n const prefix = firstSegment ? `/${firstSegment}` : ''\r\n\r\n if (prefix === '/cdt') {\r\n return {\r\n isAdmin: true,\r\n currentOrgId: 1,\r\n allowedOrgIds: ADMIN_ALLOWED_ORGS,\r\n }\r\n }\r\n\r\n const currentOrgId = ORG_BY_PATH_PREFIX[prefix] ?? 2\r\n const allowedOrgIds = Array.from(new Set([2, currentOrgId]))\r\n\r\n return {\r\n isAdmin: false,\r\n currentOrgId,\r\n allowedOrgIds,\r\n }\r\n}\r\n\r\nfunction datasetVisibleForOrg(dataset: Dataset, visibility: OrgVisibility) {\r\n if (visibility.isAdmin) return true\r\n if (dataset.group !== DatasetGroup.Organizational) return true\r\n\r\n const orgId = normalizeOrgId(dataset.organization)\r\n if (orgId === undefined) return false\r\n\r\n return visibility.allowedOrgIds.includes(orgId)\r\n}\r\n\r\n\r\ntype DatasetsProps = {\r\n isOpen: boolean\r\n setIsOpenAction: (open: boolean) => void\r\n}\r\n\r\nexport default function Datasets({ isOpen, setIsOpenAction }: DatasetsProps) {\r\n // Translation\r\n const t = useTranslations('Datasets')\r\n\r\n // Permissions\r\n const { ability } = usePermissions()\r\n\r\n const datasetColumns = useColumns()\r\n\r\n // Contexts\r\n const { state: mapState } = useMapContext()\r\n const { currentLocation } = mapState.map\r\n const { state: appConfigState } = useAppConfigContext()\r\n const orgCountry = (appConfigState.appConfig.organization?.country || '').toUpperCase()\r\n const org = appConfigState.appConfig.organization\r\n // Fall back to org fixed location when currentLocation hasn't been set yet (e.g. before map hover)\r\n const municipality = currentLocation?.municipality ?? org?.municipality ?? null\r\n const countrySubdivision = currentLocation?.countrySubdivision ?? org?.countrySubdivision ?? null\r\n const { state: datasetState, dispatch: datasetDispatch } = React.useContext(DatasetsContext)\r\n const { addedDatasets } = datasetState.datasets\r\n const { state: menusState } = React.useContext(MenusContext)\r\n const { rowsPerPage } = menusState.menus\r\n\r\n const pathname = usePathname()\r\n const orgVisibility = React.useMemo(() => getOrgVisibilityFromPath(pathname), [pathname])\r\n\r\n // UI State\r\n const [view, setView] = React.useState<'table' | 'detail'>('table')\r\n const [selectedDataset, setSelectedDataset] = React.useState<Dataset | null>(null)\r\n const [favouriteDatasets, setFavouriteDatasets] = React.useState<Dataset[]>([])\r\n const [searchTerm, setSearchTerm] = React.useState('')\r\n const [appliedFilters, setAppliedFilters] = React.useState<{ countrySubdivisions: string[], municipalities: string[], types: string[], sources: string[] }>({ countrySubdivisions: [], municipalities: [], types: [], sources: [] })\r\n const [currentTab, setCurrentTab] = React.useState('all')\r\n const [isAddPortalOpen, setIsAddPortalOpen] = React.useState(false)\r\n // Open-data datasets already published to Martin tiles, keyed by\r\n // \"{portalId}:{datasetId}\". Lets the original portal entry (National/Applied/\r\n // All tabs) show as converted, not just the organizational-list copy.\r\n const [publishedCatalog, setPublishedCatalog] = React.useState<Map<string, PublishedCatalogEntry>>(new Map())\r\n const showMunicipalTab = React.useMemo(() => Boolean(municipality), [municipality])\r\n\r\n const { openDataPortals: municipalPortals } = useOpenDataPortalsByMunicipality(municipality)\r\n const { openDataPortals: subdivisionPortals } = useOpenDataPortalsByCountrySubdivision(countrySubdivision)\r\n const { openDataPortals: nationalPortals } = useOpenDataPortalsByGroup(DatasetGroup.National)\r\n\r\n // Belt-and-suspenders country guard: portal.country must match org, or be unset (legacy/global)\r\n const matchesOrgCountry = React.useCallback(\r\n (portalCountry: string | null | undefined) => {\r\n if (!orgCountry) return true // org country unknown — show everything\r\n if (!portalCountry) return true // portal has no country set — treat as global\r\n return portalCountry.toUpperCase() === orgCountry\r\n },\r\n [orgCountry],\r\n )\r\n\r\n const filteredMunicipalPortals = React.useMemo(() => {\r\n if (!Array.isArray(municipalPortals)) return []\r\n const filtered = municipalPortals.filter(p => matchesOrgCountry(p.country))\r\n return filtered\r\n }, [municipalPortals, matchesOrgCountry, municipality])\r\n const filteredSubdivisionPortals = React.useMemo(\r\n () => (Array.isArray(subdivisionPortals)\r\n ? subdivisionPortals.filter(p => p.municipality == null && matchesOrgCountry(p.country))\r\n : []),\r\n [subdivisionPortals, matchesOrgCountry],\r\n )\r\n const filteredNationalPortals = React.useMemo(() => {\r\n if (!Array.isArray(nationalPortals)) return []\r\n const filtered = nationalPortals.filter(p => matchesOrgCountry(p.country))\r\n return filtered\r\n }, [nationalPortals, orgCountry, matchesOrgCountry])\r\n\r\n const municipal = useDatasetsForPortals(filteredMunicipalPortals, { rowsPerPage })\r\n const subdivision = useDatasetsForPortals(filteredSubdivisionPortals, { rowsPerPage })\r\n const national = useDatasetsForPortals(filteredNationalPortals, { rowsPerPage })\r\n React.useEffect(() => {\r\n const loadOrganizationalDatasets = async () => {\r\n // First, refresh the published-catalog lookup (a fast /api/files read) so\r\n // converted open-data datasets flip promptly across every tab — ahead of\r\n // the slower Martin tile-sampling below. Non-fatal on failure.\r\n try {\r\n const filesRes = await fetch('/api/files')\r\n if (filesRes.ok) {\r\n const body = await filesRes.json()\r\n const rows = Array.isArray(body?.files) ? body.files : []\r\n setPublishedCatalog(buildPublishedCatalogMap(rows))\r\n }\r\n }\r\n catch (err) {\r\n console.warn('Failed to refresh published-catalog map:', err)\r\n }\r\n\r\n // Two parallel sources: Martin vector tiles (if configured) and MinIO-\r\n // backed GeoJSON uploads (the \"Add Dataset\" path). Errors from either\r\n // are isolated so a failure on one side does not block the other.\r\n const martinBaseUrl = process.env.NEXT_PUBLIC_MARTIN_SERVER_URL?.replace(/\\/+$/, '')\r\n\r\n const martinPromise: Promise<Dataset[]> = martinBaseUrl\r\n ? (async () => {\r\n const datasetsUrl = martinBaseUrl.includes('/tiles/index.json')\r\n ? martinBaseUrl\r\n : `${martinBaseUrl}/tiles/index.json`\r\n\r\n const localPortal = {\r\n id: -1,\r\n name: 'Organizational Datasets',\r\n apiUrl: datasetsUrl,\r\n dataManagementSystem: 'Other' as const,\r\n countrySubdivision: null,\r\n municipality: null,\r\n group: 'Organizational' as const,\r\n }\r\n\r\n try {\r\n return await fetchLocalDatasets(localPortal as any)\r\n }\r\n catch (err) {\r\n console.error('Failed to load Martin organizational datasets:', err)\r\n return []\r\n }\r\n })()\r\n : Promise.resolve([])\r\n\r\n if (!martinBaseUrl) {\r\n console.warn('NEXT_PUBLIC_MARTIN_SERVER_URL not configured — skipping Martin pre-load')\r\n }\r\n\r\n // The MinIO key prefix is the *session* organization (set server-side\r\n // by the upload route), not orgVisibility.currentOrgId (which is\r\n // path-derived and hardcoded for admin routes like /cdt).\r\n const sessionOrgId = typeof org?.id === 'number'\r\n ? org.id\r\n : Number.parseInt(String(org?.id ?? ''), 10)\r\n\r\n // Martin must resolve first so MinIO suppression can check live catalog\r\n // membership — prevents \"file disappeared\" during the publish→restart gap.\r\n const martinDatasets = await martinPromise\r\n const publishedTilesInCatalog = new Set<string>(\r\n martinDatasets.map(d => typeof d.id === 'string' ? d.id : '').filter(Boolean),\r\n )\r\n\r\n const minioDatasets: Dataset[] = Number.isFinite(sessionOrgId)\r\n ? await fetchOrganizationalMinioDatasets(sessionOrgId, publishedTilesInCatalog).catch((err) => {\r\n console.error('Failed to load MinIO organizational datasets:', err)\r\n return []\r\n })\r\n : []\r\n\r\n const combined = [...martinDatasets, ...minioDatasets]\r\n const visibleOrgDatasets = combined.filter(ds => datasetVisibleForOrg(ds, orgVisibility))\r\n\r\n if (visibleOrgDatasets.length === 0) {\r\n console.warn('No organizational datasets found')\r\n }\r\n datasetDispatch({\r\n type: 'SET_DATASETS',\r\n payload: { datasets: visibleOrgDatasets },\r\n })\r\n }\r\n\r\n loadOrganizationalDatasets()\r\n }, [datasetDispatch, orgVisibility, org?.id, datasetState.datasets.orgRefreshNonce])\r\n\r\n // Stamp each portal list with published-tile identity so a converted open-data\r\n // dataset shows as converted on its own tab (National/Subdivision/Municipal),\r\n // not only on the organizational tab. No-op for unpublished datasets.\r\n const nationalDatasets = React.useMemo(() => stampPublished(national.datasets, publishedCatalog), [national.datasets, publishedCatalog])\r\n const subdivisionDatasets = React.useMemo(() => stampPublished(subdivision.datasets, publishedCatalog), [subdivision.datasets, publishedCatalog])\r\n const municipalDatasets = React.useMemo(() => stampPublished(municipal.datasets, publishedCatalog), [municipal.datasets, publishedCatalog])\r\n\r\n const isLoadingNational = national.isLoading && nationalDatasets.length === 0\r\n const isLoadingSubdivision = subdivision.isLoading && subdivisionDatasets.length === 0\r\n const isLoadingMunicipal = municipal.isLoading && municipalDatasets.length === 0\r\n\r\n const datasetsError = React.useMemo(() => {\r\n if (currentTab === 'municipal' && municipal.isError && municipalDatasets.length === 0) return t('failedFetchError')\r\n if (currentTab === 'countrySubdivision' && subdivision.isError && subdivisionDatasets.length === 0) return t('failedFetchError')\r\n if (currentTab === 'national' && national.isError && nationalDatasets.length === 0) return t('failedFetchError')\r\n return null\r\n }, [currentTab, municipal.isError, municipalDatasets.length, subdivision.isError, subdivisionDatasets.length, national.isError, nationalDatasets.length, t])\r\n\r\n const allDatasets = React.useMemo(() => {\r\n const unfiltered = [\r\n ...builtinLiveDatasets, // curated live feeds (e.g. GeoMet weather radar) → Live Data tab\r\n ...nationalDatasets,\r\n ...subdivisionDatasets,\r\n ...municipalDatasets,\r\n ...addedDatasets,\r\n ...(datasetState.datasets.datasets || []),\r\n ]\r\n\r\n const filtered = unfiltered.filter(ds => datasetVisibleForOrg(ds, orgVisibility))\r\n\r\n // Also stamp here so the addedDatasets snapshot (applied at add-time, before\r\n // conversion) and any org-list entries pick up published identity on the\r\n // Applied/All tabs. Already-stamped portal entries are unchanged.\r\n return stampPublished(filtered, publishedCatalog)\r\n }, [nationalDatasets, subdivisionDatasets, municipalDatasets, datasetState.datasets.datasets, addedDatasets, orgVisibility, publishedCatalog])\r\n\r\n const currentTabLoading = React.useMemo(() => {\r\n switch (currentTab) {\r\n case 'national':\r\n return isLoadingNational\r\n case 'countrySubdivision':\r\n return isLoadingSubdivision\r\n case 'municipal':\r\n return isLoadingMunicipal\r\n case 'all':\r\n // Show loading for \"all\" if any datasets are loading and we have no data yet\r\n return (isLoadingNational || isLoadingSubdivision || isLoadingMunicipal) && \r\n allDatasets.length === 0\r\n case 'organizational':\r\n // Show loading for \"organizational\" if any datasets are loading and we have no organizational data yet\r\n return (isLoadingNational || isLoadingSubdivision || isLoadingMunicipal) && \r\n allDatasets.filter(ds => ds.group === 'Organizational').length === 0\r\n default:\r\n return false\r\n }\r\n }, [currentTab, isLoadingNational, isLoadingSubdivision, isLoadingMunicipal, allDatasets])\r\n\r\n React.useEffect(() => {\r\n if (!showMunicipalTab && currentTab === 'municipal') {\r\n setCurrentTab('all')\r\n }\r\n }, [showMunicipalTab, currentTab])\r\n\r\n // Memoized datasets for current tab\r\n const currentTabDatasets = React.useMemo(() => {\r\n switch (currentTab) {\r\n case 'applied':\r\n return allDatasets.filter(ds => addedDatasets.some(d => d.name === ds.name))\r\n case 'favourites':\r\n return allDatasets.filter(ds => favouriteDatasets.some(fav => fav.name === ds.name))\r\n case 'organizational':\r\n return allDatasets.filter(ds => ds.group === 'Organizational')\r\n case 'liveData':\r\n return allDatasets.filter(ds => ds.portal?.live === true)\r\n case 'national':\r\n return nationalDatasets\r\n case 'countrySubdivision':\r\n return subdivisionDatasets\r\n case 'municipal':\r\n return municipalDatasets\r\n case 'all':\r\n default:\r\n return allDatasets\r\n }\r\n }, [currentTab, allDatasets, addedDatasets, favouriteDatasets, nationalDatasets, subdivisionDatasets, municipalDatasets])\r\n\r\n // Memoized filtered data\r\n const filteredData = React.useMemo(() => {\r\n return currentTabDatasets.filter((dataset) => {\r\n // Search filter\r\n const matchesSearch = Object.values(dataset).some(value =>\r\n String(value).toLowerCase().includes(searchTerm.toLowerCase()),\r\n )\r\n if (!matchesSearch)\r\n return false\r\n\r\n // Country subdivision filter\r\n const matchesSubdivision\r\n = appliedFilters.countrySubdivisions.length === 0\r\n || !dataset.countrySubdivision\r\n || appliedFilters.countrySubdivisions.includes(dataset.countrySubdivision)\r\n\r\n // Municipality filter\r\n const matchesMunicipality\r\n = appliedFilters.municipalities.length === 0\r\n || !dataset.municipality\r\n || appliedFilters.municipalities.includes(dataset.municipality)\r\n\r\n // Type filter\r\n const matchesType\r\n = appliedFilters.types.length === 0\r\n || appliedFilters.types.includes(dataset.type)\r\n\r\n // Source filter (dataset.portal?.name, falling back to publisher)\r\n const datasetSource = dataset.portal?.name ?? dataset.publisher\r\n const matchesSource\r\n = appliedFilters.sources.length === 0\r\n || (datasetSource ? appliedFilters.sources.includes(datasetSource) : false)\r\n\r\n return matchesSubdivision && matchesMunicipality && matchesType && matchesSource\r\n })\r\n }, [currentTabDatasets, searchTerm, appliedFilters])\r\n\r\n const sortedFilteredData = React.useMemo(() => {\r\n // Remove duplicates by name\r\n const uniqueByName = new Map<string, Dataset>()\r\n for (const ds of filteredData) {\r\n const name = ds.name?.toLowerCase() || ''\r\n if (!uniqueByName.has(name)) {\r\n uniqueByName.set(name, ds)\r\n }\r\n }\r\n\r\n // Filter out unwanted names/types\r\n const filtered = [...uniqueByName.values()].filter((ds) => {\r\n const name = ds.name?.toLowerCase() || ''\r\n const type = ds.type?.toLowerCase() || ''\r\n return !name.includes('basemap') && !type.includes('geocoding')\r\n })\r\n\r\n // HARD CODE BLOCK LIST\r\n const blocklisted = (ds: Dataset) => {\r\n const url = (ds.url || '').toLowerCase()\r\n const name = (ds.name || '').toLowerCase()\r\n return (\r\n url.includes('/2021_statistics_canada_boundaries/featureserver')\r\n || name.includes('2021 statistics canada boundaries')\r\n || url.includes('/limites_du_recensement_de_statistique_canada_(2021)/featureserver')\r\n || name.includes('limites du recensement de statistique canada (2021)')\r\n )\r\n }\r\n\r\n const safe = filtered.filter(ds => !blocklisted(ds))\r\n\r\n // Sort by name\r\n return safe.sort((a, b) =>\r\n (a.name || '').localeCompare(b.name || ''),\r\n )\r\n }, [filteredData])\r\n\r\n const { prefetch } = useFastDatasetCache()\r\n\r\n React.useEffect(() => {\r\n if (isOpen && sortedFilteredData.length > 0) {\r\n const datasetsToPreload = sortedFilteredData.slice(0, 10)\r\n datasetsToPreload.forEach((dataset, index) => {\r\n setTimeout(() => {\r\n prefetch(dataset)\r\n }, index * 200)\r\n })\r\n }\r\n }, [isOpen, sortedFilteredData, prefetch])\r\n\r\n // Handlers\r\n const handleTabChange = React.useCallback((value: string) => setCurrentTab(value), [])\r\n const handleRowClick = React.useCallback((dataset: Dataset) => {\r\n setSelectedDataset(dataset)\r\n setView('detail')\r\n }, [])\r\n const handleRowHover = React.useCallback((dataset: Dataset) => {\r\n prefetch(dataset)\r\n \r\n const currentIndex = sortedFilteredData.indexOf(dataset)\r\n if (currentIndex >= 0 && currentIndex < sortedFilteredData.length - 2) {\r\n setTimeout(() => {\r\n if (sortedFilteredData[currentIndex + 1]) {\r\n prefetch(sortedFilteredData[currentIndex + 1])\r\n }\r\n }, 100)\r\n }\r\n }, [prefetch, sortedFilteredData])\r\n const handleBackToTable = React.useCallback(() => {\r\n setView('table')\r\n setSelectedDataset(null)\r\n }, [])\r\n const handleAddDatasetToMap = React.useCallback(() => {\r\n if (selectedDataset) {\r\n datasetDispatch({ type: 'ADD_DATASET_TO_MAP', payload: { dataset: selectedDataset } })\r\n }\r\n }, [selectedDataset, datasetDispatch])\r\n const handleRemoveDatasetFromMap = React.useCallback(() => {\r\n if (selectedDataset) {\r\n datasetDispatch({ type: 'REMOVE_DATASET_FROM_MAP', payload: { datasetId: selectedDataset.id } })\r\n }\r\n }, [selectedDataset, datasetDispatch])\r\n const handleFavourite = handleFavouriteDataset(selectedDataset, favouriteDatasets, setFavouriteDatasets)\r\n\r\n const handleAddDataset = () => {\r\n // Logic to add a new dataset\r\n }\r\n\r\n // UI\r\n return (\r\n <Dialog open={isOpen} onOpenChange={setIsOpenAction}>\r\n <DialogContent className=\"h-screen sm:h-[90vh] sm:max-h-[90vh] w-full max-w-full sm:w-[88vw] sm:max-w-[88vw] p-0 gap-0 overflow-hidden flex flex-col\">\r\n {view === 'table' ? (\r\n <>\r\n <DialogHeader className=\"bg-background z-50 sticky top-0 p-6 flex flex-row flex-wrap justify-between items-end gap-2 text-left\">\r\n <div className=\"flex flex-col justify-end p-0\">\r\n <DialogTitle className=\"text-2xl\">{t('dialogTitle')}</DialogTitle>\r\n <DialogDescription className=\"text-sm\">\r\n {t('dialogDescription')}\r\n </DialogDescription>\r\n </div>\r\n <div className=\"flex flex-row flex-wrap justify-between items-center\">\r\n <div className=\"flex flex-wrap gap-2 font-medium\">\r\n <div className=\"relative\">\r\n <LR.Search className=\"absolute left-3 top-2.5 h-4 w-4 text-muted-foreground\" />\r\n <Input\r\n placeholder=\"Search\"\r\n className=\"pl-8 w-[250px]\"\r\n value={searchTerm}\r\n onChange={e => setSearchTerm(e.target.value)}\r\n disabled={!ability.can('read', 'File')}\r\n />\r\n </div>\r\n <div className=\"flex gap-2\">\r\n <Filters\r\n datasets={currentTabDatasets}\r\n appliedFilters={appliedFilters}\r\n onFiltersChange={setAppliedFilters}\r\n />\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n onClick={() => setIsAddPortalOpen(true)}\r\n title=\"Register a new open data portal\"\r\n >\r\n <LR.Plus className=\"h-4 w-4 mr-1\" />\r\n Add Portal\r\n </Button>\r\n </div>\r\n </div>\r\n </div>\r\n <DialogClose className=\"absolute right-2 top-2 h-5 w-5 rounded-xl text-muted-foreground hover:bg-transparent focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-background focus:ring-primary\">\r\n <LR.X className=\"!h-4 !w-4\" />\r\n </DialogClose>\r\n </DialogHeader>\r\n <div className=\"relative flex flex-col flex-1 min-h-0\">\r\n <Tabs value={currentTab} className=\"flex flex-col gap-0 h-full\" onValueChange={handleTabChange}>\r\n <div className=\"hidden md:!flex justify-between px-3 flex-shrink-0\">\r\n {' '}\r\n {/* Prevent tabs from shrinking */}\r\n <TabsList className=\"pointer-events-auto sticky flex z-40 top-[100px] bg-transparent\">\r\n <TabsTrigger className=\"hover:text-foreground gap-2\" value=\"applied\">\r\n <Badge variant=\"outline\">{addedDatasets.length}</Badge>\r\n {t('appliedTab')}\r\n </TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground gap-2\" value=\"favourites\">\r\n {t('favoritesTab')}\r\n </TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"organizational\">{t('organizationalTab')}</TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"all\">{t('allDataTab')}</TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"national\">{t('nationalTab')}</TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"countrySubdivision\">{t('countrySubdivisionTab')}</TabsTrigger>\r\n {showMunicipalTab && (\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"municipal\">{t('municipalTab')}</TabsTrigger>\r\n )}\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"liveData\">{t('liveDataTab')}</TabsTrigger>\r\n </TabsList>\r\n </div>\r\n <TabsContent\r\n value={currentTab}\r\n className=\"flex-1 pointer-events-auto mt-0 min-h-0\" // min-h-0 is crucial for flex children\r\n >\r\n {currentTabLoading ? (\r\n <DatasetSkeleton />\r\n ) : (datasetsError ? (\r\n <div className=\"flex flex-col justify-center items-center h-32 text-muted-foreground\">\r\n <LR.AlertCircle className=\"h-6 w-6 mb-2\" />\r\n <span>{datasetsError}</span>\r\n <Button variant=\"outline\" size=\"sm\" onClick={() => window.location.reload()} className=\"mt-2\">\r\n <LR.RefreshCw className=\"h-4 w-4 mr-2\" />\r\n {t('refreshButton')}\r\n </Button>\r\n </div>\r\n ) : (\r\n <DataTable\r\n showPagination={true}\r\n columns={datasetColumns}\r\n data={sortedFilteredData}\r\n tab={currentTab}\r\n onRowClick={handleRowClick}\r\n onRowHover={handleRowHover}\r\n className=\"rounded-none w-auto h-full\" \r\n paginationClasses=\"bg-background z-20 w-full border-t\" \r\n isLoading={currentTabLoading}\r\n leadingCell={props => (\r\n <RowActions\r\n {...props}\r\n favouriteDatasets={favouriteDatasets}\r\n setFavouriteDatasets={setFavouriteDatasets}\r\n />\r\n )}\r\n trailingCell={({ row, index }) => (\r\n <div>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"pointer-events-none\"\r\n >\r\n <LR.ChevronRight />\r\n </Button>\r\n </div>\r\n )}\r\n />\r\n ))}\r\n </TabsContent>\r\n </Tabs>\r\n </div>\r\n </>\r\n ) : (\r\n // Detail View Content\r\n <>\r\n <DialogHeader className=\"px-6 pt-6\">\r\n <div>\r\n <Breadcrumb>\r\n <BreadcrumbList>\r\n <BreadcrumbItem>\r\n <BreadcrumbLink\r\n href=\"#\"\r\n onClick={() => {\r\n handleBackToTable()\r\n setCurrentTab('all')\r\n }}\r\n >\r\n {t('breadcrumbTitle')}\r\n </BreadcrumbLink>\r\n </BreadcrumbItem>\r\n <BreadcrumbSeparator />\r\n <BreadcrumbItem>\r\n <BreadcrumbLink\r\n href=\"#\"\r\n onClick={() => {\r\n setCurrentTab(currentTab)\r\n handleBackToTable()\r\n }}\r\n >\r\n {currentTab.charAt(0).toUpperCase() + currentTab.slice(1)}\r\n </BreadcrumbLink>\r\n </BreadcrumbItem>\r\n <BreadcrumbSeparator />\r\n <BreadcrumbItem>\r\n <BreadcrumbPage>{selectedDataset?.name}</BreadcrumbPage>\r\n </BreadcrumbItem>\r\n </BreadcrumbList>\r\n </Breadcrumb>\r\n </div>\r\n <div className=\"flex flex-row justify-between\">\r\n <div className=\"flex items-center\">\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className={`opacity-70 hover:opacity-100 transition-opacity duration-200 hover:bg-transparent ${selectedDataset && favouriteDatasets.includes(selectedDataset) ? 'opacity-100' : ''}`}\r\n onClick={handleFavourite}\r\n >\r\n <LR.Star\r\n className=\"!h-5 !w-5\"\r\n size={24}\r\n color={`${selectedDataset && favouriteDatasets.includes(selectedDataset) ? 'hsl(var(--chart-5))' : 'black'} `}\r\n fill={`${selectedDataset && favouriteDatasets.includes(selectedDataset) ? 'hsl(var(--chart-5))' : 'none'} `}\r\n />\r\n </Button>\r\n <DialogTitle>{selectedDataset?.name}</DialogTitle>\r\n </div>\r\n <div className=\"flex gap-2\">\r\n <Button\r\n variant=\"secondary\"\r\n onClick={handleBackToTable}\r\n >\r\n <LR.ArrowLeft />\r\n {t('backToDataButton')}\r\n </Button>\r\n {selectedDataset && addedDatasets.some(d => d.name === selectedDataset.name)\r\n ? (\r\n <Button onClick={handleRemoveDatasetFromMap} disabled={!ability.can('read', 'File')}>\r\n <LR.Minus />\r\n {t('removeButton')}\r\n </Button>\r\n )\r\n : (\r\n <Button onClick={handleAddDatasetToMap} disabled={!ability.can('read', 'File')}>\r\n <LR.Plus />\r\n {t('applyButton')}\r\n </Button>\r\n )}\r\n </div>\r\n </div>\r\n </DialogHeader>\r\n <DatasetDetails selectedDataset={selectedDataset} />\r\n </>\r\n )}\r\n </DialogContent>\r\n <AddPortalDialog open={isAddPortalOpen} onOpenChange={setIsAddPortalOpen} />\r\n </Dialog>\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","_b"]}
@@ -0,0 +1,4 @@
1
+ import type { Dataset } from '../../../../../types/datasetTypes';
2
+ /** Built-in live datasets, injected into the manager so the Live Data tab has real content. */
3
+ export declare const builtinLiveDatasets: Dataset[];
4
+ //# sourceMappingURL=builtinLiveDatasets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtinLiveDatasets.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/datasets/src/builtinLiveDatasets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAA;AA4DhE,+FAA+F;AAC/F,eAAO,MAAM,mBAAmB,EAAE,OAAO,EAAmB,CAAA"}
@@ -0,0 +1,43 @@
1
+ import { DatasetGroup } from "../../../../../types/dbTypes";
2
+ import { layerColorByName } from "../../utils/stringToColour";
3
+ import { buildWmsTileUrl } from "./urlSources";
4
+ const GEOMET_WMS_URL = process.env.NEXT_PUBLIC_GEOMET_WMS_URL || "https://geo.weather.gc.ca/geomet";
5
+ const liveWeatherPortal = {
6
+ id: -1001,
7
+ // synthetic — built-in, never persisted
8
+ name: "ECCC \xB7 MSC GeoMet",
9
+ group: DatasetGroup.National,
10
+ dataManagementSystem: "Other",
11
+ apiUrl: GEOMET_WMS_URL,
12
+ country: "Canada",
13
+ live: true
14
+ };
15
+ const emptyFeatures = async () => ({ type: "FeatureCollection", features: [] });
16
+ const weatherRadar = {
17
+ id: "live-weather-radar",
18
+ name: "Live Weather Radar (Canada)",
19
+ publisher: "Environment and Climate Change Canada \xB7 MSC GeoMet",
20
+ description: "Live precipitation radar (RADAR_1KM_RRAI) \u2014 rain rate, latest frame served ~every 6 minutes.",
21
+ dataManagementSystem: "other",
22
+ datasetType: "WMS",
23
+ type: "WMS",
24
+ countrySubdivision: "",
25
+ municipality: "",
26
+ group: DatasetGroup.National,
27
+ clickable: false,
28
+ // MapLibre raster tile template; {bbox-epsg-3857} stays literal (substituted per tile).
29
+ url: buildWmsTileUrl(GEOMET_WMS_URL, "RADAR_1KM_RRAI"),
30
+ // Time-enabled: WMSDatasetLayer animates the WMS TIME dimension via the scrub/play control.
31
+ timeEnabled: true,
32
+ wms: { baseUrl: GEOMET_WMS_URL, layers: "RADAR_1KM_RRAI" },
33
+ information: "https://eccc-msc.github.io/open-data/msc-geomet/readme_en/",
34
+ portal: liveWeatherPortal,
35
+ layerColor: layerColorByName("Live Weather Radar"),
36
+ getFields: async () => [],
37
+ getFeatures: emptyFeatures
38
+ };
39
+ const builtinLiveDatasets = [weatherRadar];
40
+ export {
41
+ builtinLiveDatasets
42
+ };
43
+ //# sourceMappingURL=builtinLiveDatasets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../../../src/core/components/viewers/map/datasets/src/builtinLiveDatasets.ts"],"sourcesContent":["import type { Dataset } from '../../../../../types/datasetTypes'\r\nimport { DatasetGroup, type OpenDataPortal } from '../../../../../types/dbTypes'\r\nimport { layerColorByName } from '../../utils/stringToColour'\r\nimport { buildWmsTileUrl } from './urlSources'\r\nimport type { AllGeoJSON } from '@turf/turf'\r\n\r\n/**\r\n * Curated \"live\" datasets surfaced in the dataset manager's Live Data tab.\r\n *\r\n * Unlike portal-fetched datasets these are defined in code: a small, known set\r\n * of always-current federated feeds. The first is Environment and Climate Change\r\n * Canada's precipitation radar (MSC GeoMet) — a WMS raster of rain rate, the\r\n * server always serving the latest frame (refreshed ~every 6 minutes). Federated\r\n * and Canadian-governed: nothing of ours egresses, the browser fetches GeoMet\r\n * raster tiles directly.\r\n *\r\n * Each entry carries `portal.live === true` — the only thing the Live Data tab\r\n * filters on — and renders through the WMS branch of OpenDataLayer.\r\n */\r\n\r\nconst GEOMET_WMS_URL =\r\n process.env.NEXT_PUBLIC_GEOMET_WMS_URL || 'https://geo.weather.gc.ca/geomet'\r\n\r\nconst liveWeatherPortal: OpenDataPortal = {\r\n id: -1001, // synthetic — built-in, never persisted\r\n name: 'ECCC · MSC GeoMet',\r\n group: DatasetGroup.National,\r\n dataManagementSystem: 'Other',\r\n apiUrl: GEOMET_WMS_URL,\r\n country: 'Canada',\r\n live: true,\r\n}\r\n\r\nconst emptyFeatures = async (): Promise<AllGeoJSON> =>\r\n ({ type: 'FeatureCollection', features: [] } as AllGeoJSON)\r\n\r\nconst weatherRadar: Dataset = {\r\n id: 'live-weather-radar',\r\n name: 'Live Weather Radar (Canada)',\r\n publisher: 'Environment and Climate Change Canada · MSC GeoMet',\r\n description: 'Live precipitation radar (RADAR_1KM_RRAI) — rain rate, latest frame served ~every 6 minutes.',\r\n dataManagementSystem: 'other',\r\n datasetType: 'WMS',\r\n type: 'WMS',\r\n countrySubdivision: '',\r\n municipality: '',\r\n group: DatasetGroup.National,\r\n clickable: false,\r\n // MapLibre raster tile template; {bbox-epsg-3857} stays literal (substituted per tile).\r\n url: buildWmsTileUrl(GEOMET_WMS_URL, 'RADAR_1KM_RRAI'),\r\n // Time-enabled: WMSDatasetLayer animates the WMS TIME dimension via the scrub/play control.\r\n timeEnabled: true,\r\n wms: { baseUrl: GEOMET_WMS_URL, layers: 'RADAR_1KM_RRAI' },\r\n information: 'https://eccc-msc.github.io/open-data/msc-geomet/readme_en/',\r\n portal: liveWeatherPortal,\r\n layerColor: layerColorByName('Live Weather Radar'),\r\n getFields: async () => [],\r\n getFeatures: emptyFeatures,\r\n}\r\n\r\n/** Built-in live datasets, injected into the manager so the Live Data tab has real content. */\r\nexport const builtinLiveDatasets: Dataset[] = [weatherRadar]\r\n"],"mappings":"AACA,SAAS,oBAAyC;AAClD,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAiBhC,MAAM,iBACJ,QAAQ,IAAI,8BAA8B;AAE5C,MAAM,oBAAoC;AAAA,EACxC,IAAI;AAAA;AAAA,EACJ,MAAM;AAAA,EACN,OAAO,aAAa;AAAA,EACpB,sBAAsB;AAAA,EACtB,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AACR;AAEA,MAAM,gBAAgB,aACnB,EAAE,MAAM,qBAAqB,UAAU,CAAC,EAAE;AAE7C,MAAM,eAAwB;AAAA,EAC5B,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,WAAW;AAAA,EACX,aAAa;AAAA,EACb,sBAAsB;AAAA,EACtB,aAAa;AAAA,EACb,MAAM;AAAA,EACN,oBAAoB;AAAA,EACpB,cAAc;AAAA,EACd,OAAO,aAAa;AAAA,EACpB,WAAW;AAAA;AAAA,EAEX,KAAK,gBAAgB,gBAAgB,gBAAgB;AAAA;AAAA,EAErD,aAAa;AAAA,EACb,KAAK,EAAE,SAAS,gBAAgB,QAAQ,iBAAiB;AAAA,EACzD,aAAa;AAAA,EACb,QAAQ;AAAA,EACR,YAAY,iBAAiB,oBAAoB;AAAA,EACjD,WAAW,YAAY,CAAC;AAAA,EACxB,aAAa;AACf;AAGO,MAAM,sBAAiC,CAAC,YAAY;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"localDatasets.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/datasets/src/localDatasets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgC,MAAM,mCAAmC,CAAA;AAE9F,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAoXhF,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,OAAO,EAAE,CAAC,CA+LpB"}
1
+ {"version":3,"file":"localDatasets.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/datasets/src/localDatasets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAgC,MAAM,mCAAmC,CAAA;AAE9F,OAAO,EAAgB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAkahF,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,OAAO,EAAE,CAAC,CA+LpB"}
@@ -23,6 +23,7 @@ import { layerColorByName } from "../../utils/stringToColour";
23
23
  import Pbf from "pbf";
24
24
  import { VectorTile } from "@mapbox/vector-tile";
25
25
  import { getCache, setCache } from "./cache";
26
+ import { isPublishedOrgTable, buildPublishedTileDatasets } from "./publishedTiles";
26
27
  const ORGANIZATION_FIELD = "organization";
27
28
  function normalizeMartinBaseUrl(apiUrl) {
28
29
  return apiUrl.replace(/\/+$/, "");
@@ -154,6 +155,28 @@ async function resolveDatasetOrganization(tile) {
154
155
  geometryType: fromTile == null ? void 0 : fromTile.geometryType
155
156
  };
156
157
  }
158
+ async function fetchPublishedTileLabels() {
159
+ try {
160
+ const res = await fetch("/api/files");
161
+ if (!res.ok) return /* @__PURE__ */ new Map();
162
+ const body = await res.json();
163
+ const rows = Array.isArray(body == null ? void 0 : body.files) ? body.files : [];
164
+ const map = /* @__PURE__ */ new Map();
165
+ for (const row of rows) {
166
+ if (!(row == null ? void 0 : row.description) || !(row == null ? void 0 : row.name)) continue;
167
+ try {
168
+ const desc = JSON.parse(row.description);
169
+ if (typeof (desc == null ? void 0 : desc.tiledTable) === "string") {
170
+ map.set(desc.tiledTable, row.name.replace(/\.geojson$/i, ""));
171
+ }
172
+ } catch (e) {
173
+ }
174
+ }
175
+ return map;
176
+ } catch (e) {
177
+ return /* @__PURE__ */ new Map();
178
+ }
179
+ }
157
180
  async function fetchMartinServerDatasets(portal) {
158
181
  const { countrySubdivision, municipality } = portal;
159
182
  const martinServerUrl = portal.apiUrl;
@@ -164,6 +187,7 @@ async function fetchMartinServerDatasets(portal) {
164
187
  try {
165
188
  console.log("Fetching Martin server catalog from:", martinServerUrl);
166
189
  const { indexUrl, tileBaseUrl, fallbackCatalogUrl } = resolveMartinUrls(martinServerUrl);
190
+ const publishedLabels = await fetchPublishedTileLabels();
167
191
  let response = await fetch(indexUrl);
168
192
  if (!response.ok && fallbackCatalogUrl && fallbackCatalogUrl !== indexUrl) {
169
193
  console.warn(`Failed to fetch Martin index (${indexUrl}), falling back to catalog...`);
@@ -173,10 +197,11 @@ async function fetchMartinServerDatasets(portal) {
173
197
  throw new Error(`Failed to fetch Martin catalog: ${response.status}`);
174
198
  }
175
199
  const catalog = await response.json();
176
- const tiles = normalizeMartinCatalog(catalog, tileBaseUrl);
200
+ const tiles = normalizeMartinCatalog(catalog, tileBaseUrl).filter((t) => !isPublishedOrgTable(t.tileName) && t.tileName !== "cdt_tiles");
177
201
  console.log("Martin catalog received:", tiles.length, "tiles");
178
202
  const datasets = await Promise.all(tiles.map(async (tileInfo) => {
179
- const cleanName = formatName(
203
+ const publishedLabel = publishedLabels.get(tileInfo.tileName);
204
+ const cleanName = publishedLabel != null ? publishedLabel : formatName(
180
205
  tileInfo.tileName.replace(/_\d{8}$/, "").replace(/__\d+_\d+$/, "")
181
206
  );
182
207
  const { organization, geometryType } = await resolveDatasetOrganization(tileInfo);
@@ -239,7 +264,18 @@ async function fetchMartinServerDatasets(portal) {
239
264
  return dataset;
240
265
  }));
241
266
  console.log(`Transformed ${datasets.length} Martin datasets`);
242
- return datasets;
267
+ let publishedDatasets = [];
268
+ try {
269
+ const fileRes = await fetch("/api/files");
270
+ if (fileRes.ok) {
271
+ const fileBody = await fileRes.json();
272
+ const fileRows = Array.isArray(fileBody == null ? void 0 : fileBody.files) ? fileBody.files : [];
273
+ publishedDatasets = buildPublishedTileDatasets(fileRows, tileBaseUrl, portal);
274
+ }
275
+ } catch (err) {
276
+ console.warn("Failed to build published-tile datasets from /api/files", err);
277
+ }
278
+ return [...datasets, ...publishedDatasets];
243
279
  } catch (error) {
244
280
  console.error("Error fetching Martin server datasets:", error);
245
281
  return [];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../src/core/components/viewers/map/datasets/src/localDatasets.ts"],"sourcesContent":["import type { Dataset, FieldType, LayerGeometryType } from '../../../../../types/datasetTypes'\r\nimport { formatName } from '../utils'\r\nimport { DatasetGroup, type OpenDataPortal } from '../../../../../types/dbTypes'\r\nimport type { AllGeoJSON } from '@turf/turf'\r\nimport { layerColorByName } from '../../utils/stringToColour'\r\nimport Pbf from 'pbf'\r\nimport { VectorTile } from '@mapbox/vector-tile'\r\nimport { getCache, setCache } from './cache'\r\n\r\n\r\n// Define the structure of local dataset items\r\ninterface LocalDatasetItem {\r\n name: string\r\n organization: number\r\n featuresUrl: string\r\n tileName: string\r\n sourceLayer: string\r\n layer: {\r\n type: string\r\n properties: Record<string, string>\r\n }\r\n visible: boolean\r\n clickable: boolean\r\n url: string\r\n description: string\r\n publisher: string\r\n countrySubdivision?: string\r\n municipality?: string\r\n}\r\n\r\ninterface MartinCatalogTile {\r\n content_type: string\r\n description: string\r\n}\r\n\r\ninterface MartinCatalog {\r\n tiles: Record<string, MartinCatalogTile>\r\n}\r\n\r\ninterface MartinTileStatsAttribute {\r\n attribute: string\r\n values?: Array<string | number>\r\n min?: number | string\r\n max?: number | string\r\n}\r\n\r\ninterface MartinTileStatsLayer {\r\n layer: string\r\n attributes?: MartinTileStatsAttribute[]\r\n}\r\n\r\ninterface MartinTileStats {\r\n layers?: MartinTileStatsLayer[]\r\n}\r\n\r\ninterface MartinTileJson {\r\n id?: string\r\n name?: string\r\n description?: string\r\n tiles?: string[]\r\n vector_layers?: Array<{\r\n id: string\r\n description?: string\r\n minzoom?: number\r\n maxzoom?: number\r\n fields?: Record<string, string>\r\n }>\r\n tilestats?: MartinTileStats\r\n minzoom?: number\r\n maxzoom?: number\r\n}\r\n\r\ntype MartinIndexResponse =\r\n | MartinCatalog\r\n | MartinTileJson[]\r\n | { tiles: Record<string, MartinTileJson> }\r\n | { tilesets: MartinTileJson[] }\r\n\r\ninterface NormalizedMartinTile {\r\n tileName: string\r\n tileUrl: string\r\n description?: string\r\n vectorLayerId: string\r\n tilestats?: MartinTileStats\r\n minzoom?: number\r\n}\r\n\r\nconst ORGANIZATION_FIELD = 'organization'\r\n\r\nfunction normalizeMartinBaseUrl(apiUrl: string) {\r\n return apiUrl.replace(/\\/+$/, '')\r\n}\r\n\r\nfunction resolveMartinUrls(apiUrl: string) {\r\n const trimmed = normalizeMartinBaseUrl(apiUrl)\r\n\r\n if (trimmed.endsWith('/tiles/index.json')) {\r\n const tileBaseUrl = trimmed.replace(/\\/tiles\\/index\\.json$/, '')\r\n return {\r\n indexUrl: trimmed,\r\n tileBaseUrl,\r\n fallbackCatalogUrl: `${tileBaseUrl}/catalog`,\r\n }\r\n }\r\n\r\n if (trimmed.endsWith('/catalog')) {\r\n const tileBaseUrl = trimmed.replace(/\\/catalog$/, '')\r\n return {\r\n indexUrl: `${tileBaseUrl}/tiles/index.json`,\r\n tileBaseUrl,\r\n fallbackCatalogUrl: trimmed,\r\n }\r\n }\r\n\r\n return {\r\n indexUrl: `${trimmed}/tiles/index.json`,\r\n tileBaseUrl: trimmed,\r\n fallbackCatalogUrl: `${trimmed}/catalog`,\r\n }\r\n}\r\n\r\nfunction ensureAbsoluteTileUrl(tileUrl: string, tileBaseUrl: string) {\r\n if (/^https?:\\/\\//i.test(tileUrl)) {\r\n return tileUrl\r\n }\r\n\r\n const cleanedBase = tileBaseUrl.replace(/\\/+$/, '')\r\n const cleanedPath = tileUrl.replace(/^\\/+/, '')\r\n return `${cleanedBase}/${cleanedPath}`\r\n}\r\n\r\nfunction normalizeTileInfo(tileInfo: MartinTileJson, fallbackName: string | null, tileBaseUrl: string): NormalizedMartinTile | null {\r\n const tileName = tileInfo.id || tileInfo.name || fallbackName\r\n if (!tileName) return null\r\n\r\n const vectorLayerId = tileInfo.vector_layers?.[0]?.id || tileName\r\n const tileUrlFromInfo = Array.isArray(tileInfo.tiles) && tileInfo.tiles.length > 0\r\n ? tileInfo.tiles[0]\r\n : `${tileBaseUrl}/${tileName}/{z}/{x}/{y}`\r\n\r\n return {\r\n tileName,\r\n tileUrl: ensureAbsoluteTileUrl(tileUrlFromInfo, tileBaseUrl),\r\n description: tileInfo.description || tileInfo.vector_layers?.[0]?.description,\r\n vectorLayerId,\r\n tilestats: tileInfo.tilestats,\r\n minzoom: tileInfo.minzoom || tileInfo.vector_layers?.[0]?.minzoom,\r\n }\r\n}\r\n\r\nfunction normalizeMartinCatalog(response: MartinIndexResponse, tileBaseUrl: string): NormalizedMartinTile[] {\r\n if (Array.isArray(response)) {\r\n return response\r\n .map(tile => normalizeTileInfo(tile, null, tileBaseUrl))\r\n .filter((t): t is NormalizedMartinTile => Boolean(t))\r\n }\r\n\r\n if ('tilesets' in response && Array.isArray(response.tilesets)) {\r\n return response.tilesets\r\n .map(tile => normalizeTileInfo(tile, null, tileBaseUrl))\r\n .filter((t): t is NormalizedMartinTile => Boolean(t))\r\n }\r\n\r\n if ('tiles' in response && response.tiles) {\r\n return Object.entries(response.tiles)\r\n .map(([tileName, tileInfo]) => normalizeTileInfo(tileInfo as MartinTileJson, tileName, tileBaseUrl))\r\n .filter((t): t is NormalizedMartinTile => Boolean(t))\r\n }\r\n\r\n return []\r\n}\r\n\r\nfunction parseOrganizationValue(value: unknown): number | undefined {\r\n if (value == null) return undefined\r\n if (typeof value === 'number' && Number.isFinite(value)) return value\r\n\r\n const parsed = Number.parseInt(String(value), 10)\r\n return Number.isFinite(parsed) ? parsed : undefined\r\n}\r\n\r\nfunction extractOrganizationFromTilestats(tilestats?: MartinTileStats): number | undefined {\r\n if (!tilestats?.layers) return undefined\r\n\r\n for (const layer of tilestats.layers) {\r\n const orgAttribute = layer.attributes?.find(attr =>\r\n attr.attribute?.toLowerCase() === ORGANIZATION_FIELD,\r\n )\r\n\r\n if (!orgAttribute) continue\r\n\r\n if (orgAttribute.values && orgAttribute.values.length > 0) {\r\n const value = parseOrganizationValue(orgAttribute.values[0])\r\n if (value !== undefined) return value\r\n }\r\n\r\n if (orgAttribute.min !== undefined && orgAttribute.max !== undefined) {\r\n const min = parseOrganizationValue(orgAttribute.min)\r\n const max = parseOrganizationValue(orgAttribute.max)\r\n if (min !== undefined && max !== undefined && min === max) {\r\n return min\r\n }\r\n }\r\n }\r\n\r\n return undefined\r\n}\r\n\r\nasync function fetchOrganizationFromTile(tileUrlTemplate: string, vectorLayerId: string, preferredZoom?: number) {\r\n try {\r\n const z = typeof preferredZoom === 'number' ? Math.max(0, Math.round(preferredZoom)) : 0\r\n const sampleUrl = tileUrlTemplate\r\n .replace('{z}', String(z))\r\n .replace('{x}', '0')\r\n .replace('{y}', '0')\r\n .replace('{Z}', String(z))\r\n .replace('{X}', '0')\r\n .replace('{Y}', '0')\r\n\r\n const response = await fetch(sampleUrl)\r\n if (!response.ok) return undefined\r\n\r\n const buffer = await response.arrayBuffer()\r\n const vectorTile = new VectorTile(new Pbf(buffer))\r\n const layer = vectorTile.layers[vectorLayerId] || Object.values(vectorTile.layers)[0]\r\n\r\n if (!layer || layer.length === 0) return undefined\r\n\r\n const feature = layer.feature(0)\r\n const { properties } = feature.toGeoJSON(0, 0, z)\r\n \r\n // Determine geometry type\r\n let geometryType: LayerGeometryType | undefined\r\n if (feature.type === 1) { // Point\r\n geometryType = 'circle'\r\n } else if (feature.type === 2) { // LineString\r\n geometryType = 'line'\r\n } else if (feature.type === 3) { // Polygon\r\n geometryType = 'fill'\r\n }\r\n\r\n return {\r\n organization: parseOrganizationValue(properties?.[ORGANIZATION_FIELD]),\r\n geometryType\r\n }\r\n } catch (error) {\r\n console.warn('Failed to read organization from tile', error)\r\n return undefined\r\n }\r\n}\r\n\r\nasync function resolveDatasetOrganization(tile: NormalizedMartinTile) {\r\n const fromTilestats = extractOrganizationFromTilestats(tile.tilestats)\r\n \r\n // Always fetch from tile to get geometry type, even if we have organization from tilestats\r\n const fromTile = await fetchOrganizationFromTile(tile.tileUrl, tile.vectorLayerId, tile.minzoom)\r\n \r\n return {\r\n organization: fromTilestats !== undefined ? fromTilestats : fromTile?.organization,\r\n geometryType: fromTile?.geometryType\r\n }\r\n}\r\n\r\nasync function fetchMartinServerDatasets(\r\n portal: OpenDataPortal,\r\n): Promise<Dataset[]> {\r\n const { countrySubdivision, municipality } = portal\r\n const martinServerUrl = portal.apiUrl\r\n\r\n if (!martinServerUrl) {\r\n console.warn('No Martin server URL configured for portal', portal.name)\r\n return []\r\n }\r\n\r\n try {\r\n console.log('Fetching Martin server catalog from:', martinServerUrl)\r\n\r\n const { indexUrl, tileBaseUrl, fallbackCatalogUrl } = resolveMartinUrls(martinServerUrl)\r\n\r\n let response = await fetch(indexUrl)\r\n if (!response.ok && fallbackCatalogUrl && fallbackCatalogUrl !== indexUrl) {\r\n console.warn(`Failed to fetch Martin index (${indexUrl}), falling back to catalog...`)\r\n response = await fetch(fallbackCatalogUrl)\r\n }\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch Martin catalog: ${response.status}`)\r\n }\r\n\r\n const catalog: MartinIndexResponse = await response.json()\r\n const tiles = normalizeMartinCatalog(catalog, tileBaseUrl)\r\n\r\n console.log('Martin catalog received:', tiles.length, 'tiles')\r\n\r\n const datasets: Dataset[] = await Promise.all(tiles.map(async (tileInfo) => {\r\n const cleanName = formatName(\r\n tileInfo.tileName\r\n .replace(/_\\d{8}$/, '')\r\n .replace(/__\\d+_\\d+$/, ''),\r\n )\r\n\r\n const { organization, geometryType } = await resolveDatasetOrganization(tileInfo)\r\n\r\n const getFields = async () => {\r\n return []\r\n }\r\n\r\n const getFeatures = async (): Promise<AllGeoJSON> => {\r\n return {\r\n type: 'FeatureCollection',\r\n features: [],\r\n } as AllGeoJSON\r\n }\r\n\r\n const getFeaturesData = async () => {\r\n return {\r\n id: tileInfo.tileName,\r\n name: cleanName,\r\n type: 'MVT',\r\n visible: true,\r\n clickable: true,\r\n fields: [],\r\n source: {\r\n url: tileInfo.tileUrl,\r\n description: tileInfo.description,\r\n publisher: 'Martin Server',\r\n },\r\n serviceInfo: {\r\n tileName: tileInfo.tileName,\r\n sourceLayer: tileInfo.vectorLayerId,\r\n type: 'Martin',\r\n tileUrl: tileInfo.tileUrl,\r\n },\r\n }\r\n }\r\n\r\n const dataset: Dataset = {\r\n id: tileInfo.tileName,\r\n name: cleanName,\r\n organization,\r\n publisher: 'Martin Server',\r\n dataManagementSystem: 'other',\r\n license: 'Unknown',\r\n contact: 'Unknown',\r\n keywords: [],\r\n description: tileInfo.description || `Vector tile layer from Martin server: ${tileInfo.tileName}`,\r\n dateReleased: '',\r\n dateUpdated: '',\r\n information: tileInfo.tileUrl,\r\n url: tileInfo.tileUrl,\r\n countrySubdivision: countrySubdivision,\r\n municipality: municipality,\r\n type: 'MVT',\r\n datasetType: 'MVT' as any,\r\n portal,\r\n getFields,\r\n getFeatures,\r\n getFeaturesData,\r\n group: DatasetGroup.Organizational,\r\n layerColor: layerColorByName(cleanName),\r\n layerType: geometryType,\r\n }\r\n\r\n return dataset\r\n }))\r\n\r\n console.log(`Transformed ${datasets.length} Martin datasets`)\r\n return datasets\r\n } catch (error) {\r\n console.error('Error fetching Martin server datasets:', error)\r\n return []\r\n }\r\n}\r\n\r\n// Fetch Local datasets from localDatasetsJson array and transform to Dataset array\r\nexport async function fetchLocalDatasets(\r\n portal: OpenDataPortal,\r\n): Promise<Dataset[]> {\r\n const { countrySubdivision, municipality } = portal\r\n const apiUrl = portal.apiUrl || ''\r\n const trimmedApiUrl = apiUrl.replace(/\\/+$/, '')\r\n\r\n if (!apiUrl) {\r\n console.warn('No apiUrl provided for portal', portal.name)\r\n return []\r\n }\r\n\r\n // Skip legacy portals with non-absolute URLs (e.g. ./localDatasets/index.json)\r\n if (!apiUrl.startsWith('http://') && !apiUrl.startsWith('https://')) {\r\n return []\r\n }\r\n\r\n if (trimmedApiUrl.includes('/catalog') || trimmedApiUrl.includes('/tiles/index')) {\r\n return fetchMartinServerDatasets(portal)\r\n }\r\n\r\n try {\r\n // Fetch the localDatasets.json file\r\n const response = await fetch(apiUrl)\r\n if (!response.ok) {\r\n const shouldTryMartinFallback =\r\n !trimmedApiUrl.endsWith('.json')\r\n && !trimmedApiUrl.includes('/catalog')\r\n && !trimmedApiUrl.includes('/tiles/index')\r\n\r\n if (response.status === 404 && shouldTryMartinFallback) {\r\n console.warn(\r\n `Local dataset URL returned 404 (${apiUrl}); retrying as a Martin server base URL`,\r\n )\r\n return fetchMartinServerDatasets({\r\n ...portal,\r\n apiUrl: trimmedApiUrl,\r\n })\r\n }\r\n\r\n throw new Error(`Failed to fetch local datasets from ${apiUrl}: ${response.status}`)\r\n }\r\n\r\n const localDatasetsJson: LocalDatasetItem[] = await response.json()\r\n\r\n const transformedDatasets: Dataset[] = localDatasetsJson.map((datasetItem: LocalDatasetItem) => {\r\n // Simple getFields function that returns fields from layer properties\r\n const getFields = async () => {\r\n if (datasetItem.layer?.properties) {\r\n return Object.entries(datasetItem.layer.properties).map(([name, type]) => ({\r\n name,\r\n label: formatName(name),\r\n type: type as string,\r\n description: `${formatName(name)} field`,\r\n }))\r\n }\r\n return []\r\n }\r\n\r\n // Fetch GeoJSON data from the featuresUrl\r\n const getFeatures = async (): Promise<AllGeoJSON> => {\r\n // Create a cache key based on the dataset name and features URL\r\n const featuresKey = `features:local:${datasetItem.name}:${datasetItem.featuresUrl}`\r\n \r\n // Check cache first\r\n const cachedFeatures = getCache<AllGeoJSON>(featuresKey)\r\n if (cachedFeatures) {\r\n return cachedFeatures\r\n }\r\n \r\n try {\r\n // Use the featuresUrl from the dataset item\r\n let geojsonUrl: string\r\n if (datasetItem.featuresUrl.startsWith('http://') || datasetItem.featuresUrl.startsWith('https://')) {\r\n geojsonUrl = datasetItem.featuresUrl\r\n } else {\r\n const baseUrl = apiUrl.endsWith('.json') \r\n ? apiUrl.substring(0, apiUrl.lastIndexOf('/'))\r\n : apiUrl\r\n geojsonUrl = `${baseUrl}/${datasetItem.featuresUrl}`\r\n }\r\n\r\n const response = await fetch(geojsonUrl)\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch GeoJSON: ${response.status}`)\r\n }\r\n\r\n const geojsonData = await response.json() as AllGeoJSON\r\n \r\n // Cache for 1 hour\r\n setCache(featuresKey, geojsonData, 60 * 60 * 1000)\r\n \r\n return geojsonData\r\n } catch (error) {\r\n console.error(`Error loading GeoJSON for ${datasetItem.name}:`, error)\r\n return {\r\n type: 'FeatureCollection',\r\n features: [],\r\n } as AllGeoJSON\r\n }\r\n }\r\n\r\n const name = formatName(datasetItem.name)\r\n\r\n const getFeaturesData = async () => {\r\n try {\r\n return {\r\n // Basic layer information\r\n id: datasetItem.tileName || datasetItem.name.toLowerCase().replace(/\\s+/g, '-'),\r\n name: datasetItem.name,\r\n type: datasetItem.layer?.type || 'GeoJSON',\r\n\r\n // Layer configuration\r\n visible: datasetItem.visible,\r\n clickable: datasetItem.clickable,\r\n\r\n // Field information (similar to ArcGIS fields structure)\r\n fields: datasetItem.layer?.properties\r\n ? Object.entries(datasetItem.layer.properties).map(([name, type]) => ({\r\n name,\r\n type: type as FieldType,\r\n alias: formatName(name),\r\n description: `${formatName(name)} field`,\r\n }))\r\n : [],\r\n\r\n // Source information\r\n source: {\r\n url: datasetItem.url,\r\n description: datasetItem.description,\r\n publisher: datasetItem.publisher,\r\n featuresUrl: datasetItem.featuresUrl,\r\n },\r\n\r\n // Additional metadata that DatasetDetails.tsx might use\r\n editingInfo: {\r\n lastEditDate: new Date().toISOString(), // Current date as placeholder\r\n dataLastEditDate: new Date().toISOString(),\r\n },\r\n\r\n // Layer properties summary\r\n properties: datasetItem.layer?.properties || {},\r\n fieldCount: datasetItem.layer?.properties ? Object.keys(datasetItem.layer.properties).length : 0,\r\n\r\n // Geometry information\r\n geometryType: 'Unknown', // You could infer this from the actual GeoJSON if needed\r\n\r\n // Service information (for compatibility)\r\n serviceInfo: {\r\n tileName: datasetItem.tileName,\r\n sourceLayer: datasetItem.sourceLayer,\r\n type: 'Local',\r\n },\r\n }\r\n } catch (error) {\r\n console.error('Error getting features data for dataset:', datasetItem.name, error)\r\n return null\r\n }\r\n }\r\n\r\n return {\r\n id: datasetItem.tileName || datasetItem.name.toLowerCase().replace(/\\s+/g, '-'),\r\n name,\r\n organization: datasetItem.organization || 0,\r\n publisher: datasetItem.publisher || 'Unknown',\r\n dataManagementSystem: 'other',\r\n license: 'Unknown',\r\n contact: 'Unknown',\r\n keywords: [],\r\n description: datasetItem.description || 'No description available',\r\n dateReleased: '',\r\n dateUpdated: '',\r\n information: datasetItem.url || '',\r\n url: datasetItem.url || '#', // Ensure there's always a valid URL for the Link component\r\n countrySubdivision: datasetItem.countrySubdivision || countrySubdivision,\r\n municipality: datasetItem.municipality || municipality,\r\n type: datasetItem.layer?.type || 'GeoJSON',\r\n datasetType: 'GeoJSON' as const,\r\n portal,\r\n getFields,\r\n getFeatures,\r\n getFeaturesData,\r\n group: 'Organizational',\r\n layerColor: layerColorByName(name),\r\n }\r\n })\r\n\r\n return transformedDatasets\r\n } catch (error) {\r\n console.error('Error fetching local datasets:', error)\r\n return []\r\n }\r\n}\r\n"],"mappings":"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","names":["_a","name","response"]}
1
+ {"version":3,"sources":["../../../../../../../src/core/components/viewers/map/datasets/src/localDatasets.ts"],"sourcesContent":["import type { Dataset, FieldType, LayerGeometryType } from '../../../../../types/datasetTypes'\r\nimport { formatName } from '../utils'\r\nimport { DatasetGroup, type OpenDataPortal } from '../../../../../types/dbTypes'\r\nimport type { AllGeoJSON } from '@turf/turf'\r\nimport { layerColorByName } from '../../utils/stringToColour'\r\nimport Pbf from 'pbf'\r\nimport { VectorTile } from '@mapbox/vector-tile'\r\nimport { getCache, setCache } from './cache'\r\nimport { isPublishedOrgTable, buildPublishedTileDatasets, type PublishedFileRow } from './publishedTiles'\r\n\r\n\r\n// Define the structure of local dataset items\r\ninterface LocalDatasetItem {\r\n name: string\r\n organization: number\r\n featuresUrl: string\r\n tileName: string\r\n sourceLayer: string\r\n layer: {\r\n type: string\r\n properties: Record<string, string>\r\n }\r\n visible: boolean\r\n clickable: boolean\r\n url: string\r\n description: string\r\n publisher: string\r\n countrySubdivision?: string\r\n municipality?: string\r\n}\r\n\r\ninterface MartinCatalogTile {\r\n content_type: string\r\n description: string\r\n}\r\n\r\ninterface MartinCatalog {\r\n tiles: Record<string, MartinCatalogTile>\r\n}\r\n\r\ninterface MartinTileStatsAttribute {\r\n attribute: string\r\n values?: Array<string | number>\r\n min?: number | string\r\n max?: number | string\r\n}\r\n\r\ninterface MartinTileStatsLayer {\r\n layer: string\r\n attributes?: MartinTileStatsAttribute[]\r\n}\r\n\r\ninterface MartinTileStats {\r\n layers?: MartinTileStatsLayer[]\r\n}\r\n\r\ninterface MartinTileJson {\r\n id?: string\r\n name?: string\r\n description?: string\r\n tiles?: string[]\r\n vector_layers?: Array<{\r\n id: string\r\n description?: string\r\n minzoom?: number\r\n maxzoom?: number\r\n fields?: Record<string, string>\r\n }>\r\n tilestats?: MartinTileStats\r\n minzoom?: number\r\n maxzoom?: number\r\n}\r\n\r\ntype MartinIndexResponse =\r\n | MartinCatalog\r\n | MartinTileJson[]\r\n | { tiles: Record<string, MartinTileJson> }\r\n | { tilesets: MartinTileJson[] }\r\n\r\ninterface NormalizedMartinTile {\r\n tileName: string\r\n tileUrl: string\r\n description?: string\r\n vectorLayerId: string\r\n tilestats?: MartinTileStats\r\n minzoom?: number\r\n}\r\n\r\nconst ORGANIZATION_FIELD = 'organization'\r\n\r\nfunction normalizeMartinBaseUrl(apiUrl: string) {\r\n return apiUrl.replace(/\\/+$/, '')\r\n}\r\n\r\nfunction resolveMartinUrls(apiUrl: string) {\r\n const trimmed = normalizeMartinBaseUrl(apiUrl)\r\n\r\n if (trimmed.endsWith('/tiles/index.json')) {\r\n const tileBaseUrl = trimmed.replace(/\\/tiles\\/index\\.json$/, '')\r\n return {\r\n indexUrl: trimmed,\r\n tileBaseUrl,\r\n fallbackCatalogUrl: `${tileBaseUrl}/catalog`,\r\n }\r\n }\r\n\r\n if (trimmed.endsWith('/catalog')) {\r\n const tileBaseUrl = trimmed.replace(/\\/catalog$/, '')\r\n return {\r\n indexUrl: `${tileBaseUrl}/tiles/index.json`,\r\n tileBaseUrl,\r\n fallbackCatalogUrl: trimmed,\r\n }\r\n }\r\n\r\n return {\r\n indexUrl: `${trimmed}/tiles/index.json`,\r\n tileBaseUrl: trimmed,\r\n fallbackCatalogUrl: `${trimmed}/catalog`,\r\n }\r\n}\r\n\r\nfunction ensureAbsoluteTileUrl(tileUrl: string, tileBaseUrl: string) {\r\n if (/^https?:\\/\\//i.test(tileUrl)) {\r\n return tileUrl\r\n }\r\n\r\n const cleanedBase = tileBaseUrl.replace(/\\/+$/, '')\r\n const cleanedPath = tileUrl.replace(/^\\/+/, '')\r\n return `${cleanedBase}/${cleanedPath}`\r\n}\r\n\r\nfunction normalizeTileInfo(tileInfo: MartinTileJson, fallbackName: string | null, tileBaseUrl: string): NormalizedMartinTile | null {\r\n const tileName = tileInfo.id || tileInfo.name || fallbackName\r\n if (!tileName) return null\r\n\r\n const vectorLayerId = tileInfo.vector_layers?.[0]?.id || tileName\r\n const tileUrlFromInfo = Array.isArray(tileInfo.tiles) && tileInfo.tiles.length > 0\r\n ? tileInfo.tiles[0]\r\n : `${tileBaseUrl}/${tileName}/{z}/{x}/{y}`\r\n\r\n return {\r\n tileName,\r\n tileUrl: ensureAbsoluteTileUrl(tileUrlFromInfo, tileBaseUrl),\r\n description: tileInfo.description || tileInfo.vector_layers?.[0]?.description,\r\n vectorLayerId,\r\n tilestats: tileInfo.tilestats,\r\n minzoom: tileInfo.minzoom || tileInfo.vector_layers?.[0]?.minzoom,\r\n }\r\n}\r\n\r\nfunction normalizeMartinCatalog(response: MartinIndexResponse, tileBaseUrl: string): NormalizedMartinTile[] {\r\n if (Array.isArray(response)) {\r\n return response\r\n .map(tile => normalizeTileInfo(tile, null, tileBaseUrl))\r\n .filter((t): t is NormalizedMartinTile => Boolean(t))\r\n }\r\n\r\n if ('tilesets' in response && Array.isArray(response.tilesets)) {\r\n return response.tilesets\r\n .map(tile => normalizeTileInfo(tile, null, tileBaseUrl))\r\n .filter((t): t is NormalizedMartinTile => Boolean(t))\r\n }\r\n\r\n if ('tiles' in response && response.tiles) {\r\n return Object.entries(response.tiles)\r\n .map(([tileName, tileInfo]) => normalizeTileInfo(tileInfo as MartinTileJson, tileName, tileBaseUrl))\r\n .filter((t): t is NormalizedMartinTile => Boolean(t))\r\n }\r\n\r\n return []\r\n}\r\n\r\nfunction parseOrganizationValue(value: unknown): number | undefined {\r\n if (value == null) return undefined\r\n if (typeof value === 'number' && Number.isFinite(value)) return value\r\n\r\n const parsed = Number.parseInt(String(value), 10)\r\n return Number.isFinite(parsed) ? parsed : undefined\r\n}\r\n\r\nfunction extractOrganizationFromTilestats(tilestats?: MartinTileStats): number | undefined {\r\n if (!tilestats?.layers) return undefined\r\n\r\n for (const layer of tilestats.layers) {\r\n const orgAttribute = layer.attributes?.find(attr =>\r\n attr.attribute?.toLowerCase() === ORGANIZATION_FIELD,\r\n )\r\n\r\n if (!orgAttribute) continue\r\n\r\n if (orgAttribute.values && orgAttribute.values.length > 0) {\r\n const value = parseOrganizationValue(orgAttribute.values[0])\r\n if (value !== undefined) return value\r\n }\r\n\r\n if (orgAttribute.min !== undefined && orgAttribute.max !== undefined) {\r\n const min = parseOrganizationValue(orgAttribute.min)\r\n const max = parseOrganizationValue(orgAttribute.max)\r\n if (min !== undefined && max !== undefined && min === max) {\r\n return min\r\n }\r\n }\r\n }\r\n\r\n return undefined\r\n}\r\n\r\nasync function fetchOrganizationFromTile(tileUrlTemplate: string, vectorLayerId: string, preferredZoom?: number) {\r\n try {\r\n const z = typeof preferredZoom === 'number' ? Math.max(0, Math.round(preferredZoom)) : 0\r\n const sampleUrl = tileUrlTemplate\r\n .replace('{z}', String(z))\r\n .replace('{x}', '0')\r\n .replace('{y}', '0')\r\n .replace('{Z}', String(z))\r\n .replace('{X}', '0')\r\n .replace('{Y}', '0')\r\n\r\n const response = await fetch(sampleUrl)\r\n if (!response.ok) return undefined\r\n\r\n const buffer = await response.arrayBuffer()\r\n const vectorTile = new VectorTile(new Pbf(buffer))\r\n const layer = vectorTile.layers[vectorLayerId] || Object.values(vectorTile.layers)[0]\r\n\r\n if (!layer || layer.length === 0) return undefined\r\n\r\n const feature = layer.feature(0)\r\n const { properties } = feature.toGeoJSON(0, 0, z)\r\n \r\n // Determine geometry type\r\n let geometryType: LayerGeometryType | undefined\r\n if (feature.type === 1) { // Point\r\n geometryType = 'circle'\r\n } else if (feature.type === 2) { // LineString\r\n geometryType = 'line'\r\n } else if (feature.type === 3) { // Polygon\r\n geometryType = 'fill'\r\n }\r\n\r\n return {\r\n organization: parseOrganizationValue(properties?.[ORGANIZATION_FIELD]),\r\n geometryType\r\n }\r\n } catch (error) {\r\n console.warn('Failed to read organization from tile', error)\r\n return undefined\r\n }\r\n}\r\n\r\nasync function resolveDatasetOrganization(tile: NormalizedMartinTile) {\r\n const fromTilestats = extractOrganizationFromTilestats(tile.tilestats)\r\n \r\n // Always fetch from tile to get geometry type, even if we have organization from tilestats\r\n const fromTile = await fetchOrganizationFromTile(tile.tileUrl, tile.vectorLayerId, tile.minzoom)\r\n \r\n return {\r\n organization: fromTilestats !== undefined ? fromTilestats : fromTile?.organization,\r\n geometryType: fromTile?.geometryType\r\n }\r\n}\r\n\r\nasync function fetchPublishedTileLabels(): Promise<Map<string, string>> {\r\n try {\r\n const res = await fetch('/api/files')\r\n if (!res.ok) return new Map()\r\n const body = await res.json()\r\n const rows: Array<{ name?: string | null, description?: string | null }> =\r\n Array.isArray(body?.files) ? body.files : []\r\n const map = new Map<string, string>()\r\n for (const row of rows) {\r\n if (!row?.description || !row?.name) continue\r\n try {\r\n const desc = JSON.parse(row.description) as { tiledTable?: unknown }\r\n if (typeof desc?.tiledTable === 'string') {\r\n map.set(desc.tiledTable, row.name.replace(/\\.geojson$/i, ''))\r\n }\r\n }\r\n catch { /* skip malformed */ }\r\n }\r\n return map\r\n }\r\n catch {\r\n return new Map()\r\n }\r\n}\r\n\r\nasync function fetchMartinServerDatasets(\r\n portal: OpenDataPortal,\r\n): Promise<Dataset[]> {\r\n const { countrySubdivision, municipality } = portal\r\n const martinServerUrl = portal.apiUrl\r\n\r\n if (!martinServerUrl) {\r\n console.warn('No Martin server URL configured for portal', portal.name)\r\n return []\r\n }\r\n\r\n try {\r\n console.log('Fetching Martin server catalog from:', martinServerUrl)\r\n\r\n const { indexUrl, tileBaseUrl, fallbackCatalogUrl } = resolveMartinUrls(martinServerUrl)\r\n\r\n const publishedLabels = await fetchPublishedTileLabels()\r\n\r\n let response = await fetch(indexUrl)\r\n if (!response.ok && fallbackCatalogUrl && fallbackCatalogUrl !== indexUrl) {\r\n console.warn(`Failed to fetch Martin index (${indexUrl}), falling back to catalog...`)\r\n response = await fetch(fallbackCatalogUrl)\r\n }\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch Martin catalog: ${response.status}`)\r\n }\r\n\r\n const catalog: MartinIndexResponse = await response.json()\r\n const tiles = normalizeMartinCatalog(catalog, tileBaseUrl)\r\n // Drop our published org tables (served via the cdt_tiles function + discovered\r\n // from File metadata) and the cdt_tiles function source itself (no ?source= → empty).\r\n .filter(t => !isPublishedOrgTable(t.tileName) && t.tileName !== 'cdt_tiles')\r\n\r\n console.log('Martin catalog received:', tiles.length, 'tiles')\r\n\r\n const datasets: Dataset[] = await Promise.all(tiles.map(async (tileInfo) => {\r\n const publishedLabel = publishedLabels.get(tileInfo.tileName)\r\n const cleanName = publishedLabel ?? formatName(\r\n tileInfo.tileName\r\n .replace(/_\\d{8}$/, '')\r\n .replace(/__\\d+_\\d+$/, ''),\r\n )\r\n\r\n const { organization, geometryType } = await resolveDatasetOrganization(tileInfo)\r\n\r\n const getFields = async () => {\r\n return []\r\n }\r\n\r\n const getFeatures = async (): Promise<AllGeoJSON> => {\r\n return {\r\n type: 'FeatureCollection',\r\n features: [],\r\n } as AllGeoJSON\r\n }\r\n\r\n const getFeaturesData = async () => {\r\n return {\r\n id: tileInfo.tileName,\r\n name: cleanName,\r\n type: 'MVT',\r\n visible: true,\r\n clickable: true,\r\n fields: [],\r\n source: {\r\n url: tileInfo.tileUrl,\r\n description: tileInfo.description,\r\n publisher: 'Martin Server',\r\n },\r\n serviceInfo: {\r\n tileName: tileInfo.tileName,\r\n sourceLayer: tileInfo.vectorLayerId,\r\n type: 'Martin',\r\n tileUrl: tileInfo.tileUrl,\r\n },\r\n }\r\n }\r\n\r\n const dataset: Dataset = {\r\n id: tileInfo.tileName,\r\n name: cleanName,\r\n organization,\r\n publisher: 'Martin Server',\r\n dataManagementSystem: 'other',\r\n license: 'Unknown',\r\n contact: 'Unknown',\r\n keywords: [],\r\n description: tileInfo.description || `Vector tile layer from Martin server: ${tileInfo.tileName}`,\r\n dateReleased: '',\r\n dateUpdated: '',\r\n information: tileInfo.tileUrl,\r\n url: tileInfo.tileUrl,\r\n countrySubdivision: countrySubdivision,\r\n municipality: municipality,\r\n type: 'MVT',\r\n datasetType: 'MVT' as any,\r\n portal,\r\n getFields,\r\n getFeatures,\r\n getFeaturesData,\r\n group: DatasetGroup.Organizational,\r\n layerColor: layerColorByName(cleanName),\r\n layerType: geometryType,\r\n }\r\n\r\n return dataset\r\n }))\r\n\r\n console.log(`Transformed ${datasets.length} Martin datasets`)\r\n\r\n let publishedDatasets: Dataset[] = []\r\n try {\r\n const fileRes = await fetch('/api/files')\r\n if (fileRes.ok) {\r\n const fileBody = await fileRes.json()\r\n const fileRows: PublishedFileRow[] = Array.isArray(fileBody?.files) ? fileBody.files : []\r\n publishedDatasets = buildPublishedTileDatasets(fileRows, tileBaseUrl, portal)\r\n }\r\n }\r\n catch (err) {\r\n console.warn('Failed to build published-tile datasets from /api/files', err)\r\n }\r\n\r\n return [...datasets, ...publishedDatasets]\r\n } catch (error) {\r\n console.error('Error fetching Martin server datasets:', error)\r\n return []\r\n }\r\n}\r\n\r\n// Fetch Local datasets from localDatasetsJson array and transform to Dataset array\r\nexport async function fetchLocalDatasets(\r\n portal: OpenDataPortal,\r\n): Promise<Dataset[]> {\r\n const { countrySubdivision, municipality } = portal\r\n const apiUrl = portal.apiUrl || ''\r\n const trimmedApiUrl = apiUrl.replace(/\\/+$/, '')\r\n\r\n if (!apiUrl) {\r\n console.warn('No apiUrl provided for portal', portal.name)\r\n return []\r\n }\r\n\r\n // Skip legacy portals with non-absolute URLs (e.g. ./localDatasets/index.json)\r\n if (!apiUrl.startsWith('http://') && !apiUrl.startsWith('https://')) {\r\n return []\r\n }\r\n\r\n if (trimmedApiUrl.includes('/catalog') || trimmedApiUrl.includes('/tiles/index')) {\r\n return fetchMartinServerDatasets(portal)\r\n }\r\n\r\n try {\r\n // Fetch the localDatasets.json file\r\n const response = await fetch(apiUrl)\r\n if (!response.ok) {\r\n const shouldTryMartinFallback =\r\n !trimmedApiUrl.endsWith('.json')\r\n && !trimmedApiUrl.includes('/catalog')\r\n && !trimmedApiUrl.includes('/tiles/index')\r\n\r\n if (response.status === 404 && shouldTryMartinFallback) {\r\n console.warn(\r\n `Local dataset URL returned 404 (${apiUrl}); retrying as a Martin server base URL`,\r\n )\r\n return fetchMartinServerDatasets({\r\n ...portal,\r\n apiUrl: trimmedApiUrl,\r\n })\r\n }\r\n\r\n throw new Error(`Failed to fetch local datasets from ${apiUrl}: ${response.status}`)\r\n }\r\n\r\n const localDatasetsJson: LocalDatasetItem[] = await response.json()\r\n\r\n const transformedDatasets: Dataset[] = localDatasetsJson.map((datasetItem: LocalDatasetItem) => {\r\n // Simple getFields function that returns fields from layer properties\r\n const getFields = async () => {\r\n if (datasetItem.layer?.properties) {\r\n return Object.entries(datasetItem.layer.properties).map(([name, type]) => ({\r\n name,\r\n label: formatName(name),\r\n type: type as string,\r\n description: `${formatName(name)} field`,\r\n }))\r\n }\r\n return []\r\n }\r\n\r\n // Fetch GeoJSON data from the featuresUrl\r\n const getFeatures = async (): Promise<AllGeoJSON> => {\r\n // Create a cache key based on the dataset name and features URL\r\n const featuresKey = `features:local:${datasetItem.name}:${datasetItem.featuresUrl}`\r\n \r\n // Check cache first\r\n const cachedFeatures = getCache<AllGeoJSON>(featuresKey)\r\n if (cachedFeatures) {\r\n return cachedFeatures\r\n }\r\n \r\n try {\r\n // Use the featuresUrl from the dataset item\r\n let geojsonUrl: string\r\n if (datasetItem.featuresUrl.startsWith('http://') || datasetItem.featuresUrl.startsWith('https://')) {\r\n geojsonUrl = datasetItem.featuresUrl\r\n } else {\r\n const baseUrl = apiUrl.endsWith('.json') \r\n ? apiUrl.substring(0, apiUrl.lastIndexOf('/'))\r\n : apiUrl\r\n geojsonUrl = `${baseUrl}/${datasetItem.featuresUrl}`\r\n }\r\n\r\n const response = await fetch(geojsonUrl)\r\n\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch GeoJSON: ${response.status}`)\r\n }\r\n\r\n const geojsonData = await response.json() as AllGeoJSON\r\n \r\n // Cache for 1 hour\r\n setCache(featuresKey, geojsonData, 60 * 60 * 1000)\r\n \r\n return geojsonData\r\n } catch (error) {\r\n console.error(`Error loading GeoJSON for ${datasetItem.name}:`, error)\r\n return {\r\n type: 'FeatureCollection',\r\n features: [],\r\n } as AllGeoJSON\r\n }\r\n }\r\n\r\n const name = formatName(datasetItem.name)\r\n\r\n const getFeaturesData = async () => {\r\n try {\r\n return {\r\n // Basic layer information\r\n id: datasetItem.tileName || datasetItem.name.toLowerCase().replace(/\\s+/g, '-'),\r\n name: datasetItem.name,\r\n type: datasetItem.layer?.type || 'GeoJSON',\r\n\r\n // Layer configuration\r\n visible: datasetItem.visible,\r\n clickable: datasetItem.clickable,\r\n\r\n // Field information (similar to ArcGIS fields structure)\r\n fields: datasetItem.layer?.properties\r\n ? Object.entries(datasetItem.layer.properties).map(([name, type]) => ({\r\n name,\r\n type: type as FieldType,\r\n alias: formatName(name),\r\n description: `${formatName(name)} field`,\r\n }))\r\n : [],\r\n\r\n // Source information\r\n source: {\r\n url: datasetItem.url,\r\n description: datasetItem.description,\r\n publisher: datasetItem.publisher,\r\n featuresUrl: datasetItem.featuresUrl,\r\n },\r\n\r\n // Additional metadata that DatasetDetails.tsx might use\r\n editingInfo: {\r\n lastEditDate: new Date().toISOString(), // Current date as placeholder\r\n dataLastEditDate: new Date().toISOString(),\r\n },\r\n\r\n // Layer properties summary\r\n properties: datasetItem.layer?.properties || {},\r\n fieldCount: datasetItem.layer?.properties ? Object.keys(datasetItem.layer.properties).length : 0,\r\n\r\n // Geometry information\r\n geometryType: 'Unknown', // You could infer this from the actual GeoJSON if needed\r\n\r\n // Service information (for compatibility)\r\n serviceInfo: {\r\n tileName: datasetItem.tileName,\r\n sourceLayer: datasetItem.sourceLayer,\r\n type: 'Local',\r\n },\r\n }\r\n } catch (error) {\r\n console.error('Error getting features data for dataset:', datasetItem.name, error)\r\n return null\r\n }\r\n }\r\n\r\n return {\r\n id: datasetItem.tileName || datasetItem.name.toLowerCase().replace(/\\s+/g, '-'),\r\n name,\r\n organization: datasetItem.organization || 0,\r\n publisher: datasetItem.publisher || 'Unknown',\r\n dataManagementSystem: 'other',\r\n license: 'Unknown',\r\n contact: 'Unknown',\r\n keywords: [],\r\n description: datasetItem.description || 'No description available',\r\n dateReleased: '',\r\n dateUpdated: '',\r\n information: datasetItem.url || '',\r\n url: datasetItem.url || '#', // Ensure there's always a valid URL for the Link component\r\n countrySubdivision: datasetItem.countrySubdivision || countrySubdivision,\r\n municipality: datasetItem.municipality || municipality,\r\n type: datasetItem.layer?.type || 'GeoJSON',\r\n datasetType: 'GeoJSON' as const,\r\n portal,\r\n getFields,\r\n getFeatures,\r\n getFeaturesData,\r\n group: 'Organizational',\r\n layerColor: layerColorByName(name),\r\n }\r\n })\r\n\r\n return transformedDatasets\r\n } catch (error) {\r\n console.error('Error fetching local datasets:', error)\r\n return []\r\n }\r\n}\r\n"],"mappings":"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","names":["_a","name","response"]}
@@ -1,3 +1,3 @@
1
1
  import type { Dataset } from '../../../../../types/datasetTypes';
2
- export declare function fetchOrganizationalMinioDatasets(organizationId: number): Promise<Dataset[]>;
2
+ export declare function fetchOrganizationalMinioDatasets(organizationId: number, publishedTilesInCatalog?: ReadonlySet<string>): Promise<Dataset[]>;
3
3
  //# sourceMappingURL=minioDatasets.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"minioDatasets.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/datasets/src/minioDatasets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAA;AA+ChE,wBAAsB,gCAAgC,CACpD,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,OAAO,EAAE,CAAC,CA8EpB"}
1
+ {"version":3,"file":"minioDatasets.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/datasets/src/minioDatasets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAA;AAmDhE,wBAAsB,gCAAgC,CACpD,cAAc,EAAE,MAAM,EACtB,uBAAuB,GAAE,WAAW,CAAC,MAAM,CAAa,GACvD,OAAO,CAAC,OAAO,EAAE,CAAC,CAmFpB"}
@@ -15,7 +15,7 @@ function buildMinioUrl(bucket, organizationId, assetId) {
15
15
  if (!base) return null;
16
16
  return `${base.replace(/\/+$/, "")}/${bucket}/${organizationId}/${assetId}`;
17
17
  }
18
- async function fetchOrganizationalMinioDatasets(organizationId) {
18
+ async function fetchOrganizationalMinioDatasets(organizationId, publishedTilesInCatalog = /* @__PURE__ */ new Set()) {
19
19
  var _a, _b;
20
20
  let rows = [];
21
21
  try {
@@ -36,6 +36,7 @@ async function fetchOrganizationalMinioDatasets(organizationId) {
36
36
  if (row.tag !== TAG) continue;
37
37
  if (!row.assetId) continue;
38
38
  const meta = parseDescription(row.description);
39
+ if ((meta == null ? void 0 : meta.tiledTable) && publishedTilesInCatalog.has(meta.tiledTable)) continue;
39
40
  const bucket = meta == null ? void 0 : meta.bucket;
40
41
  if (!bucket) continue;
41
42
  const sourceUrl = buildMinioUrl(bucket, organizationId, row.assetId);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../src/core/components/viewers/map/datasets/src/minioDatasets.ts"],"sourcesContent":["import type { Dataset } from '../../../../../types/datasetTypes'\r\nimport { DatasetGroup } from '../../../../../types/dbTypes'\r\nimport { layerColorByName } from '../../utils/stringToColour'\r\nimport type { AllGeoJSON } from '@turf/turf'\r\n\r\n/**\r\n * Hydrates uploaded GeoJSON datasets persisted via \"Add Dataset\". Looks up\r\n * File rows tagged `organizational-dataset`, reads the bucket from each row's\r\n * description JSON, and builds Dataset entries whose `getFeatures` lazy-loads\r\n * the GeoJSON from MinIO on first render.\r\n */\r\n\r\ninterface OrgDatasetDescription {\r\n bucket?: string\r\n geometryType?: 'points' | 'lines' | 'polygons'\r\n layerStyles?: Record<string, Record<string, string | number>>\r\n}\r\n\r\ninterface RawFileRow {\r\n id: number\r\n type?: string | null\r\n tag?: string | null\r\n name?: string | null\r\n assetId?: string | null\r\n description?: string | null\r\n uploadedAt?: string | Date | null\r\n}\r\n\r\nconst TAG = 'organizational-dataset'\r\n\r\nfunction parseDescription(value: string | null | undefined): OrgDatasetDescription | null {\r\n if (!value) return null\r\n try {\r\n const parsed = JSON.parse(value)\r\n return typeof parsed === 'object' && parsed !== null ? parsed as OrgDatasetDescription : null\r\n }\r\n catch {\r\n return null\r\n }\r\n}\r\n\r\nfunction buildMinioUrl(bucket: string, organizationId: number, assetId: string): string | null {\r\n const base = process.env.NEXT_PUBLIC_MINIO_BUCKET_URL\r\n if (!base) return null\r\n return `${base.replace(/\\/+$/, '')}/${bucket}/${organizationId}/${assetId}`\r\n}\r\n\r\nexport async function fetchOrganizationalMinioDatasets(\r\n organizationId: number,\r\n): Promise<Dataset[]> {\r\n let rows: RawFileRow[] = []\r\n try {\r\n const res = await fetch('/api/files')\r\n if (!res.ok) {\r\n console.warn(`fetchOrganizationalMinioDatasets: /api/files returned ${res.status}`)\r\n return []\r\n }\r\n const body = await res.json()\r\n rows = Array.isArray(body?.files) ? body.files : []\r\n }\r\n catch (err) {\r\n console.warn('fetchOrganizationalMinioDatasets: /api/files request failed', err)\r\n return []\r\n }\r\n\r\n const datasets: Dataset[] = []\r\n for (const row of rows) {\r\n if (row.type !== 'map-file') continue\r\n if (row.tag !== TAG) continue\r\n if (!row.assetId) continue\r\n\r\n const meta = parseDescription(row.description)\r\n const bucket = meta?.bucket\r\n if (!bucket) continue\r\n\r\n const sourceUrl = buildMinioUrl(bucket, organizationId, row.assetId)\r\n if (!sourceUrl) continue\r\n\r\n const name = row.name?.replace(/\\.geojson$/i, '') || `Dataset ${row.id}`\r\n const id = `org-minio-${row.id}`\r\n let cached: AllGeoJSON | null = null\r\n\r\n const getFeatures = async (): Promise<AllGeoJSON> => {\r\n if (cached) return cached\r\n const response = await fetch(sourceUrl)\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch GeoJSON from ${sourceUrl}: ${response.status}`)\r\n }\r\n cached = await response.json() as AllGeoJSON\r\n return cached\r\n }\r\n\r\n const getFields = async () => []\r\n\r\n datasets.push({\r\n id,\r\n name,\r\n type: 'Organizational',\r\n publisher: 'Organizational',\r\n license: 'Unknown',\r\n contact: 'Unknown',\r\n description: `Uploaded ${row.uploadedAt ?? ''}`.trim(),\r\n dateReleased: typeof row.uploadedAt === 'string' ? row.uploadedAt : '',\r\n dateUpdated: typeof row.uploadedAt === 'string' ? row.uploadedAt : '',\r\n countrySubdivision: '',\r\n municipality: '',\r\n sourceUrl,\r\n url: sourceUrl,\r\n clickable: true,\r\n properties: {},\r\n getFeatures,\r\n getFields,\r\n dataManagementSystem: 'other',\r\n datasetType: 'GeoJSON',\r\n group: DatasetGroup.Organizational,\r\n layerColor: layerColorByName(id),\r\n layerType: meta?.geometryType === 'lines'\r\n ? 'line'\r\n : meta?.geometryType === 'points'\r\n ? 'circle'\r\n : meta?.geometryType === 'polygons'\r\n ? 'fill'\r\n : undefined,\r\n })\r\n }\r\n\r\n return datasets\r\n}\r\n"],"mappings":"AACA,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AA0BjC,MAAM,MAAM;AAEZ,SAAS,iBAAiB,OAAgE;AACxF,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,WAAO,OAAO,WAAW,YAAY,WAAW,OAAO,SAAkC;AAAA,EAC3F,SACM;AACJ,WAAO;AAAA,EACT;AACF;AAEA,SAAS,cAAc,QAAgB,gBAAwB,SAAgC;AAC7F,QAAM,OAAO,QAAQ,IAAI;AACzB,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,GAAG,KAAK,QAAQ,QAAQ,EAAE,CAAC,IAAI,MAAM,IAAI,cAAc,IAAI,OAAO;AAC3E;AAEA,eAAsB,iCACpB,gBACoB;AAjDtB;AAkDE,MAAI,OAAqB,CAAC;AAC1B,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,YAAY;AACpC,QAAI,CAAC,IAAI,IAAI;AACX,cAAQ,KAAK,yDAAyD,IAAI,MAAM,EAAE;AAClF,aAAO,CAAC;AAAA,IACV;AACA,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,WAAO,MAAM,QAAQ,6BAAM,KAAK,IAAI,KAAK,QAAQ,CAAC;AAAA,EACpD,SACO,KAAK;AACV,YAAQ,KAAK,+DAA+D,GAAG;AAC/E,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,WAAsB,CAAC;AAC7B,aAAW,OAAO,MAAM;AACtB,QAAI,IAAI,SAAS,WAAY;AAC7B,QAAI,IAAI,QAAQ,IAAK;AACrB,QAAI,CAAC,IAAI,QAAS;AAElB,UAAM,OAAO,iBAAiB,IAAI,WAAW;AAC7C,UAAM,SAAS,6BAAM;AACrB,QAAI,CAAC,OAAQ;AAEb,UAAM,YAAY,cAAc,QAAQ,gBAAgB,IAAI,OAAO;AACnE,QAAI,CAAC,UAAW;AAEhB,UAAM,SAAO,SAAI,SAAJ,mBAAU,QAAQ,eAAe,QAAO,WAAW,IAAI,EAAE;AACtE,UAAM,KAAK,aAAa,IAAI,EAAE;AAC9B,QAAI,SAA4B;AAEhC,UAAM,cAAc,YAAiC;AACnD,UAAI,OAAQ,QAAO;AACnB,YAAM,WAAW,MAAM,MAAM,SAAS;AACtC,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,MAAM,gCAAgC,SAAS,KAAK,SAAS,MAAM,EAAE;AAAA,MACjF;AACA,eAAS,MAAM,SAAS,KAAK;AAC7B,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,YAAY,CAAC;AAE/B,aAAS,KAAK;AAAA,MACZ;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,MACT,SAAS;AAAA,MACT,aAAa,aAAY,SAAI,eAAJ,YAAkB,EAAE,GAAG,KAAK;AAAA,MACrD,cAAc,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAAA,MACpE,aAAa,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAAA,MACnE,oBAAoB;AAAA,MACpB,cAAc;AAAA,MACd;AAAA,MACA,KAAK;AAAA,MACL,WAAW;AAAA,MACX,YAAY,CAAC;AAAA,MACb;AAAA,MACA;AAAA,MACA,sBAAsB;AAAA,MACtB,aAAa;AAAA,MACb,OAAO,aAAa;AAAA,MACpB,YAAY,iBAAiB,EAAE;AAAA,MAC/B,YAAW,6BAAM,kBAAiB,UAC9B,UACA,6BAAM,kBAAiB,WACrB,YACA,6BAAM,kBAAiB,aACrB,SACA;AAAA,IACV,CAAC;AAAA,EACH;AAEA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../../../../../../../src/core/components/viewers/map/datasets/src/minioDatasets.ts"],"sourcesContent":["import type { Dataset } from '../../../../../types/datasetTypes'\r\nimport { DatasetGroup } from '../../../../../types/dbTypes'\r\nimport { layerColorByName } from '../../utils/stringToColour'\r\nimport type { AllGeoJSON } from '@turf/turf'\r\n\r\n/**\r\n * Hydrates uploaded GeoJSON datasets persisted via \"Add Dataset\". Looks up\r\n * File rows tagged `organizational-dataset`, reads the bucket from each row's\r\n * description JSON, and builds Dataset entries whose `getFeatures` lazy-loads\r\n * the GeoJSON from MinIO on first render.\r\n */\r\n\r\ninterface OrgDatasetDescription {\r\n bucket?: string\r\n geometryType?: 'points' | 'lines' | 'polygons'\r\n layerStyles?: Record<string, Record<string, string | number>>\r\n tiledTable?: string\r\n tiledAt?: string\r\n featuresIngested?: number\r\n featuresSkipped?: number\r\n}\r\n\r\ninterface RawFileRow {\r\n id: number\r\n type?: string | null\r\n tag?: string | null\r\n name?: string | null\r\n assetId?: string | null\r\n description?: string | null\r\n uploadedAt?: string | Date | null\r\n}\r\n\r\nconst TAG = 'organizational-dataset'\r\n\r\nfunction parseDescription(value: string | null | undefined): OrgDatasetDescription | null {\r\n if (!value) return null\r\n try {\r\n const parsed = JSON.parse(value)\r\n return typeof parsed === 'object' && parsed !== null ? parsed as OrgDatasetDescription : null\r\n }\r\n catch {\r\n return null\r\n }\r\n}\r\n\r\nfunction buildMinioUrl(bucket: string, organizationId: number, assetId: string): string | null {\r\n const base = process.env.NEXT_PUBLIC_MINIO_BUCKET_URL\r\n if (!base) return null\r\n return `${base.replace(/\\/+$/, '')}/${bucket}/${organizationId}/${assetId}`\r\n}\r\n\r\nexport async function fetchOrganizationalMinioDatasets(\r\n organizationId: number,\r\n publishedTilesInCatalog: ReadonlySet<string> = new Set(),\r\n): Promise<Dataset[]> {\r\n let rows: RawFileRow[] = []\r\n try {\r\n const res = await fetch('/api/files')\r\n if (!res.ok) {\r\n console.warn(`fetchOrganizationalMinioDatasets: /api/files returned ${res.status}`)\r\n return []\r\n }\r\n const body = await res.json()\r\n rows = Array.isArray(body?.files) ? body.files : []\r\n }\r\n catch (err) {\r\n console.warn('fetchOrganizationalMinioDatasets: /api/files request failed', err)\r\n return []\r\n }\r\n\r\n const datasets: Dataset[] = []\r\n for (const row of rows) {\r\n if (row.type !== 'map-file') continue\r\n if (row.tag !== TAG) continue\r\n if (!row.assetId) continue\r\n\r\n const meta = parseDescription(row.description)\r\n // Suppress the MinIO entry only once Martin actually serves the published\r\n // table — otherwise the file appears to vanish during the publish→restart\r\n // gap. Un-publish drops the table immediately, so the MinIO row reappears\r\n // on next reload with no extra plumbing.\r\n if (meta?.tiledTable && publishedTilesInCatalog.has(meta.tiledTable)) continue\r\n const bucket = meta?.bucket\r\n if (!bucket) continue\r\n\r\n const sourceUrl = buildMinioUrl(bucket, organizationId, row.assetId)\r\n if (!sourceUrl) continue\r\n\r\n const name = row.name?.replace(/\\.geojson$/i, '') || `Dataset ${row.id}`\r\n const id = `org-minio-${row.id}`\r\n let cached: AllGeoJSON | null = null\r\n\r\n const getFeatures = async (): Promise<AllGeoJSON> => {\r\n if (cached) return cached\r\n const response = await fetch(sourceUrl)\r\n if (!response.ok) {\r\n throw new Error(`Failed to fetch GeoJSON from ${sourceUrl}: ${response.status}`)\r\n }\r\n cached = await response.json() as AllGeoJSON\r\n return cached\r\n }\r\n\r\n const getFields = async () => []\r\n\r\n datasets.push({\r\n id,\r\n name,\r\n type: 'Organizational',\r\n publisher: 'Organizational',\r\n license: 'Unknown',\r\n contact: 'Unknown',\r\n description: `Uploaded ${row.uploadedAt ?? ''}`.trim(),\r\n dateReleased: typeof row.uploadedAt === 'string' ? row.uploadedAt : '',\r\n dateUpdated: typeof row.uploadedAt === 'string' ? row.uploadedAt : '',\r\n countrySubdivision: '',\r\n municipality: '',\r\n sourceUrl,\r\n url: sourceUrl,\r\n clickable: true,\r\n properties: {},\r\n getFeatures,\r\n getFields,\r\n dataManagementSystem: 'other',\r\n datasetType: 'GeoJSON',\r\n group: DatasetGroup.Organizational,\r\n layerColor: layerColorByName(id),\r\n layerType: meta?.geometryType === 'lines'\r\n ? 'line'\r\n : meta?.geometryType === 'points'\r\n ? 'circle'\r\n : meta?.geometryType === 'polygons'\r\n ? 'fill'\r\n : undefined,\r\n })\r\n }\r\n\r\n return datasets\r\n}\r\n"],"mappings":"AACA,SAAS,oBAAoB;AAC7B,SAAS,wBAAwB;AA8BjC,MAAM,MAAM;AAEZ,SAAS,iBAAiB,OAAgE;AACxF,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,WAAO,OAAO,WAAW,YAAY,WAAW,OAAO,SAAkC;AAAA,EAC3F,SACM;AACJ,WAAO;AAAA,EACT;AACF;AAEA,SAAS,cAAc,QAAgB,gBAAwB,SAAgC;AAC7F,QAAM,OAAO,QAAQ,IAAI;AACzB,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,GAAG,KAAK,QAAQ,QAAQ,EAAE,CAAC,IAAI,MAAM,IAAI,cAAc,IAAI,OAAO;AAC3E;AAEA,eAAsB,iCACpB,gBACA,0BAA+C,oBAAI,IAAI,GACnC;AAtDtB;AAuDE,MAAI,OAAqB,CAAC;AAC1B,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,YAAY;AACpC,QAAI,CAAC,IAAI,IAAI;AACX,cAAQ,KAAK,yDAAyD,IAAI,MAAM,EAAE;AAClF,aAAO,CAAC;AAAA,IACV;AACA,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,WAAO,MAAM,QAAQ,6BAAM,KAAK,IAAI,KAAK,QAAQ,CAAC;AAAA,EACpD,SACO,KAAK;AACV,YAAQ,KAAK,+DAA+D,GAAG;AAC/E,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,WAAsB,CAAC;AAC7B,aAAW,OAAO,MAAM;AACtB,QAAI,IAAI,SAAS,WAAY;AAC7B,QAAI,IAAI,QAAQ,IAAK;AACrB,QAAI,CAAC,IAAI,QAAS;AAElB,UAAM,OAAO,iBAAiB,IAAI,WAAW;AAK7C,SAAI,6BAAM,eAAc,wBAAwB,IAAI,KAAK,UAAU,EAAG;AACtE,UAAM,SAAS,6BAAM;AACrB,QAAI,CAAC,OAAQ;AAEb,UAAM,YAAY,cAAc,QAAQ,gBAAgB,IAAI,OAAO;AACnE,QAAI,CAAC,UAAW;AAEhB,UAAM,SAAO,SAAI,SAAJ,mBAAU,QAAQ,eAAe,QAAO,WAAW,IAAI,EAAE;AACtE,UAAM,KAAK,aAAa,IAAI,EAAE;AAC9B,QAAI,SAA4B;AAEhC,UAAM,cAAc,YAAiC;AACnD,UAAI,OAAQ,QAAO;AACnB,YAAM,WAAW,MAAM,MAAM,SAAS;AACtC,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,MAAM,gCAAgC,SAAS,KAAK,SAAS,MAAM,EAAE;AAAA,MACjF;AACA,eAAS,MAAM,SAAS,KAAK;AAC7B,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,YAAY,CAAC;AAE/B,aAAS,KAAK;AAAA,MACZ;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,MACT,SAAS;AAAA,MACT,aAAa,aAAY,SAAI,eAAJ,YAAkB,EAAE,GAAG,KAAK;AAAA,MACrD,cAAc,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAAA,MACpE,aAAa,OAAO,IAAI,eAAe,WAAW,IAAI,aAAa;AAAA,MACnE,oBAAoB;AAAA,MACpB,cAAc;AAAA,MACd;AAAA,MACA,KAAK;AAAA,MACL,WAAW;AAAA,MACX,YAAY,CAAC;AAAA,MACb;AAAA,MACA;AAAA,MACA,sBAAsB;AAAA,MACtB,aAAa;AAAA,MACb,OAAO,aAAa;AAAA,MACpB,YAAY,iBAAiB,EAAE;AAAA,MAC/B,YAAW,6BAAM,kBAAiB,UAC9B,UACA,6BAAM,kBAAiB,WACrB,YACA,6BAAM,kBAAiB,aACrB,SACA;AAAA,IACV,CAAC;AAAA,EACH;AAEA,SAAO;AACT;","names":[]}