@collabdt/core 0.3.1 → 0.3.3

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 (300) hide show
  1. package/dist/core/components/authentication/ForgotPassword.d.ts.map +1 -1
  2. package/dist/core/components/authentication/ForgotPassword.js +0 -1
  3. package/dist/core/components/authentication/ForgotPassword.js.map +1 -1
  4. package/dist/core/components/ui/Comments/CollapsibleCommentItem.d.ts +12 -2
  5. package/dist/core/components/ui/Comments/CollapsibleCommentItem.d.ts.map +1 -1
  6. package/dist/core/components/ui/Comments/CollapsibleCommentItem.js +137 -139
  7. package/dist/core/components/ui/Comments/CollapsibleCommentItem.js.map +1 -1
  8. package/dist/core/components/ui/Comments/Comment.d.ts +18 -1
  9. package/dist/core/components/ui/Comments/Comment.d.ts.map +1 -1
  10. package/dist/core/components/ui/Comments/Comment.js +94 -23
  11. package/dist/core/components/ui/Comments/Comment.js.map +1 -1
  12. package/dist/core/components/ui/Comments/CommentActionButtons.d.ts +38 -0
  13. package/dist/core/components/ui/Comments/CommentActionButtons.d.ts.map +1 -0
  14. package/dist/core/components/ui/Comments/CommentActionButtons.js +134 -0
  15. package/dist/core/components/ui/Comments/CommentActionButtons.js.map +1 -0
  16. package/dist/core/components/ui/Comments/CommentInput.d.ts.map +1 -1
  17. package/dist/core/components/ui/Comments/CommentInput.js +5 -2
  18. package/dist/core/components/ui/Comments/CommentInput.js.map +1 -1
  19. package/dist/core/components/ui/Comments/CommentsSection.d.ts.map +1 -1
  20. package/dist/core/components/ui/Comments/CommentsSection.js +86 -42
  21. package/dist/core/components/ui/Comments/CommentsSection.js.map +1 -1
  22. package/dist/core/components/ui/Comments/commentUtils.d.ts.map +1 -1
  23. package/dist/core/components/ui/Comments/commentUtils.js +2 -1
  24. package/dist/core/components/ui/Comments/commentUtils.js.map +1 -1
  25. package/dist/core/components/ui/FilesManager/src/useFileUploadWithProgress.d.ts.map +1 -1
  26. package/dist/core/components/ui/FilesManager/src/useFileUploadWithProgress.js +0 -1
  27. package/dist/core/components/ui/FilesManager/src/useFileUploadWithProgress.js.map +1 -1
  28. package/dist/core/components/ui/InfoSidebar/Container.d.ts.map +1 -1
  29. package/dist/core/components/ui/InfoSidebar/Container.js +16 -12
  30. package/dist/core/components/ui/InfoSidebar/Container.js.map +1 -1
  31. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts +1 -2
  32. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts.map +1 -1
  33. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js +66 -94
  34. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js.map +1 -1
  35. package/dist/core/components/ui/Sensors/Sensor.d.ts +16 -3
  36. package/dist/core/components/ui/Sensors/Sensor.d.ts.map +1 -1
  37. package/dist/core/components/ui/Sensors/Sensor.js +76 -37
  38. package/dist/core/components/ui/Sensors/Sensor.js.map +1 -1
  39. package/dist/core/components/ui/Sensors/SensorChart.d.ts +12 -2
  40. package/dist/core/components/ui/Sensors/SensorChart.d.ts.map +1 -1
  41. package/dist/core/components/ui/Sensors/SensorChart.js +49 -12
  42. package/dist/core/components/ui/Sensors/SensorChart.js.map +1 -1
  43. package/dist/core/components/ui/Sensors/SensorDetailDialog.d.ts +9 -0
  44. package/dist/core/components/ui/Sensors/SensorDetailDialog.d.ts.map +1 -0
  45. package/dist/core/components/ui/Sensors/SensorDetailDialog.js +128 -0
  46. package/dist/core/components/ui/Sensors/SensorDetailDialog.js.map +1 -0
  47. package/dist/core/components/ui/Sensors/SensorInput.d.ts +6 -1
  48. package/dist/core/components/ui/Sensors/SensorInput.d.ts.map +1 -1
  49. package/dist/core/components/ui/Sensors/SensorInput.js +94 -9
  50. package/dist/core/components/ui/Sensors/SensorInput.js.map +1 -1
  51. package/dist/core/components/ui/Sensors/SensorTagsSection.d.ts +3 -1
  52. package/dist/core/components/ui/Sensors/SensorTagsSection.d.ts.map +1 -1
  53. package/dist/core/components/ui/Sensors/SensorTagsSection.js +4 -1
  54. package/dist/core/components/ui/Sensors/SensorTagsSection.js.map +1 -1
  55. package/dist/core/components/ui/Sensors/SensorsSection.d.ts +1 -3
  56. package/dist/core/components/ui/Sensors/SensorsSection.d.ts.map +1 -1
  57. package/dist/core/components/ui/Sensors/SensorsSection.js +33 -10
  58. package/dist/core/components/ui/Sensors/SensorsSection.js.map +1 -1
  59. package/dist/core/components/ui/Sensors/TimeZoneSelect.d.ts +7 -0
  60. package/dist/core/components/ui/Sensors/TimeZoneSelect.d.ts.map +1 -0
  61. package/dist/core/components/ui/Sensors/TimeZoneSelect.js +56 -0
  62. package/dist/core/components/ui/Sensors/TimeZoneSelect.js.map +1 -0
  63. package/dist/core/components/ui/Sensors/sensorData.d.ts +42 -0
  64. package/dist/core/components/ui/Sensors/sensorData.d.ts.map +1 -0
  65. package/dist/core/components/ui/Sensors/sensorData.js +118 -0
  66. package/dist/core/components/ui/Sensors/sensorData.js.map +1 -0
  67. package/dist/core/components/ui/Sensors/sensorRange.d.ts +24 -0
  68. package/dist/core/components/ui/Sensors/sensorRange.d.ts.map +1 -0
  69. package/dist/core/components/ui/Sensors/sensorRange.js +34 -0
  70. package/dist/core/components/ui/Sensors/sensorRange.js.map +1 -0
  71. package/dist/core/components/ui/Sensors/useSensorSeries.d.ts +15 -0
  72. package/dist/core/components/ui/Sensors/useSensorSeries.d.ts.map +1 -0
  73. package/dist/core/components/ui/Sensors/useSensorSeries.js +63 -0
  74. package/dist/core/components/ui/Sensors/useSensorSeries.js.map +1 -0
  75. package/dist/core/components/ui/Sidebar.d.ts.map +1 -1
  76. package/dist/core/components/ui/Sidebar.js +27 -4
  77. package/dist/core/components/ui/Sidebar.js.map +1 -1
  78. package/dist/core/components/ui/ToolbarButton.d.ts.map +1 -1
  79. package/dist/core/components/ui/ToolbarButton.js +0 -1
  80. package/dist/core/components/ui/ToolbarButton.js.map +1 -1
  81. package/dist/core/components/viewers/Data/advancedFilter/FiltersDialog.d.ts.map +1 -1
  82. package/dist/core/components/viewers/Data/advancedFilter/FiltersDialog.js +0 -2
  83. package/dist/core/components/viewers/Data/advancedFilter/FiltersDialog.js.map +1 -1
  84. package/dist/core/components/viewers/Data/details/EnergySourcesGrid.d.ts.map +1 -1
  85. package/dist/core/components/viewers/Data/details/EnergySourcesGrid.js +0 -10
  86. package/dist/core/components/viewers/Data/details/EnergySourcesGrid.js.map +1 -1
  87. package/dist/core/components/viewers/Data/files/DatatableFileAdder.d.ts.map +1 -1
  88. package/dist/core/components/viewers/Data/files/DatatableFileAdder.js +0 -1
  89. package/dist/core/components/viewers/Data/files/DatatableFileAdder.js.map +1 -1
  90. package/dist/core/components/viewers/Data/files/utils/fuzzySearch.d.ts.map +1 -1
  91. package/dist/core/components/viewers/Data/files/utils/fuzzySearch.js +0 -1
  92. package/dist/core/components/viewers/Data/files/utils/fuzzySearch.js.map +1 -1
  93. package/dist/core/components/viewers/Data/userDetails/UserMoreOptions.d.ts.map +1 -1
  94. package/dist/core/components/viewers/Data/userDetails/UserMoreOptions.js +0 -1
  95. package/dist/core/components/viewers/Data/userDetails/UserMoreOptions.js.map +1 -1
  96. package/dist/core/components/viewers/Data/utils/filterHelper.d.ts.map +1 -1
  97. package/dist/core/components/viewers/Data/utils/filterHelper.js +0 -2
  98. package/dist/core/components/viewers/Data/utils/filterHelper.js.map +1 -1
  99. package/dist/core/components/viewers/Viewer.js +1 -1
  100. package/dist/core/components/viewers/Viewer.js.map +1 -1
  101. package/dist/core/components/viewers/bim/src/BimSidebar/src/CommunicationTab/src/TopicsSection.d.ts.map +1 -1
  102. package/dist/core/components/viewers/bim/src/BimSidebar/src/CommunicationTab/src/TopicsSection.js +0 -3
  103. package/dist/core/components/viewers/bim/src/BimSidebar/src/CommunicationTab/src/TopicsSection.js.map +1 -1
  104. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
  105. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js +1 -7
  106. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js.map +1 -1
  107. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
  108. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.js +1 -9
  109. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
  110. package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.d.ts +1 -3
  111. package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.d.ts.map +1 -1
  112. package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.js +2 -2
  113. package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.js.map +1 -1
  114. package/dist/core/components/viewers/bim/src/BimSidebar/src/TabSelector.d.ts.map +1 -1
  115. package/dist/core/components/viewers/bim/src/BimSidebar/src/TabSelector.js +4 -3
  116. package/dist/core/components/viewers/bim/src/BimSidebar/src/TabSelector.js.map +1 -1
  117. package/dist/core/components/viewers/bim/src/BimSidebar/src/index.js +1 -1
  118. package/dist/core/components/viewers/bim/src/BimSidebar/src/index.js.map +1 -1
  119. package/dist/core/components/viewers/bim/src/ClippingPlane.d.ts.map +1 -1
  120. package/dist/core/components/viewers/bim/src/ClippingPlane.js +0 -1
  121. package/dist/core/components/viewers/bim/src/ClippingPlane.js.map +1 -1
  122. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts +1 -2
  123. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts.map +1 -1
  124. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js +25 -2
  125. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js.map +1 -1
  126. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimComment.d.ts +16 -10
  127. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimComment.d.ts.map +1 -1
  128. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimComment.js +26 -6
  129. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimComment.js.map +1 -1
  130. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimCommentCluster.d.ts +2 -0
  131. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimCommentCluster.d.ts.map +1 -0
  132. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimCommentCluster.js +5 -0
  133. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimCommentCluster.js.map +1 -0
  134. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.d.ts +8 -1
  135. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.d.ts.map +1 -1
  136. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js +15 -3
  137. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js.map +1 -1
  138. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/clusterMarkersByScreenSpace.d.ts +44 -0
  139. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/clusterMarkersByScreenSpace.d.ts.map +1 -0
  140. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/clusterMarkersByScreenSpace.js +77 -0
  141. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/clusterMarkersByScreenSpace.js.map +1 -0
  142. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentCameraUtils.d.ts +3 -0
  143. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentCameraUtils.d.ts.map +1 -0
  144. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentCameraUtils.js +5 -0
  145. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentCameraUtils.js.map +1 -0
  146. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentMarkerConfig.d.ts +33 -0
  147. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentMarkerConfig.d.ts.map +1 -0
  148. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentMarkerConfig.js +90 -0
  149. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentMarkerConfig.js.map +1 -0
  150. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/renderCSS2DMarkers.d.ts.map +1 -1
  151. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/renderCSS2DMarkers.js +2 -2
  152. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/renderCSS2DMarkers.js.map +1 -1
  153. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useCommentMarkers.d.ts +7 -1
  154. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useCommentMarkers.d.ts.map +1 -1
  155. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useCommentMarkers.js +50 -73
  156. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useCommentMarkers.js.map +1 -1
  157. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.d.ts +7 -1
  158. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.d.ts.map +1 -1
  159. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.js +39 -11
  160. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.js.map +1 -1
  161. package/dist/core/components/viewers/bim/src/tools/ClippingTool/ClippingTool.d.ts.map +1 -1
  162. package/dist/core/components/viewers/bim/src/tools/ClippingTool/ClippingTool.js +1 -5
  163. package/dist/core/components/viewers/bim/src/tools/ClippingTool/ClippingTool.js.map +1 -1
  164. package/dist/core/components/viewers/bim/src/tools/ExplodeByLevelTool.d.ts.map +1 -1
  165. package/dist/core/components/viewers/bim/src/tools/ExplodeByLevelTool.js +0 -1
  166. package/dist/core/components/viewers/bim/src/tools/ExplodeByLevelTool.js.map +1 -1
  167. package/dist/core/components/viewers/bim/src/tools/measureBimTool.d.ts.map +1 -1
  168. package/dist/core/components/viewers/bim/src/tools/measureBimTool.js +1 -2
  169. package/dist/core/components/viewers/bim/src/tools/measureBimTool.js.map +1 -1
  170. package/dist/core/components/viewers/map/MapViewer.d.ts +1 -2
  171. package/dist/core/components/viewers/map/MapViewer.d.ts.map +1 -1
  172. package/dist/core/components/viewers/map/MapViewer.js +2 -2
  173. package/dist/core/components/viewers/map/MapViewer.js.map +1 -1
  174. package/dist/core/components/viewers/map/datasets/src/arcGISDatasets.d.ts.map +1 -1
  175. package/dist/core/components/viewers/map/datasets/src/arcGISDatasets.js +11 -14
  176. package/dist/core/components/viewers/map/datasets/src/arcGISDatasets.js.map +1 -1
  177. package/dist/core/components/viewers/map/datasets/src/ckanDatasets.d.ts.map +1 -1
  178. package/dist/core/components/viewers/map/datasets/src/ckanDatasets.js +2 -5
  179. package/dist/core/components/viewers/map/datasets/src/ckanDatasets.js.map +1 -1
  180. package/dist/core/components/viewers/map/datasets/src/localDatasets.d.ts.map +1 -1
  181. package/dist/core/components/viewers/map/datasets/src/localDatasets.js +0 -3
  182. package/dist/core/components/viewers/map/datasets/src/localDatasets.js.map +1 -1
  183. package/dist/core/components/viewers/map/datasets/src/opendatasoftDatasets.d.ts.map +1 -1
  184. package/dist/core/components/viewers/map/datasets/src/opendatasoftDatasets.js +0 -11
  185. package/dist/core/components/viewers/map/datasets/src/opendatasoftDatasets.js.map +1 -1
  186. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.d.ts.map +1 -1
  187. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.js +0 -1
  188. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.js.map +1 -1
  189. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.d.ts.map +1 -1
  190. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js +0 -1
  191. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js.map +1 -1
  192. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.d.ts.map +1 -1
  193. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.js +0 -1
  194. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.js.map +1 -1
  195. package/dist/core/components/viewers/map/src/MapLayers/index.d.ts +1 -2
  196. package/dist/core/components/viewers/map/src/MapLayers/index.d.ts.map +1 -1
  197. package/dist/core/components/viewers/map/src/MapLayers/index.js +2 -2
  198. package/dist/core/components/viewers/map/src/MapLayers/index.js.map +1 -1
  199. package/dist/core/components/viewers/map/src/MapLayers/src/CommentLayer/index.d.ts.map +1 -1
  200. package/dist/core/components/viewers/map/src/MapLayers/src/CommentLayer/index.js +174 -53
  201. package/dist/core/components/viewers/map/src/MapLayers/src/CommentLayer/index.js.map +1 -1
  202. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/components/MapFileManager.d.ts.map +1 -1
  203. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/components/MapFileManager.js +2 -1
  204. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/components/MapFileManager.js.map +1 -1
  205. package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.d.ts +1 -3
  206. package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.d.ts.map +1 -1
  207. package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.js +74 -42
  208. package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.js.map +1 -1
  209. package/dist/core/components/viewers/map/src/MapSidebar/TabSelector.d.ts.map +1 -1
  210. package/dist/core/components/viewers/map/src/MapSidebar/TabSelector.js +4 -3
  211. package/dist/core/components/viewers/map/src/MapSidebar/TabSelector.js.map +1 -1
  212. package/dist/core/components/viewers/map/src/MapSidebar/index.js +1 -1
  213. package/dist/core/components/viewers/map/src/MapSidebar/index.js.map +1 -1
  214. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
  215. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.js +0 -1
  216. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.js.map +1 -1
  217. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
  218. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.js +1 -5
  219. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
  220. package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.d.ts +1 -3
  221. package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.d.ts.map +1 -1
  222. package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.js +2 -2
  223. package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.js.map +1 -1
  224. package/dist/core/components/viewers/map/src/tools/AddTools/AddFile/utils/uploadToPresignedURLS.d.ts.map +1 -1
  225. package/dist/core/components/viewers/map/src/tools/AddTools/AddFile/utils/uploadToPresignedURLS.js +1 -3
  226. package/dist/core/components/viewers/map/src/tools/AddTools/AddFile/utils/uploadToPresignedURLS.js.map +1 -1
  227. package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.d.ts.map +1 -1
  228. package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.js +0 -1
  229. package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.js.map +1 -1
  230. package/dist/core/components/viewers/map/utils/flyToEach.d.ts.map +1 -1
  231. package/dist/core/components/viewers/map/utils/flyToEach.js +0 -1
  232. package/dist/core/components/viewers/map/utils/flyToEach.js.map +1 -1
  233. package/dist/core/components/viewers/map/utils/getOsmIdbyCoordinates.d.ts.map +1 -1
  234. package/dist/core/components/viewers/map/utils/getOsmIdbyCoordinates.js +0 -2
  235. package/dist/core/components/viewers/map/utils/getOsmIdbyCoordinates.js.map +1 -1
  236. package/dist/core/components/viewers/shared/markers/BimMarkerCluster.d.ts +19 -0
  237. package/dist/core/components/viewers/shared/markers/BimMarkerCluster.d.ts.map +1 -0
  238. package/dist/core/components/viewers/shared/markers/BimMarkerCluster.js +108 -0
  239. package/dist/core/components/viewers/shared/markers/BimMarkerCluster.js.map +1 -0
  240. package/dist/core/components/viewers/shared/markers/computeMarkerLookAt.d.ts +24 -0
  241. package/dist/core/components/viewers/shared/markers/computeMarkerLookAt.d.ts.map +1 -0
  242. package/dist/core/components/viewers/shared/markers/computeMarkerLookAt.js +27 -0
  243. package/dist/core/components/viewers/shared/markers/computeMarkerLookAt.js.map +1 -0
  244. package/dist/core/components/viewers/shared/markers/types.d.ts +66 -0
  245. package/dist/core/components/viewers/shared/markers/types.d.ts.map +1 -0
  246. package/dist/core/components/viewers/shared/markers/types.js +1 -0
  247. package/dist/core/components/viewers/shared/markers/types.js.map +1 -0
  248. package/dist/core/components/viewers/shared/markers/useMarkerLayerBim.d.ts +22 -0
  249. package/dist/core/components/viewers/shared/markers/useMarkerLayerBim.d.ts.map +1 -0
  250. package/dist/core/components/viewers/shared/markers/useMarkerLayerBim.js +233 -0
  251. package/dist/core/components/viewers/shared/markers/useMarkerLayerBim.js.map +1 -0
  252. package/dist/core/hooks/comments/comments.d.ts +11 -0
  253. package/dist/core/hooks/comments/comments.d.ts.map +1 -1
  254. package/dist/core/hooks/comments/comments.js +3 -1
  255. package/dist/core/hooks/comments/comments.js.map +1 -1
  256. package/dist/core/hooks/comments/createCommentHooks.d.ts +11 -0
  257. package/dist/core/hooks/comments/createCommentHooks.d.ts.map +1 -1
  258. package/dist/core/hooks/comments/createCommentHooks.js +30 -1
  259. package/dist/core/hooks/comments/createCommentHooks.js.map +1 -1
  260. package/dist/core/hooks/files/files.d.ts.map +1 -1
  261. package/dist/core/hooks/files/files.js +0 -1
  262. package/dist/core/hooks/files/files.js.map +1 -1
  263. package/dist/core/hooks/ui/useResizableSidebarWidth.d.ts +30 -0
  264. package/dist/core/hooks/ui/useResizableSidebarWidth.d.ts.map +1 -0
  265. package/dist/core/hooks/ui/useResizableSidebarWidth.js +75 -0
  266. package/dist/core/hooks/ui/useResizableSidebarWidth.js.map +1 -0
  267. package/dist/core/i18n/messages/en.json +10 -1
  268. package/dist/core/i18n/messages/es.json +11 -2
  269. package/dist/core/i18n/messages/fr.json +11 -2
  270. package/dist/core/store/AppConfig/context.d.ts.map +1 -1
  271. package/dist/core/store/AppConfig/context.js +4 -1
  272. package/dist/core/store/AppConfig/context.js.map +1 -1
  273. package/dist/core/store/AppConfig/reducer.d.ts +10 -0
  274. package/dist/core/store/AppConfig/reducer.d.ts.map +1 -1
  275. package/dist/core/store/AppConfig/reducer.js +10 -0
  276. package/dist/core/store/AppConfig/reducer.js.map +1 -1
  277. package/dist/core/store/Datasets/reducer.d.ts.map +1 -1
  278. package/dist/core/store/Datasets/reducer.js +0 -2
  279. package/dist/core/store/Datasets/reducer.js.map +1 -1
  280. package/dist/core/store/Files/reducer.js +0 -1
  281. package/dist/core/store/Files/reducer.js.map +1 -1
  282. package/dist/core/store/Menus/context.d.ts.map +1 -1
  283. package/dist/core/store/Menus/context.js +8 -2
  284. package/dist/core/store/Menus/context.js.map +1 -1
  285. package/dist/core/store/Menus/reducer.d.ts +65 -1
  286. package/dist/core/store/Menus/reducer.d.ts.map +1 -1
  287. package/dist/core/store/Menus/reducer.js +39 -3
  288. package/dist/core/store/Menus/reducer.js.map +1 -1
  289. package/dist/core/utils/markerUtils.d.ts +10 -0
  290. package/dist/core/utils/markerUtils.d.ts.map +1 -1
  291. package/dist/core/utils/markerUtils.js +9 -1
  292. package/dist/core/utils/markerUtils.js.map +1 -1
  293. package/dist/core/utils/memcache.d.ts.map +1 -1
  294. package/dist/core/utils/memcache.js +0 -7
  295. package/dist/core/utils/memcache.js.map +1 -1
  296. package/dist/core/utils/timeUtils.d.ts +24 -1
  297. package/dist/core/utils/timeUtils.d.ts.map +1 -1
  298. package/dist/core/utils/timeUtils.js +52 -3
  299. package/dist/core/utils/timeUtils.js.map +1 -1
  300. package/package.json +4 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.ts"],"sourcesContent":["\"use client\"\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from \"react\"\r\n\r\nimport { useCoreHooks } from \"../../../../../../../hooks/provider\"\r\nimport { useSensors, useSensor } from \"../../../../../../../hooks/sensors/sensors\"\r\nimport { useSensorTypes } from \"../../../../../../../hooks/sensorTypes/sensorTypes\"\r\nimport { useUsers } from \"../../../../../../../hooks/users/users\"\r\nimport { MenusContext } from \"../../../../../../../store\"\r\nimport { ViewerNames } from \"../../../../../../../types/dbTypes\"\r\nimport { UNTAGGED_TAG } from \"../../../../../../ui/Sensors/SensorsSection\"\r\n\r\nimport BimSensor from \"./BimSensor\"\r\nimport { renderCSS2DMarkers, type MarkerRef } from \"./renderCSS2DMarkers\"\r\n//import { useAppConfigContext } from \"../../../../../../../store/AppConfig/context\"\r\n\r\nexport function useSensorMarkers(world: any, buildingId: number, minioBaseUrl?: string) {\r\n const { state: menusState } = React.useContext(MenusContext)\r\n const { currentSensorId, visibleSensorTypes, visibleSensorTags } = menusState.menus\r\n //const { state: appConfigState } = useAppConfigContext()\r\n\r\n const registry = React.useRef<Map<string, MarkerRef>>(new Map())\r\n\r\n const { sensors } = useSensors()\r\n const { users } = useUsers()\r\n const { sensorTypes } = useSensorTypes()\r\n const coreHooks = useCoreHooks()\r\n\r\n const [sensorToDelete, setSensorToDelete] = React.useState<number | null>(null)\r\n const { deleteSensor } = useSensor(sensorToDelete)\r\n\r\n const eligibleSensors = sensors\r\n .filter((sensor) => {\r\n const { x, y, z, viewer } = sensor\r\n if (x == null || y == null || z == null) return false\r\n if (viewer !== ViewerNames.bim) return false\r\n if (buildingId !== -1 && sensor.buildingId !== buildingId) return false\r\n return true\r\n })\r\n .map((sensor) => {\r\n const user = users.find(u => u.id === sensor.authorId)\r\n const sensorType = sensorTypes.find(t => t.id === sensor.typeId)\r\n return {\r\n ...sensor,\r\n authorName: user?.name ?? \"Unknown User\",\r\n imageFileId: user?.imageFileId ?? \"images/default-avatar.svg\",\r\n sensorType,\r\n }\r\n })\r\n\r\n // Stable ref so the render effect reads current sensors without re-running on every change\r\n const eligibleSensorsRef = React.useRef(eligibleSensors)\r\n eligibleSensorsRef.current = eligibleSensors\r\n\r\n React.useEffect(() => {\r\n if (sensorToDelete !== null) {\r\n deleteSensor()\r\n setSensorToDelete(null)\r\n }\r\n }, [sensorToDelete, deleteSensor])\r\n\r\n const handleRemoveSensor = React.useCallback((sensorId: number) => {\r\n setSensorToDelete(sensorId)\r\n }, [])\r\n\r\n // Pending markers for loading indicators while sensor is being created\r\n const [pendingSensors, setPendingSensors] = React.useState<Array<{ id: number; x: number; y: number; z: number }>>([])\r\n\r\n const addPendingSensor = React.useCallback((position: { x: number; y: number; z: number }) => {\r\n const id = -Date.now()\r\n setPendingSensors(prev => [...prev, { id, ...position }])\r\n return id\r\n }, [])\r\n\r\n const removePendingSensor = React.useCallback((id: number) => {\r\n setPendingSensors(prev => prev.filter(p => p.id !== id))\r\n }, [])\r\n\r\n // Render sensor markers with visibility filtering\r\n React.useEffect(() => {\r\n const typesVisible = visibleSensorTypes?.[ViewerNames.bim] || []\r\n const tagsVisible = visibleSensorTags?.[ViewerNames.bim] || []\r\n\r\n const visibleSensors = eligibleSensorsRef.current.filter(sensor => {\r\n const matchesType = typesVisible.includes(sensor.typeId)\r\n const hasNoTags = !sensor.tags?.length\r\n const matchesTag = hasNoTags\r\n ? tagsVisible.includes(UNTAGGED_TAG)\r\n : sensor.tags?.some((tag: string) => tagsVisible.includes(tag)) ?? false\r\n return matchesType || matchesTag\r\n })\r\n\r\n const allSensors = [\r\n ...visibleSensors.map(s => ({ ...s, isPending: false })),\r\n ...pendingSensors.map(p => ({\r\n id: p.id,\r\n name: \"Creating...\",\r\n sensorType: undefined,\r\n typeId: undefined,\r\n x: p.x,\r\n y: p.y,\r\n z: p.z,\r\n url: \"\",\r\n dataFormat: \"Json\",\r\n updateFrequency: 0,\r\n createdAt: new Date().toISOString(),\r\n buildingId,\r\n tags: [],\r\n isPending: true,\r\n })),\r\n ]\r\n\r\n renderCSS2DMarkers(world, {\r\n items: allSensors,\r\n markerIdKey: \"sensorId\",\r\n registry,\r\n component: BimSensor,\r\n hooksContextValue: coreHooks,\r\n propsMapper: (sensor) => ({\r\n sensorName: sensor.name,\r\n sensorType: sensorTypes.find(t => t.id === sensor.typeId),\r\n tags: sensor.tags,\r\n dataUrl: sensor.url?.startsWith(\"http\")\r\n ? sensor.url\r\n : minioBaseUrl\r\n ? `${minioBaseUrl}/sensors/${sensor.url}`\r\n : \"\",\r\n dataFormat: sensor.dataFormat,\r\n updateFrequency: sensor.updateFrequency,\r\n buildingId: sensor.buildingId,\r\n timestamp: new Date(sensor.createdAt),\r\n highlight: currentSensorId === sensor.id,\r\n }),\r\n sphereColor: \"#10b981\",\r\n isVisible: true,\r\n onRemove: handleRemoveSensor,\r\n })\r\n }, [world, sensors, pendingSensors, handleRemoveSensor, visibleSensorTypes, visibleSensorTags, buildingId, currentSensorId, sensorTypes, coreHooks])\r\n\r\n const sensorCount = sensors.filter(\r\n s => s.viewer === ViewerNames.bim && (!buildingId || buildingId === -1 || s.buildingId === buildingId)\r\n ).length\r\n\r\n return { addPendingSensor, removePendingSensor, sensorCount }\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAKA,YAAY,WAAW;AAEvB,SAAS,oBAAoB;AAC7B,SAAS,YAAY,iBAAiB;AACtC,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB;AACzB,SAAS,oBAAoB;AAC7B,SAAS,mBAAmB;AAC5B,SAAS,oBAAoB;AAE7B,OAAO,eAAe;AACtB,SAAS,0BAA0C;AAG5C,SAAS,iBAAiB,OAAY,YAAoB,cAAuB;AACtF,QAAM,EAAE,OAAO,WAAW,IAAI,MAAM,WAAW,YAAY;AAC3D,QAAM,EAAE,iBAAiB,oBAAoB,kBAAkB,IAAI,WAAW;AAG9E,QAAM,WAAW,MAAM,OAA+B,oBAAI,IAAI,CAAC;AAE/D,QAAM,EAAE,QAAQ,IAAI,WAAW;AAC/B,QAAM,EAAE,MAAM,IAAI,SAAS;AAC3B,QAAM,EAAE,YAAY,IAAI,eAAe;AACvC,QAAM,YAAY,aAAa;AAE/B,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAwB,IAAI;AAC9E,QAAM,EAAE,aAAa,IAAI,UAAU,cAAc;AAEjD,QAAM,kBAAkB,QACrB,OAAO,CAAC,WAAW;AAClB,UAAM,EAAE,GAAG,GAAG,GAAG,OAAO,IAAI;AAC5B,QAAI,KAAK,QAAQ,KAAK,QAAQ,KAAK,KAAM,QAAO;AAChD,QAAI,WAAW,YAAY,IAAK,QAAO;AACvC,QAAI,eAAe,MAAM,OAAO,eAAe,WAAY,QAAO;AAClE,WAAO;AAAA,EACT,CAAC,EACA,IAAI,CAAC,WAAW;AA1CrB;AA2CM,UAAM,OAAO,MAAM,KAAK,OAAK,EAAE,OAAO,OAAO,QAAQ;AACrD,UAAM,aAAa,YAAY,KAAK,OAAK,EAAE,OAAO,OAAO,MAAM;AAC/D,WAAO,iCACF,SADE;AAAA,MAEL,aAAY,kCAAM,SAAN,YAAc;AAAA,MAC1B,cAAa,kCAAM,gBAAN,YAAqB;AAAA,MAClC;AAAA,IACF;AAAA,EACF,CAAC;AAGH,QAAM,qBAAqB,MAAM,OAAO,eAAe;AACvD,qBAAmB,UAAU;AAE7B,QAAM,UAAU,MAAM;AACpB,QAAI,mBAAmB,MAAM;AAC3B,mBAAa;AACb,wBAAkB,IAAI;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,gBAAgB,YAAY,CAAC;AAEjC,QAAM,qBAAqB,MAAM,YAAY,CAAC,aAAqB;AACjE,sBAAkB,QAAQ;AAAA,EAC5B,GAAG,CAAC,CAAC;AAGL,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAiE,CAAC,CAAC;AAErH,QAAM,mBAAmB,MAAM,YAAY,CAAC,aAAkD;AAC5F,UAAM,KAAK,CAAC,KAAK,IAAI;AACrB,sBAAkB,UAAQ,CAAC,GAAG,MAAM,iBAAE,MAAO,SAAU,CAAC;AACxD,WAAO;AAAA,EACT,GAAG,CAAC,CAAC;AAEL,QAAM,sBAAsB,MAAM,YAAY,CAAC,OAAe;AAC5D,sBAAkB,UAAQ,KAAK,OAAO,OAAK,EAAE,OAAO,EAAE,CAAC;AAAA,EACzD,GAAG,CAAC,CAAC;AAGL,QAAM,UAAU,MAAM;AACpB,UAAM,gBAAe,yDAAqB,YAAY,SAAQ,CAAC;AAC/D,UAAM,eAAc,uDAAoB,YAAY,SAAQ,CAAC;AAE7D,UAAM,iBAAiB,mBAAmB,QAAQ,OAAO,YAAU;AAtFvE;AAuFM,YAAM,cAAc,aAAa,SAAS,OAAO,MAAM;AACvD,YAAM,YAAY,GAAC,YAAO,SAAP,mBAAa;AAChC,YAAM,aAAa,YACf,YAAY,SAAS,YAAY,KACjC,kBAAO,SAAP,mBAAa,KAAK,CAAC,QAAgB,YAAY,SAAS,GAAG,OAA3D,YAAiE;AACrE,aAAO,eAAe;AAAA,IACxB,CAAC;AAED,UAAM,aAAa;AAAA,MACjB,GAAG,eAAe,IAAI,OAAM,iCAAK,IAAL,EAAQ,WAAW,MAAM,EAAE;AAAA,MACvD,GAAG,eAAe,IAAI,QAAM;AAAA,QAC1B,IAAI,EAAE;AAAA,QACN,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,QAAQ;AAAA,QACR,GAAG,EAAE;AAAA,QACL,GAAG,EAAE;AAAA,QACL,GAAG,EAAE;AAAA,QACL,KAAK;AAAA,QACL,YAAY;AAAA,QACZ,iBAAiB;AAAA,QACjB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QAClC;AAAA,QACA,MAAM,CAAC;AAAA,QACP,WAAW;AAAA,MACb,EAAE;AAAA,IACJ;AAEA,uBAAmB,OAAO;AAAA,MACxB,OAAO;AAAA,MACP,aAAa;AAAA,MACb;AAAA,MACA,WAAW;AAAA,MACX,mBAAmB;AAAA,MACnB,aAAa,CAAC,WAAQ;AAzH5B;AAyHgC;AAAA,UACxB,YAAY,OAAO;AAAA,UACnB,YAAY,YAAY,KAAK,OAAK,EAAE,OAAO,OAAO,MAAM;AAAA,UACxD,MAAM,OAAO;AAAA,UACb,WAAS,YAAO,QAAP,mBAAY,WAAW,WAC5B,OAAO,MACP,eACE,GAAG,YAAY,YAAY,OAAO,GAAG,KACrC;AAAA,UACN,YAAY,OAAO;AAAA,UACnB,iBAAiB,OAAO;AAAA,UACxB,YAAY,OAAO;AAAA,UACnB,WAAW,IAAI,KAAK,OAAO,SAAS;AAAA,UACpC,WAAW,oBAAoB,OAAO;AAAA,QACxC;AAAA;AAAA,MACA,aAAa;AAAA,MACb,WAAW;AAAA,MACX,UAAU;AAAA,IACZ,CAAC;AAAA,EACH,GAAG,CAAC,OAAO,SAAS,gBAAgB,oBAAoB,oBAAoB,mBAAmB,YAAY,iBAAiB,aAAa,SAAS,CAAC;AAEnJ,QAAM,cAAc,QAAQ;AAAA,IAC1B,OAAK,EAAE,WAAW,YAAY,QAAQ,CAAC,cAAc,eAAe,MAAM,EAAE,eAAe;AAAA,EAC7F,EAAE;AAEF,SAAO,EAAE,kBAAkB,qBAAqB,YAAY;AAC9D;","names":[]}
1
+ {"version":3,"sources":["../../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.ts"],"sourcesContent":["\"use client\"\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport { useSession } from \"next-auth/react\"\r\nimport { useTranslations } from \"next-intl\"\r\nimport * as React from \"react\"\r\n\r\nimport { useCoreHooks } from \"../../../../../../../hooks/provider\"\r\nimport { useSensors, useSensor } from \"../../../../../../../hooks/sensors/sensors\"\r\nimport { useSensorTypes } from \"../../../../../../../hooks/sensorTypes/sensorTypes\"\r\nimport { useUsers } from \"../../../../../../../hooks/users/users\"\r\nimport { AppConfigContext, MenusContext } from \"../../../../../../../store\"\r\nimport { ViewerNames, type Sensor } from \"../../../../../../../types/dbTypes\"\r\nimport { UNTAGGED_TAG } from \"../../../../../../ui/Sensors/SensorsSection\"\r\n\r\nimport BimSensor from \"./BimSensor\"\r\nimport { renderCSS2DMarkers, type MarkerRef } from \"./renderCSS2DMarkers\"\r\n\r\nexport function useSensorMarkers(world: any, buildingId: number) {\r\n const { state: menusState } = React.useContext(MenusContext)\r\n const { currentSensorId, visibleSensorTypes, visibleSensorTags } = menusState.menus\r\n const { state: appConfigState } = React.useContext(AppConfigContext)\r\n const timeZone = appConfigState.appConfig.displayTimeZone\r\n const sessionUser = useSession().data?.user\r\n const tr = useTranslations('SensorsSection')\r\n const actionLabels = { expand: tr('expandSensor'), edit: tr('editSensor'), delete: tr('deleteSensor') }\r\n const [detailSensor, setDetailSensor] = React.useState<Sensor | null>(null)\r\n const [editSensor, setEditSensor] = React.useState<Sensor | null>(null)\r\n\r\n const registry = React.useRef<Map<string, MarkerRef>>(new Map())\r\n\r\n const { sensors } = useSensors()\r\n const { users } = useUsers()\r\n const { sensorTypes } = useSensorTypes()\r\n const coreHooks = useCoreHooks()\r\n\r\n const [sensorToDelete, setSensorToDelete] = React.useState<number | null>(null)\r\n const { deleteSensor } = useSensor(sensorToDelete)\r\n\r\n const eligibleSensors = sensors\r\n .filter((sensor) => {\r\n const { x, y, z, viewer } = sensor\r\n if (x == null || y == null || z == null) return false\r\n if (viewer !== ViewerNames.bim) return false\r\n if (buildingId !== -1 && sensor.buildingId !== buildingId) return false\r\n return true\r\n })\r\n .map((sensor) => {\r\n const user = users.find(u => u.id === sensor.authorId)\r\n const sensorType = sensorTypes.find(t => t.id === sensor.typeId)\r\n return {\r\n ...sensor,\r\n authorName: user?.name ?? \"Unknown User\",\r\n imageFileId: user?.imageFileId ?? \"images/default-avatar.svg\",\r\n sensorType,\r\n }\r\n })\r\n\r\n // Stable ref so the render effect reads current sensors without re-running on every change\r\n const eligibleSensorsRef = React.useRef(eligibleSensors)\r\n eligibleSensorsRef.current = eligibleSensors\r\n\r\n React.useEffect(() => {\r\n if (sensorToDelete !== null) {\r\n deleteSensor()\r\n setSensorToDelete(null)\r\n }\r\n }, [sensorToDelete, deleteSensor])\r\n\r\n const handleRemoveSensor = React.useCallback((sensorId: number) => {\r\n setSensorToDelete(sensorId)\r\n }, [])\r\n\r\n // Pending markers for loading indicators while sensor is being created\r\n const [pendingSensors, setPendingSensors] = React.useState<Array<{ id: number; x: number; y: number; z: number }>>([])\r\n\r\n const addPendingSensor = React.useCallback((position: { x: number; y: number; z: number }) => {\r\n const id = -Date.now()\r\n setPendingSensors(prev => [...prev, { id, ...position }])\r\n return id\r\n }, [])\r\n\r\n const removePendingSensor = React.useCallback((id: number) => {\r\n setPendingSensors(prev => prev.filter(p => p.id !== id))\r\n }, [])\r\n\r\n // Render sensor markers with visibility filtering\r\n React.useEffect(() => {\r\n const typesVisible = visibleSensorTypes?.[ViewerNames.bim] || []\r\n const tagsVisible = visibleSensorTags?.[ViewerNames.bim] || []\r\n\r\n const visibleSensors = eligibleSensorsRef.current.filter(sensor => {\r\n const matchesType = typesVisible.includes(sensor.typeId)\r\n const hasNoTags = !sensor.tags?.length\r\n const matchesTag = hasNoTags\r\n ? tagsVisible.includes(UNTAGGED_TAG)\r\n : sensor.tags?.some((tag: string) => tagsVisible.includes(tag)) ?? false\r\n return matchesType || matchesTag\r\n })\r\n\r\n const allSensors = [\r\n ...visibleSensors.map(s => ({ ...s, isPending: false })),\r\n ...pendingSensors.map(p => ({\r\n id: p.id,\r\n name: \"Creating...\",\r\n sensorType: undefined,\r\n typeId: undefined,\r\n x: p.x,\r\n y: p.y,\r\n z: p.z,\r\n url: \"\",\r\n dataFormat: \"Json\",\r\n updateFrequency: 0,\r\n createdAt: new Date().toISOString(),\r\n buildingId,\r\n tags: [],\r\n authorId: -1,\r\n isPending: true,\r\n })),\r\n ]\r\n\r\n renderCSS2DMarkers(world, {\r\n items: allSensors,\r\n markerIdKey: \"sensorId\",\r\n registry,\r\n component: BimSensor,\r\n hooksContextValue: coreHooks,\r\n propsMapper: (sensor) => ({\r\n sensorName: sensor.name,\r\n sensorType: sensorTypes.find(t => t.id === sensor.typeId),\r\n tags: sensor.tags,\r\n dataUrl: sensor.url ?? \"\",\r\n dataFormat: sensor.dataFormat,\r\n updateFrequency: sensor.updateFrequency,\r\n buildingId: sensor.buildingId,\r\n timestamp: new Date(sensor.createdAt),\r\n highlight: currentSensorId === sensor.id,\r\n timeZone,\r\n showActions: true,\r\n onExpand: () => setDetailSensor(sensor as unknown as Sensor),\r\n onEdit: () => setEditSensor(sensor as unknown as Sensor),\r\n actionLabels,\r\n canEdit: sessionUser?.id === String(sensor.authorId),\r\n canDelete: sessionUser?.id === String(sensor.authorId),\r\n }),\r\n sphereColor: \"#10b981\",\r\n isVisible: true,\r\n onRemove: handleRemoveSensor,\r\n })\r\n }, [world, sensors, pendingSensors, handleRemoveSensor, visibleSensorTypes, visibleSensorTags, buildingId, currentSensorId, sensorTypes, coreHooks, timeZone, sessionUser?.id])\r\n\r\n const sensorCount = sensors.filter(\r\n s => s.viewer === ViewerNames.bim && (!buildingId || buildingId === -1 || s.buildingId === buildingId)\r\n ).length\r\n\r\n const detailSensorType = detailSensor ? sensorTypes.find(t => t.id === detailSensor.typeId) : undefined\r\n\r\n return {\r\n addPendingSensor,\r\n removePendingSensor,\r\n sensorCount,\r\n detailSensor,\r\n detailSensorType,\r\n closeSensorDetail: () => setDetailSensor(null),\r\n editSensor,\r\n closeSensorEdit: () => setEditSensor(null),\r\n }\r\n}\r\n"],"mappings":"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","names":["_a"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ClippingTool.d.ts","sourceRoot":"","sources":["../../../../../../../../src/core/components/viewers/bim/src/tools/ClippingTool/ClippingTool.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAmB/B,OAAO,KAAK,EAAE,IAAI,EAAmB,MAAM,+BAA+B,CAAA;AAI1E,UAAU,iBAAiB;IACzB,IAAI,EAAE,IAAI,CAAA;CACX;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CAoKpD,CAAA"}
1
+ {"version":3,"file":"ClippingTool.d.ts","sourceRoot":"","sources":["../../../../../../../../src/core/components/viewers/bim/src/tools/ClippingTool/ClippingTool.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAmB/B,OAAO,KAAK,EAAE,IAAI,EAAmB,MAAM,+BAA+B,CAAA;AAI1E,UAAU,iBAAiB;IACzB,IAAI,EAAE,IAAI,CAAA;CACX;AAED,eAAO,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,iBAAiB,CA+JpD,CAAA"}
@@ -40,7 +40,6 @@ const ClippingTool = ({ tool }) => {
40
40
  };
41
41
  const removeAllClippingPlanes = React.useCallback(() => {
42
42
  if (!world || !bimComponents) return;
43
- console.log("Remove all clipping planes");
44
43
  bimComponents.get(OBC.Clipper).deleteAll();
45
44
  }, [world, bimComponents]);
46
45
  const handleCreateClippingPlane = React.useCallback(async () => {
@@ -89,10 +88,7 @@ const ClippingTool = ({ tool }) => {
89
88
  items: { All: { style: "Black" } }
90
89
  });
91
90
  });
92
- const result = await clipper.create(world);
93
- if (result) {
94
- console.log(result);
95
- }
91
+ await clipper.create(world);
96
92
  }, [world, bimComponents]);
97
93
  React.useEffect(() => {
98
94
  keydownRef.current = (event) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../../src/core/components/viewers/bim/src/tools/ClippingTool/ClippingTool.tsx"],"sourcesContent":["\"use client\"\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Dependencies\r\nimport * as OBC from '@thatopen/components'\r\nimport * as OBF from \"@thatopen/components-front\"\r\nimport * as LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from \"react\";\r\nimport * as THREE from \"three\";\r\nimport { LineMaterial } from \"three/examples/jsm/lines/LineMaterial.js\";\r\n\r\n// Utilities\r\nimport { MenusContext, ToolsContext } from '../../../../../../store'\r\nimport { BimContext } from '../../../../../../store'\r\n\r\n\r\n// Shadcn components\r\nimport { ToolbarSubmenu, SubmenuContext } from '../../../../../ToolbarSubmenu'\r\nimport { Button } from '../../../../../ui/Button'\r\nimport { Card, CardContent, CardHeader, CardTitle } from '../../../../../ui/Card'\r\nimport { DropdownMenuItem } from '../../../../../ui/DropdownMenu'\r\n\r\n// Icons\r\nimport { Cursor } from '../../Cursor'\r\n\r\nimport type { CursorType } from '../../../../../../types/global'\r\nimport type { Tool, ToolbarToolType } from '../../../../../../types/tools'\r\n\r\n// Submenu wrapper\r\n\r\ninterface ClippingToolProps {\r\n tool: Tool\r\n}\r\n\r\nexport const ClippingTool: React.FC<ClippingToolProps> = ({ tool }) => {\r\n const { dispatch: toolsDispatch, state: toolsState } = React.useContext(ToolsContext)\r\n const { dispatch: menusDispatch } = React.useContext(MenusContext)\r\n const { state: bimState } = React.useContext(BimContext)\r\n const { bimComponents, world } = bimState.bim\r\n\r\n const [active, setActive] = React.useState(false)\r\n const keydownRef = React.useRef<(e: KeyboardEvent) => void>(() => {})\r\n\r\n const setCursor = (cursor: CursorType) => {\r\n if (!bimComponents) return\r\n const currentCursor = bimComponents.get(Cursor)\r\n if (!currentCursor) return\r\n currentCursor.cursor = cursor\r\n }\r\n\r\n const setTools = (currentToolId: ToolbarToolType) => {\r\n toolsDispatch({\r\n type: 'SET-TOOL',\r\n payload: { currentToolId },\r\n })\r\n }\r\n\r\n const flipAddingPlaneState = async () => {\r\n const _active = !active\r\n\r\n setActive(_active)\r\n setTools(_active ? tool.id : null)\r\n setCursor(_active ? 'crosshair' : '')\r\n }\r\n\r\n const removeAllClippingPlanes = React.useCallback(() => {\r\n if (!world || !bimComponents) return\r\n console.log(\"Remove all clipping planes\")\r\n bimComponents.get(OBC.Clipper).deleteAll()\r\n }, [world, bimComponents])\r\n\r\n //use effect to handle controlling the state of adding clipping plane\r\n const handleCreateClippingPlane = React.useCallback(async () => {\r\n if (!world || !bimComponents) return\r\n // set up\r\n const casters = bimComponents.get(OBC.Raycasters)\r\n casters.get(world)\r\n\r\n //styling\r\n const clipStyler = bimComponents.get(OBF.ClipStyler)\r\n clipStyler.world = world;\r\n clipStyler.styles.set(\"Black\", {\r\n linesMaterial: new LineMaterial({\r\n color: \"black\",\r\n linewidth: 2, // thick, screen-space lines\r\n }),\r\n fillsMaterial: new THREE.MeshBasicMaterial({\r\n color: 0x000000,\r\n side: THREE.DoubleSide, // see the cap from both sides\r\n // transparent: true, // enable opacity blending\r\n // opacity: 0.2, // soft see-through cap\r\n // depthWrite: false, // reduce sorting issues with transparency\r\n // polygonOffset: true, // nudge to prevent z-fighting\r\n // polygonOffsetFactor: -2,\r\n // polygonOffsetUnits: 1,\r\n }),\r\n });\r\n\r\n //set up items to be filled\r\n const finder = bimComponents.get(OBC.ItemsFinder);\r\n finder.create(\"Walls\", [{ categories: [/WALL/] }]);\r\n finder.create(\"Slabs\", [{ categories: [/SLAB/] }]);\r\n finder.create(\"Columns\", [{ categories: [/COLUMN/] }]);\r\n finder.create(\"Doors\", [{ categories: [/DOOR/] }]);\r\n finder.create(\"Curtains\", [{ categories: [/PLATE/, /MEMBER/] }]);\r\n finder.create(\"Windows\", [{ categories: [/WINDOW/] }]);\r\n\r\n const classifier = bimComponents.get(OBC.Classifier);\r\n const classificationName = \"ClipperGroups\";\r\n classifier.setGroupQuery(classificationName, \"Walls\", { name: \"Walls\" });\r\n classifier.setGroupQuery(classificationName, \"Slabs\", { name: \"Slabs\" });\r\n classifier.setGroupQuery(classificationName, \"Columns\", { name: \"Columns\" });\r\n classifier.setGroupQuery(classificationName, \"Doors\", { name: \"Doors\" });\r\n classifier.setGroupQuery(classificationName, \"Curtains\", { name: \"Curtains\" });\r\n classifier.setGroupQuery(classificationName, \"Windows\", { name: \"Windows\" });\r\n\r\n //Create clipper\r\n const clipper = bimComponents.get(OBC.Clipper)\r\n clipper.enabled = true\r\n\r\n //Apply styling\r\n clipper.list.onItemSet.add(({ key }) => {\r\n clipStyler.createFromClipping(key, {\r\n items: { All: { style: \"Black\" } },\r\n });\r\n });\r\n\r\n const result = await clipper.create(world)\r\n\r\n if (result) {\r\n console.log(result)\r\n }\r\n }, [world, bimComponents])\r\n\r\n React.useEffect(() => {\r\n keydownRef.current = (event: KeyboardEvent) => {\r\n if (event.key === 'Backspace') {\r\n // Remove the clipping plane under the cursor\r\n if (!world || !bimComponents) return\r\n bimComponents.get(OBC.Clipper).delete(world, undefined)\r\n }\r\n }\r\n }, [world, bimComponents])\r\n\r\n const handleKeyDown = React.useCallback((e: KeyboardEvent) => {\r\n keydownRef.current?.(e)\r\n }, [])\r\n\r\n // Handle deleting plane using Backspace\r\n React.useEffect(() => {\r\n if (!active) {\r\n window.removeEventListener('keydown', handleKeyDown)\r\n return\r\n }\r\n window.addEventListener('keydown', handleKeyDown)\r\n return () => {\r\n window.removeEventListener('keydown', handleKeyDown)\r\n }\r\n }, [active, handleKeyDown])\r\n\r\n React.useEffect (() => {\r\n if (!world || !bimComponents) return\r\n\r\n const container = world.renderer.three.domElement\r\n\r\n if (active) {\r\n container.addEventListener(\"dblclick\", handleCreateClippingPlane)\r\n }\r\n else {\r\n container.removeEventListener(\"dblclick\", handleCreateClippingPlane)\r\n }\r\n\r\n }, [active, world, bimComponents])\r\n\r\n return (\r\n <div>\r\n <ToolbarSubmenu tool={tool}>\r\n <DropdownMenuItem onClick={flipAddingPlaneState}>\r\n <LR.PlusSquare />\r\n <span>{active? 'Cancel add' : 'Add'} clipping Plane</span>\r\n </DropdownMenuItem>\r\n\r\n <DropdownMenuItem onClick={() => removeAllClippingPlanes()}>\r\n <LR.Trash2/>\r\n <span> Delete all clipping planes</span>\r\n </DropdownMenuItem>\r\n </ToolbarSubmenu>\r\n\r\n {active &&\r\n <Card className=\"p-3 absolute bottom-10 left-0 bg-background shadow-md z-10 w-full\">\r\n <span className=\"text-muted-foreground text-xs\">\r\n Double click on the model to add a clipping plane. Press Backspace to remove the clipping plane.\r\n </span>\r\n </Card>\r\n }\r\n </div>\r\n\r\n )\r\n}"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../../../../src/core/components/viewers/bim/src/tools/ClippingTool/ClippingTool.tsx"],"sourcesContent":["\"use client\"\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Dependencies\r\nimport * as OBC from '@thatopen/components'\r\nimport * as OBF from \"@thatopen/components-front\"\r\nimport * as LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from \"react\";\r\nimport * as THREE from \"three\";\r\nimport { LineMaterial } from \"three/examples/jsm/lines/LineMaterial.js\";\r\n\r\n// Utilities\r\nimport { MenusContext, ToolsContext } from '../../../../../../store'\r\nimport { BimContext } from '../../../../../../store'\r\n\r\n\r\n// Shadcn components\r\nimport { ToolbarSubmenu, SubmenuContext } from '../../../../../ToolbarSubmenu'\r\nimport { Button } from '../../../../../ui/Button'\r\nimport { Card, CardContent, CardHeader, CardTitle } from '../../../../../ui/Card'\r\nimport { DropdownMenuItem } from '../../../../../ui/DropdownMenu'\r\n\r\n// Icons\r\nimport { Cursor } from '../../Cursor'\r\n\r\nimport type { CursorType } from '../../../../../../types/global'\r\nimport type { Tool, ToolbarToolType } from '../../../../../../types/tools'\r\n\r\n// Submenu wrapper\r\n\r\ninterface ClippingToolProps {\r\n tool: Tool\r\n}\r\n\r\nexport const ClippingTool: React.FC<ClippingToolProps> = ({ tool }) => {\r\n const { dispatch: toolsDispatch, state: toolsState } = React.useContext(ToolsContext)\r\n const { dispatch: menusDispatch } = React.useContext(MenusContext)\r\n const { state: bimState } = React.useContext(BimContext)\r\n const { bimComponents, world } = bimState.bim\r\n\r\n const [active, setActive] = React.useState(false)\r\n const keydownRef = React.useRef<(e: KeyboardEvent) => void>(() => {})\r\n\r\n const setCursor = (cursor: CursorType) => {\r\n if (!bimComponents) return\r\n const currentCursor = bimComponents.get(Cursor)\r\n if (!currentCursor) return\r\n currentCursor.cursor = cursor\r\n }\r\n\r\n const setTools = (currentToolId: ToolbarToolType) => {\r\n toolsDispatch({\r\n type: 'SET-TOOL',\r\n payload: { currentToolId },\r\n })\r\n }\r\n\r\n const flipAddingPlaneState = async () => {\r\n const _active = !active\r\n\r\n setActive(_active)\r\n setTools(_active ? tool.id : null)\r\n setCursor(_active ? 'crosshair' : '')\r\n }\r\n\r\n const removeAllClippingPlanes = React.useCallback(() => {\r\n if (!world || !bimComponents) return\r\n bimComponents.get(OBC.Clipper).deleteAll()\r\n }, [world, bimComponents])\r\n\r\n //use effect to handle controlling the state of adding clipping plane\r\n const handleCreateClippingPlane = React.useCallback(async () => {\r\n if (!world || !bimComponents) return\r\n // set up\r\n const casters = bimComponents.get(OBC.Raycasters)\r\n casters.get(world)\r\n\r\n //styling\r\n const clipStyler = bimComponents.get(OBF.ClipStyler)\r\n clipStyler.world = world;\r\n clipStyler.styles.set(\"Black\", {\r\n linesMaterial: new LineMaterial({\r\n color: \"black\",\r\n linewidth: 2, // thick, screen-space lines\r\n }),\r\n fillsMaterial: new THREE.MeshBasicMaterial({\r\n color: 0x000000,\r\n side: THREE.DoubleSide, // see the cap from both sides\r\n // transparent: true, // enable opacity blending\r\n // opacity: 0.2, // soft see-through cap\r\n // depthWrite: false, // reduce sorting issues with transparency\r\n // polygonOffset: true, // nudge to prevent z-fighting\r\n // polygonOffsetFactor: -2,\r\n // polygonOffsetUnits: 1,\r\n }),\r\n });\r\n\r\n //set up items to be filled\r\n const finder = bimComponents.get(OBC.ItemsFinder);\r\n finder.create(\"Walls\", [{ categories: [/WALL/] }]);\r\n finder.create(\"Slabs\", [{ categories: [/SLAB/] }]);\r\n finder.create(\"Columns\", [{ categories: [/COLUMN/] }]);\r\n finder.create(\"Doors\", [{ categories: [/DOOR/] }]);\r\n finder.create(\"Curtains\", [{ categories: [/PLATE/, /MEMBER/] }]);\r\n finder.create(\"Windows\", [{ categories: [/WINDOW/] }]);\r\n\r\n const classifier = bimComponents.get(OBC.Classifier);\r\n const classificationName = \"ClipperGroups\";\r\n classifier.setGroupQuery(classificationName, \"Walls\", { name: \"Walls\" });\r\n classifier.setGroupQuery(classificationName, \"Slabs\", { name: \"Slabs\" });\r\n classifier.setGroupQuery(classificationName, \"Columns\", { name: \"Columns\" });\r\n classifier.setGroupQuery(classificationName, \"Doors\", { name: \"Doors\" });\r\n classifier.setGroupQuery(classificationName, \"Curtains\", { name: \"Curtains\" });\r\n classifier.setGroupQuery(classificationName, \"Windows\", { name: \"Windows\" });\r\n\r\n //Create clipper\r\n const clipper = bimComponents.get(OBC.Clipper)\r\n clipper.enabled = true\r\n\r\n //Apply styling\r\n clipper.list.onItemSet.add(({ key }) => {\r\n clipStyler.createFromClipping(key, {\r\n items: { All: { style: \"Black\" } },\r\n });\r\n });\r\n\r\n await clipper.create(world)\r\n }, [world, bimComponents])\r\n\r\n React.useEffect(() => {\r\n keydownRef.current = (event: KeyboardEvent) => {\r\n if (event.key === 'Backspace') {\r\n // Remove the clipping plane under the cursor\r\n if (!world || !bimComponents) return\r\n bimComponents.get(OBC.Clipper).delete(world, undefined)\r\n }\r\n }\r\n }, [world, bimComponents])\r\n\r\n const handleKeyDown = React.useCallback((e: KeyboardEvent) => {\r\n keydownRef.current?.(e)\r\n }, [])\r\n\r\n // Handle deleting plane using Backspace\r\n React.useEffect(() => {\r\n if (!active) {\r\n window.removeEventListener('keydown', handleKeyDown)\r\n return\r\n }\r\n window.addEventListener('keydown', handleKeyDown)\r\n return () => {\r\n window.removeEventListener('keydown', handleKeyDown)\r\n }\r\n }, [active, handleKeyDown])\r\n\r\n React.useEffect (() => {\r\n if (!world || !bimComponents) return\r\n\r\n const container = world.renderer.three.domElement\r\n\r\n if (active) {\r\n container.addEventListener(\"dblclick\", handleCreateClippingPlane)\r\n }\r\n else {\r\n container.removeEventListener(\"dblclick\", handleCreateClippingPlane)\r\n }\r\n\r\n }, [active, world, bimComponents])\r\n\r\n return (\r\n <div>\r\n <ToolbarSubmenu tool={tool}>\r\n <DropdownMenuItem onClick={flipAddingPlaneState}>\r\n <LR.PlusSquare />\r\n <span>{active? 'Cancel add' : 'Add'} clipping Plane</span>\r\n </DropdownMenuItem>\r\n\r\n <DropdownMenuItem onClick={() => removeAllClippingPlanes()}>\r\n <LR.Trash2/>\r\n <span> Delete all clipping planes</span>\r\n </DropdownMenuItem>\r\n </ToolbarSubmenu>\r\n\r\n {active &&\r\n <Card className=\"p-3 absolute bottom-10 left-0 bg-background shadow-md z-10 w-full\">\r\n <span className=\"text-muted-foreground text-xs\">\r\n Double click on the model to add a clipping plane. Press Backspace to remove the clipping plane.\r\n </span>\r\n </Card>\r\n }\r\n </div>\r\n\r\n )\r\n}"],"mappings":"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","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"ExplodeByLevelTool.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/bim/src/tools/ExplodeByLevelTool.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAA;AAOtD,UAAU,mBAAmB;IAC3B,IAAI,EAAE,IAAI,CAAA;CACX;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA+B5D,CAAA"}
1
+ {"version":3,"file":"ExplodeByLevelTool.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/bim/src/tools/ExplodeByLevelTool.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAA;AAOtD,UAAU,mBAAmB;IAC3B,IAAI,EAAE,IAAI,CAAA;CACX;AAED,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA8B5D,CAAA"}
@@ -12,7 +12,6 @@ const ExplodeByLevelTool = ({ tool }) => {
12
12
  const handleExplodeByLevel = async () => {
13
13
  if (!bimComponents) return;
14
14
  try {
15
- console.log("Explode by level functionality not implemented yet");
16
15
  } catch (error) {
17
16
  console.error("Error exploding by level:", error);
18
17
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../src/core/components/viewers/bim/src/tools/ExplodeByLevelTool.tsx"],"sourcesContent":["\"use client\"\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Use this tutorial https://docs.thatopen.com/Tutorials/Fragments/Fragments/FragmentsModels/EditApi\r\n\r\n// Dependencies\r\nimport * as LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from \"react\";\r\n\r\n// Utilities\r\nimport { BimContext } from '../../../../../store/BIM/context'\r\nimport { Button } from '../../../../ui/Button'\r\n\r\nimport type { Tool } from '../../../../../types/tools'\r\n\r\n// Shadcn components\r\n\r\n// Icons\r\n\r\n\r\ninterface ExplodeByLevelProps {\r\n tool: Tool\r\n}\r\n\r\nexport const ExplodeByLevelTool: React.FC<ExplodeByLevelProps> = ({ tool }) => {\r\n // Translation\r\n const t = useTranslations('ExplodeByLevelTool')\r\n\r\n const { state: bimState } = React.useContext(BimContext)\r\n const { bimComponents } = bimState.bim\r\n\r\n const handleExplodeByLevel = async () => {\r\n if (!bimComponents) return\r\n\r\n try {\r\n // TODO: Implement explode by level functionality\r\n console.log('Explode by level functionality not implemented yet')\r\n }\r\n catch (error) {\r\n console.error('Error exploding by level:', error)\r\n }\r\n }\r\n\r\n return (\r\n <Button\r\n size=\"icon\"\r\n variant=\"ghost\"\r\n className=\"flex justify-center items-center h-9 w-9 pointer-events-auto opacity-50\"\r\n onClick={handleExplodeByLevel}\r\n title={`${tool.title} (${t('comingSoon')})`}\r\n disabled={true}\r\n >\r\n <LR.Layers3 />\r\n </Button>\r\n )\r\n}"],"mappings":";AAuDM;AA/CN,YAAY,QAAQ;AACpB,SAAS,uBAAuB;AAChC,YAAY,WAAW;AAGvB,SAAS,kBAAkB;AAC3B,SAAS,cAAc;AAahB,MAAM,qBAAoD,CAAC,EAAE,KAAK,MAAM;AAE7E,QAAM,IAAI,gBAAgB,oBAAoB;AAE9C,QAAM,EAAE,OAAO,SAAS,IAAI,MAAM,WAAW,UAAU;AACvD,QAAM,EAAE,cAAc,IAAI,SAAS;AAEnC,QAAM,uBAAuB,YAAY;AACvC,QAAI,CAAC,cAAe;AAEpB,QAAI;AAEF,cAAQ,IAAI,oDAAoD;AAAA,IAClE,SACO,OAAO;AACZ,cAAQ,MAAM,6BAA6B,KAAK;AAAA,IAClD;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAQ;AAAA,MACR,WAAU;AAAA,MACV,SAAS;AAAA,MACT,OAAO,GAAG,KAAK,KAAK,KAAK,EAAE,YAAY,CAAC;AAAA,MACxC,UAAU;AAAA,MAEV,8BAAC,GAAG,SAAH,EAAW;AAAA;AAAA,EACd;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../../../../../src/core/components/viewers/bim/src/tools/ExplodeByLevelTool.tsx"],"sourcesContent":["\"use client\"\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Use this tutorial https://docs.thatopen.com/Tutorials/Fragments/Fragments/FragmentsModels/EditApi\r\n\r\n// Dependencies\r\nimport * as LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from \"react\";\r\n\r\n// Utilities\r\nimport { BimContext } from '../../../../../store/BIM/context'\r\nimport { Button } from '../../../../ui/Button'\r\n\r\nimport type { Tool } from '../../../../../types/tools'\r\n\r\n// Shadcn components\r\n\r\n// Icons\r\n\r\n\r\ninterface ExplodeByLevelProps {\r\n tool: Tool\r\n}\r\n\r\nexport const ExplodeByLevelTool: React.FC<ExplodeByLevelProps> = ({ tool }) => {\r\n // Translation\r\n const t = useTranslations('ExplodeByLevelTool')\r\n\r\n const { state: bimState } = React.useContext(BimContext)\r\n const { bimComponents } = bimState.bim\r\n\r\n const handleExplodeByLevel = async () => {\r\n if (!bimComponents) return\r\n\r\n try {\r\n // ⚠️ Explode-by-level functionality not implemented\r\n }\r\n catch (error) {\r\n console.error('Error exploding by level:', error)\r\n }\r\n }\r\n\r\n return (\r\n <Button\r\n size=\"icon\"\r\n variant=\"ghost\"\r\n className=\"flex justify-center items-center h-9 w-9 pointer-events-auto opacity-50\"\r\n onClick={handleExplodeByLevel}\r\n title={`${tool.title} (${t('comingSoon')})`}\r\n disabled={true}\r\n >\r\n <LR.Layers3 />\r\n </Button>\r\n )\r\n}"],"mappings":";AAsDM;AA9CN,YAAY,QAAQ;AACpB,SAAS,uBAAuB;AAChC,YAAY,WAAW;AAGvB,SAAS,kBAAkB;AAC3B,SAAS,cAAc;AAahB,MAAM,qBAAoD,CAAC,EAAE,KAAK,MAAM;AAE7E,QAAM,IAAI,gBAAgB,oBAAoB;AAE9C,QAAM,EAAE,OAAO,SAAS,IAAI,MAAM,WAAW,UAAU;AACvD,QAAM,EAAE,cAAc,IAAI,SAAS;AAEnC,QAAM,uBAAuB,YAAY;AACvC,QAAI,CAAC,cAAe;AAEpB,QAAI;AAAA,IAEJ,SACO,OAAO;AACZ,cAAQ,MAAM,6BAA6B,KAAK;AAAA,IAClD;AAAA,EACF;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,SAAQ;AAAA,MACR,WAAU;AAAA,MACV,SAAS;AAAA,MACT,OAAO,GAAG,KAAK,KAAK,KAAK,EAAE,YAAY,CAAC;AAAA,MACxC,UAAU;AAAA,MAEV,8BAAC,GAAG,SAAH,EAAW;AAAA;AAAA,EACd;AAEJ;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"measureBimTool.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/bim/src/tools/measureBimTool.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAa/B,OAAO,KAAK,EAAE,IAAI,EAAC,MAAM,4BAA4B,CAAC;AACtD,UAAU,gBAAgB;IACxB,IAAI,EAAE,IAAI,CAAA;CACX;AAID,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAiHrD,CAAA"}
1
+ {"version":3,"file":"measureBimTool.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/bim/src/tools/measureBimTool.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAa/B,OAAO,KAAK,EAAE,IAAI,EAAC,MAAM,4BAA4B,CAAC;AACtD,UAAU,gBAAgB;IACxB,IAAI,EAAE,IAAI,CAAA;CACX;AAID,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAgHrD,CAAA"}
@@ -45,8 +45,7 @@ const MeasureBimTool = ({ tool }) => {
45
45
  }, [currentToolId, toolId, lengthMeasurement]);
46
46
  React.useEffect(() => {
47
47
  if (!lengthMeasurement) return;
48
- const handleMeasurementCreated = (data) => {
49
- console.log("Measurement created:", data.length);
48
+ const handleMeasurementCreated = () => {
50
49
  };
51
50
  lengthMeasurement.onDimensionCreate.add(handleMeasurementCreated);
52
51
  return () => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../src/core/components/viewers/bim/src/tools/measureBimTool.tsx"],"sourcesContent":["\"use client\"\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Dependencies\r\nimport * as OBF from \"@thatopen/components-front\"\r\n\r\n// Utilities\r\n\r\n// Shadcn components\r\n\r\n// Icons\r\nimport * as LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from \"react\";\r\n\r\nimport { ToolsContext } from '../../../../../store'\r\nimport { BimContext } from '../../../../../store/BIM/context'\r\nimport { type ToolbarToolType } from '../../../../../types/tools'\r\nimport { ToolbarSubmenu } from '../../../../ToolbarSubmenu'\r\nimport {\r\n DropdownMenuItem,\r\n} from '../../../../ui/DropdownMenu'\r\nimport { LengthMeasurement } from '../BimMeasurements/LenghtMeasurement'\r\nimport { Cursor } from '../Cursor'\r\n\r\nimport type { CursorType } from '../../../../../types/global'\r\nimport type { Tool} from '../../../../../types/tools';\r\ninterface MeasureToolProps {\r\n tool: Tool\r\n}\r\n\r\ntype MeasureType = 'free' | 'edge' | 'area' | 'volume'\r\n\r\nexport const MeasureBimTool: React.FC<MeasureToolProps> = ({ tool }) => {\r\n // Translation\r\n const t = useTranslations('MeasureBimTool')\r\n\r\n const { dispatch: toolsDispatch, state: toolsState } = React.useContext(ToolsContext)\r\n const { state: bimState } = React.useContext(BimContext)\r\n const [active, setActive] = React.useState(false)\r\n\r\n const { bimComponents } = bimState.bim\r\n const lengthMeasurement = bimComponents?.get(LengthMeasurement)\r\n const hoverHandler = bimComponents?.get(OBF.Hoverer)\r\n\r\n const setCursor = (cursor: CursorType) => {\r\n if (!bimComponents) return\r\n const currentCursor = bimComponents.get(Cursor)\r\n if (!currentCursor) return\r\n currentCursor.cursor = cursor\r\n }\r\n\r\n const toolId = tool.id\r\n const { currentToolId } = toolsState.tools\r\n const setTools = (currentToolId: ToolbarToolType) => {\r\n toolsDispatch({\r\n type: 'SET-TOOL',\r\n payload: { currentToolId },\r\n })\r\n }\r\n\r\n // When current tool changes\r\n React.useEffect(() => {\r\n setActive(currentToolId === toolId)\r\n\r\n // Disable measurement when tool is deactivated\r\n if (currentToolId !== toolId && lengthMeasurement) {\r\n lengthMeasurement.enabled = false\r\n if (hoverHandler) {\r\n hoverHandler.enabled = true\r\n }\r\n }\r\n }, [currentToolId, toolId, lengthMeasurement])\r\n\r\n // Optional: Listen to measurement creation events\r\n React.useEffect(() => {\r\n if (!lengthMeasurement) return\r\n\r\n const handleMeasurementCreated = (data: { length: number }) => {\r\n console.log('Measurement created:', data.length)\r\n // You can add custom logic here when a measurement is created\r\n }\r\n\r\n lengthMeasurement.onDimensionCreate.add(handleMeasurementCreated)\r\n\r\n return () => {\r\n lengthMeasurement.onDimensionCreate.remove(handleMeasurementCreated)\r\n }\r\n }, [lengthMeasurement])\r\n\r\n const handleMeasureTypeChange = (type: MeasureType) => {\r\n if (!lengthMeasurement) return\r\n\r\n // Set the tool as active\r\n setTools(toolId)\r\n if (hoverHandler) {\r\n hoverHandler.enabled = false\r\n }\r\n\r\n // Enable the measurement component and set measurement mode\r\n if (type === 'free') {\r\n lengthMeasurement.createFreeMeasurements()\r\n }\r\n if (type === 'edge') {\r\n lengthMeasurement.createEdgeMeasurements()\r\n }\r\n\r\n setCursor('crosshair')\r\n }\r\n\r\n // Clear measurements function\r\n const clearMeasurements = () => {\r\n if (lengthMeasurement) {\r\n lengthMeasurement.deleteAll()\r\n lengthMeasurement.enabled = false\r\n }\r\n if (hoverHandler) {\r\n hoverHandler.enabled = true\r\n }\r\n setCursor('')\r\n }\r\n\r\n return (\r\n <ToolbarSubmenu tool={tool}>\r\n <DropdownMenuItem onClick={() => handleMeasureTypeChange('free')} >\r\n <LR.Ruler />\r\n <span>{t('free')}</span>\r\n </DropdownMenuItem>\r\n <DropdownMenuItem onClick={() => handleMeasureTypeChange('edge')} >\r\n <LR.RulerDimensionLine />\r\n <span>{t('edge')}</span>\r\n </DropdownMenuItem>\r\n <DropdownMenuItem onClick={() => handleMeasureTypeChange('area')} disabled={true}>\r\n <LR.SquareDashed />\r\n <span>{t('area')}</span>\r\n </DropdownMenuItem>\r\n <DropdownMenuItem onClick={() => handleMeasureTypeChange('volume')} disabled={true}>\r\n <LR.Box />\r\n <span>{t('volume')}</span>\r\n </DropdownMenuItem>\r\n <DropdownMenuItem onClick={clearMeasurements} >\r\n <LR.X />\r\n <span>{t('clear')}</span>\r\n </DropdownMenuItem>\r\n </ToolbarSubmenu>\r\n )\r\n}\r\n"],"mappings":"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","names":["currentToolId"]}
1
+ {"version":3,"sources":["../../../../../../../src/core/components/viewers/bim/src/tools/measureBimTool.tsx"],"sourcesContent":["\"use client\"\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Dependencies\r\nimport * as OBF from \"@thatopen/components-front\"\r\n\r\n// Utilities\r\n\r\n// Shadcn components\r\n\r\n// Icons\r\nimport * as LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from \"react\";\r\n\r\nimport { ToolsContext } from '../../../../../store'\r\nimport { BimContext } from '../../../../../store/BIM/context'\r\nimport { type ToolbarToolType } from '../../../../../types/tools'\r\nimport { ToolbarSubmenu } from '../../../../ToolbarSubmenu'\r\nimport {\r\n DropdownMenuItem,\r\n} from '../../../../ui/DropdownMenu'\r\nimport { LengthMeasurement } from '../BimMeasurements/LenghtMeasurement'\r\nimport { Cursor } from '../Cursor'\r\n\r\nimport type { CursorType } from '../../../../../types/global'\r\nimport type { Tool} from '../../../../../types/tools';\r\ninterface MeasureToolProps {\r\n tool: Tool\r\n}\r\n\r\ntype MeasureType = 'free' | 'edge' | 'area' | 'volume'\r\n\r\nexport const MeasureBimTool: React.FC<MeasureToolProps> = ({ tool }) => {\r\n // Translation\r\n const t = useTranslations('MeasureBimTool')\r\n\r\n const { dispatch: toolsDispatch, state: toolsState } = React.useContext(ToolsContext)\r\n const { state: bimState } = React.useContext(BimContext)\r\n const [active, setActive] = React.useState(false)\r\n\r\n const { bimComponents } = bimState.bim\r\n const lengthMeasurement = bimComponents?.get(LengthMeasurement)\r\n const hoverHandler = bimComponents?.get(OBF.Hoverer)\r\n\r\n const setCursor = (cursor: CursorType) => {\r\n if (!bimComponents) return\r\n const currentCursor = bimComponents.get(Cursor)\r\n if (!currentCursor) return\r\n currentCursor.cursor = cursor\r\n }\r\n\r\n const toolId = tool.id\r\n const { currentToolId } = toolsState.tools\r\n const setTools = (currentToolId: ToolbarToolType) => {\r\n toolsDispatch({\r\n type: 'SET-TOOL',\r\n payload: { currentToolId },\r\n })\r\n }\r\n\r\n // When current tool changes\r\n React.useEffect(() => {\r\n setActive(currentToolId === toolId)\r\n\r\n // Disable measurement when tool is deactivated\r\n if (currentToolId !== toolId && lengthMeasurement) {\r\n lengthMeasurement.enabled = false\r\n if (hoverHandler) {\r\n hoverHandler.enabled = true\r\n }\r\n }\r\n }, [currentToolId, toolId, lengthMeasurement])\r\n\r\n // Optional: Listen to measurement creation events\r\n React.useEffect(() => {\r\n if (!lengthMeasurement) return\r\n\r\n const handleMeasurementCreated = () => {\r\n // You can add custom logic here when a measurement is created\r\n }\r\n\r\n lengthMeasurement.onDimensionCreate.add(handleMeasurementCreated)\r\n\r\n return () => {\r\n lengthMeasurement.onDimensionCreate.remove(handleMeasurementCreated)\r\n }\r\n }, [lengthMeasurement])\r\n\r\n const handleMeasureTypeChange = (type: MeasureType) => {\r\n if (!lengthMeasurement) return\r\n\r\n // Set the tool as active\r\n setTools(toolId)\r\n if (hoverHandler) {\r\n hoverHandler.enabled = false\r\n }\r\n\r\n // Enable the measurement component and set measurement mode\r\n if (type === 'free') {\r\n lengthMeasurement.createFreeMeasurements()\r\n }\r\n if (type === 'edge') {\r\n lengthMeasurement.createEdgeMeasurements()\r\n }\r\n\r\n setCursor('crosshair')\r\n }\r\n\r\n // Clear measurements function\r\n const clearMeasurements = () => {\r\n if (lengthMeasurement) {\r\n lengthMeasurement.deleteAll()\r\n lengthMeasurement.enabled = false\r\n }\r\n if (hoverHandler) {\r\n hoverHandler.enabled = true\r\n }\r\n setCursor('')\r\n }\r\n\r\n return (\r\n <ToolbarSubmenu tool={tool}>\r\n <DropdownMenuItem onClick={() => handleMeasureTypeChange('free')} >\r\n <LR.Ruler />\r\n <span>{t('free')}</span>\r\n </DropdownMenuItem>\r\n <DropdownMenuItem onClick={() => handleMeasureTypeChange('edge')} >\r\n <LR.RulerDimensionLine />\r\n <span>{t('edge')}</span>\r\n </DropdownMenuItem>\r\n <DropdownMenuItem onClick={() => handleMeasureTypeChange('area')} disabled={true}>\r\n <LR.SquareDashed />\r\n <span>{t('area')}</span>\r\n </DropdownMenuItem>\r\n <DropdownMenuItem onClick={() => handleMeasureTypeChange('volume')} disabled={true}>\r\n <LR.Box />\r\n <span>{t('volume')}</span>\r\n </DropdownMenuItem>\r\n <DropdownMenuItem onClick={clearMeasurements} >\r\n <LR.X />\r\n <span>{t('clear')}</span>\r\n </DropdownMenuItem>\r\n </ToolbarSubmenu>\r\n )\r\n}\r\n"],"mappings":"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","names":["currentToolId"]}
@@ -4,9 +4,8 @@ interface Props {
4
4
  width?: string;
5
5
  height?: string;
6
6
  organization: Organization;
7
- minioBaseUrl?: string;
8
7
  maptilerKey?: string;
9
8
  }
10
- export declare function MapViewer({ width, height, organization, minioBaseUrl, maptilerKey }: Props): React.JSX.Element;
9
+ export declare function MapViewer({ width, height, organization, maptilerKey }: Props): React.JSX.Element;
11
10
  export {};
12
11
  //# sourceMappingURL=MapViewer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MapViewer.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/viewers/map/MapViewer.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,MAAM,OAAO,CAAA;AAkBzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAa1D,UAAU,KAAK;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,YAAY,CAAA;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,SAAS,CAAC,EAAE,KAAc,EAAE,MAAe,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,KAAK,qBAsL5G"}
1
+ {"version":3,"file":"MapViewer.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/viewers/map/MapViewer.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,MAAM,OAAO,CAAA;AAkBzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAa1D,UAAU,KAAK;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,YAAY,CAAA;IAC1B,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,SAAS,CAAC,EAAE,KAAc,EAAE,MAAe,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,KAAK,qBAuL9F"}
@@ -20,7 +20,7 @@ const CANADA_DEFAULTS = {
20
20
  };
21
21
  const DEFAULT_MAP_STYLE = { name: "Satellite", url: "mapStyles/satellite.json" };
22
22
  const MAX_GLOBE_ZOOM = 5;
23
- function MapViewer({ width = "100%", height = "100%", organization, minioBaseUrl, maptilerKey }) {
23
+ function MapViewer({ width = "100%", height = "100%", organization, maptilerKey }) {
24
24
  var _a, _b, _c;
25
25
  const searchParams = useSearchParams();
26
26
  const [isMapLoaded, setIsMapLoaded] = React.useState(false);
@@ -144,7 +144,7 @@ function MapViewer({ width = "100%", height = "100%", organization, minioBaseUrl
144
144
  /* @__PURE__ */ jsx(NavigationControl, { visualizePitch: true }),
145
145
  /* @__PURE__ */ jsx(SettingsButton, {}),
146
146
  isMapLoaded && /* @__PURE__ */ jsxs(Fragment, { children: [
147
- /* @__PURE__ */ jsx(MapLayers, { minioBaseUrl, organization, maptilerKey }),
147
+ /* @__PURE__ */ jsx(MapLayers, { organization, maptilerKey }),
148
148
  /* @__PURE__ */ jsxs("div", { className: "absolute bottom-[10px] left-3 z-10 flex flex-col gap-2 pointer-events-none", children: [
149
149
  /* @__PURE__ */ jsx("div", { id: "wms-time-slot", style: { display: "contents" } }),
150
150
  /* @__PURE__ */ jsx(MapLegendHost, {}),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/core/components/viewers/map/MapViewer.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport maplibregl from 'maplibre-gl'\r\nimport { useSearchParams } from 'next/navigation'\r\nimport React from 'react'\r\nimport Map, { NavigationControl } from 'react-map-gl/maplibre'\r\n\r\n\r\nimport { MapContext } from '../../../store'\r\nimport SettingsButton from '../../ui/SettingsButton'\r\nimport { StatsOverlay } from '../../ui/stats'\r\n\r\nimport DatasetManagerMenu from './datasets/DatasetManager'\r\nimport { MapLegendHost } from './legends/MapLegendHost'\r\nimport { MapLayers } from './src/MapLayers'\r\nimport { MapClickManager } from './utils/MapEventManager/MapClickManager'\r\nimport { MapHoverManager } from './utils/MapEventManager/MapHoverManager'\r\nimport { resolveBounds } from './utils/validateBounds'\r\n\r\n\r\n\r\n\r\nimport type { Organization } from '../../../types/dbTypes'\r\nimport type { CurrentLocation } from '../../../types/map'\r\nimport type { MapRef} from 'react-map-gl/maplibre';\r\n\r\nconst CANADA_DEFAULTS = {\r\n zoom: 3,\r\n lat: 56.415,\r\n long: -98.74,\r\n} as const\r\n\r\nconst DEFAULT_MAP_STYLE = { name: 'Satellite', url: 'mapStyles/satellite.json' } as const\r\nconst MAX_GLOBE_ZOOM = 5\r\n\r\ninterface Props {\r\n width?: string\r\n height?: string\r\n organization: Organization\r\n minioBaseUrl?: string\r\n maptilerKey?: string\r\n}\r\n\r\nexport function MapViewer({ width = '100%', height = '100%', organization, minioBaseUrl, maptilerKey }: Props) {\r\n\r\n const searchParams = useSearchParams()\r\n\r\n // Add state to track if map is loaded\r\n const [isMapLoaded, setIsMapLoaded] = React.useState(false)\r\n\r\n const viewState = React.useMemo(() => {\r\n return searchParams.size === 0\r\n ? {\r\n zoom: organization.zoom ?? CANADA_DEFAULTS.zoom,\r\n bearing: organization.bearing ?? 0,\r\n pitch: organization.pitch ?? 0,\r\n longitude: organization.long ?? CANADA_DEFAULTS.long,\r\n latitude: organization.lat ?? CANADA_DEFAULTS.lat,\r\n }\r\n : {\r\n latitude: searchParams.has('lat') ? Number.parseFloat(searchParams.get('lat')) : organization.lat ?? CANADA_DEFAULTS.lat,\r\n longitude: searchParams.has('lng') ? Number.parseFloat(searchParams.get('lng')) : organization.long ?? CANADA_DEFAULTS.long,\r\n bearing: searchParams.has('bearing') ? Number.parseFloat(searchParams.get('bearing')) : organization.bearing ?? 0,\r\n pitch: searchParams.has('pitch') ? Number.parseFloat(searchParams.get('pitch')) : organization.pitch ?? 0,\r\n zoom: searchParams.has('zoom') ? Number.parseFloat(searchParams.get('zoom')) : organization.zoom ?? CANADA_DEFAULTS.zoom,\r\n }\r\n }, [searchParams, organization])\r\n\r\n const initialProjection = viewState.zoom > MAX_GLOBE_ZOOM ? 'mercator' : 'globe'\r\n\r\n // Memoize the inline style object that gets passed to <Map> for a stable prop identity.\r\n const mapContainerStyle = React.useMemo(\r\n () => ({ width, height, backgroundColor: 'black' }),\r\n [width, height],\r\n )\r\n\r\n // Adaptive pixel ratio. A hardcoded 2 doubled fragment-shader cost on 1× DPR\r\n // desktops for zero visual gain; capping at 2 keeps phones (DPR 3-4) effective.\r\n const pixelRatio = React.useMemo(\r\n () => Math.min(typeof window !== 'undefined' ? window.devicePixelRatio : 1, 2),\r\n [],\r\n )\r\n\r\n const mapRef = React.useRef<MapRef>(null)\r\n const { dispatch: mapDispatch, state: mapState } = React.useContext(MapContext)\r\n\r\n // Keep the projection in sync with zoom at all times — not only while the\r\n // map-settings sidebar is mounted. The globe projection degrades past\r\n // MAX_GLOBE_ZOOM, so we force mercator regardless of which panels are open.\r\n const activeMap = mapState?.map?.map\r\n\r\n React.useEffect(() => {\r\n if (!activeMap) return\r\n\r\n const enforceProjectionForZoom = () => {\r\n if (activeMap.getZoom() <= MAX_GLOBE_ZOOM) return\r\n\r\n const projection = activeMap.getProjection()\r\n const currentType =\r\n typeof projection === 'string'\r\n ? projection\r\n : (projection as { type?: string; name?: string })?.type ?? (projection as { type?: string; name?: string })?.name\r\n\r\n if (currentType !== 'mercator') {\r\n activeMap.setProjection({ type: 'mercator' })\r\n }\r\n }\r\n\r\n enforceProjectionForZoom()\r\n activeMap.on('zoom', enforceProjectionForZoom)\r\n\r\n return () => {\r\n activeMap.off('zoom', enforceProjectionForZoom)\r\n }\r\n }, [activeMap])\r\n\r\n const handleMapLoad = () => {\r\n const map = mapRef.current.getMap()\r\n\r\n if (map.getZoom() > MAX_GLOBE_ZOOM) {\r\n map.setProjection({ type: 'mercator' })\r\n }\r\n\r\n // Only dispatch SET_MAP after map is fully loaded\r\n if (mapRef.current) {\r\n mapDispatch({\r\n type: 'SET_MAP',\r\n payload: { map },\r\n })\r\n }\r\n // initilize a new click manager\r\n const mapClickManager = new MapClickManager(map)\r\n mapDispatch({\r\n type: 'ADD_MAP_CLICK_MANAGER',\r\n payload: { mapClickManager },\r\n })\r\n\r\n const mapHoverManager = new MapHoverManager(map)\r\n mapDispatch({\r\n type: 'ADD_MAP_HOVER_MANAGER',\r\n payload: { mapHoverManager },\r\n })\r\n\r\n // update current Location with URL params or fallback to theme location\r\n const updatedLocation: CurrentLocation = {\r\n // Then override with URL params (this ensures URL params take precedence)\r\n lat: searchParams.has('lat') ? Number.parseFloat(searchParams.get('lat')) : organization.lat ?? CANADA_DEFAULTS.lat,\r\n lng: searchParams.has('lng') ? Number.parseFloat(searchParams.get('lng')) : organization.long ?? CANADA_DEFAULTS.long,\r\n bearing: searchParams.has('bearing') ? Number.parseFloat(searchParams.get('bearing')) : organization.bearing ?? 0,\r\n pitch: searchParams.has('pitch') ? Number.parseFloat(searchParams.get('pitch')) : organization.pitch ?? 0,\r\n zoom: searchParams.has('zoom') ? Number.parseFloat(searchParams.get('zoom')) : organization.zoom ?? CANADA_DEFAULTS.zoom,\r\n // Add location details from URL params if available\r\n countrySubdivision: searchParams.has('countrySubdivision') ? searchParams.get('countrySubdivision') : (organization.countrySubdivision ?? ''),\r\n municipality: searchParams.has('municipality') ? searchParams.get('municipality') : (organization.municipality ?? ''),\r\n address: searchParams.has('address') ? searchParams.get('address') : '', // organization.address,\r\n site: searchParams.has('site') ? searchParams.get('site') : String(organization.locationSiteId ?? ''),\r\n id: String(organization.id),\r\n }\r\n\r\n mapDispatch({\r\n type: 'UPDATE_LOCATION',\r\n payload: { currentLocation: updatedLocation },\r\n })\r\n\r\n // Set map as loaded after all dispatches are complete\r\n setIsMapLoaded(true)\r\n }\r\n\r\n // Enable the perf HUD by appending ?debug=1 to the URL. Never reaches\r\n // production users unless they explicitly opt in.\r\n const isDebug = searchParams.get('debug') === '1'\r\n\r\n // useCallback so the onDblClick prop identity is stable across renders of\r\n // MapViewer; a new function each render caused react-map-gl to detach/re-attach\r\n // the listener. The console.log is gated behind a dev-mode check.\r\n const onDblClick = React.useCallback((e) => {\r\n if (process.env.NODE_ENV === 'production') return\r\n const { lng, lat } = e.lngLat\r\n const elevation = mapRef.current?.queryTerrainElevation([lng, lat]) || 0\r\n const coordinates = { lng, lat, elevation, zoom: mapRef.current?.getZoom() }\r\n console.log('📍 Map coordinates:', coordinates)\r\n }, [])\r\n\r\n const mapStyle = mapState?.map.mapStyle ?? DEFAULT_MAP_STYLE;\r\n\r\n return (\r\n <>\r\n <Map\r\n id=\"map-component\"\r\n mapStyle={mapStyle.url}\r\n mapLib={maplibregl}\r\n onLoad={handleMapLoad}\r\n ref={mapRef}\r\n style={mapContainerStyle}\r\n initialViewState={viewState}\r\n maxPitch={60}\r\n minZoom={organization?.minZoom ?? CANADA_DEFAULTS.zoom}\r\n maxBounds={resolveBounds(organization?.maxBounds)}\r\n projection={initialProjection}\r\n doubleClickZoom={false}\r\n onDblClick={onDblClick}\r\n pixelRatio={pixelRatio}\r\n >\r\n <NavigationControl visualizePitch />\r\n <SettingsButton />\r\n {isMapLoaded\r\n && (\r\n <>\r\n <MapLayers minioBaseUrl={minioBaseUrl} organization={organization} maptilerKey={maptilerKey} />\r\n {/* Bottom-left stack: legend above the layers/styling card, gap auto-managed by flex. */}\r\n <div className=\"absolute bottom-[10px] left-3 z-10 flex flex-col gap-2 pointer-events-none\">\r\n {/* Portal slot for on-map WMS time controls; display:contents so an\r\n empty slot adds no flex item / gap, but a mounted control stacks\r\n above the legend + dataset-manager cards. */}\r\n <div id=\"wms-time-slot\" style={{ display: 'contents' }} />\r\n <MapLegendHost />\r\n <DatasetManagerMenu />\r\n </div>\r\n </>\r\n )}\r\n </Map>\r\n <StatsOverlay mapRef={mapRef} enabled={isDebug} />\r\n </>\r\n\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","_b","_c"]}
1
+ {"version":3,"sources":["../../../../../src/core/components/viewers/map/MapViewer.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport maplibregl from 'maplibre-gl'\r\nimport { useSearchParams } from 'next/navigation'\r\nimport React from 'react'\r\nimport Map, { NavigationControl } from 'react-map-gl/maplibre'\r\n\r\n\r\nimport { MapContext } from '../../../store'\r\nimport SettingsButton from '../../ui/SettingsButton'\r\nimport { StatsOverlay } from '../../ui/stats'\r\n\r\nimport DatasetManagerMenu from './datasets/DatasetManager'\r\nimport { MapLegendHost } from './legends/MapLegendHost'\r\nimport { MapLayers } from './src/MapLayers'\r\nimport { MapClickManager } from './utils/MapEventManager/MapClickManager'\r\nimport { MapHoverManager } from './utils/MapEventManager/MapHoverManager'\r\nimport { resolveBounds } from './utils/validateBounds'\r\n\r\n\r\n\r\n\r\nimport type { Organization } from '../../../types/dbTypes'\r\nimport type { CurrentLocation } from '../../../types/map'\r\nimport type { MapRef} from 'react-map-gl/maplibre';\r\n\r\nconst CANADA_DEFAULTS = {\r\n zoom: 3,\r\n lat: 56.415,\r\n long: -98.74,\r\n} as const\r\n\r\nconst DEFAULT_MAP_STYLE = { name: 'Satellite', url: 'mapStyles/satellite.json' } as const\r\nconst MAX_GLOBE_ZOOM = 5\r\n\r\ninterface Props {\r\n width?: string\r\n height?: string\r\n organization: Organization\r\n maptilerKey?: string\r\n}\r\n\r\nexport function MapViewer({ width = '100%', height = '100%', organization, maptilerKey }: Props) {\r\n\r\n const searchParams = useSearchParams()\r\n\r\n // Add state to track if map is loaded\r\n const [isMapLoaded, setIsMapLoaded] = React.useState(false)\r\n\r\n const viewState = React.useMemo(() => {\r\n return searchParams.size === 0\r\n ? {\r\n zoom: organization.zoom ?? CANADA_DEFAULTS.zoom,\r\n bearing: organization.bearing ?? 0,\r\n pitch: organization.pitch ?? 0,\r\n longitude: organization.long ?? CANADA_DEFAULTS.long,\r\n latitude: organization.lat ?? CANADA_DEFAULTS.lat,\r\n }\r\n : {\r\n latitude: searchParams.has('lat') ? Number.parseFloat(searchParams.get('lat')) : organization.lat ?? CANADA_DEFAULTS.lat,\r\n longitude: searchParams.has('lng') ? Number.parseFloat(searchParams.get('lng')) : organization.long ?? CANADA_DEFAULTS.long,\r\n bearing: searchParams.has('bearing') ? Number.parseFloat(searchParams.get('bearing')) : organization.bearing ?? 0,\r\n pitch: searchParams.has('pitch') ? Number.parseFloat(searchParams.get('pitch')) : organization.pitch ?? 0,\r\n zoom: searchParams.has('zoom') ? Number.parseFloat(searchParams.get('zoom')) : organization.zoom ?? CANADA_DEFAULTS.zoom,\r\n }\r\n }, [searchParams, organization])\r\n\r\n const initialProjection = viewState.zoom > MAX_GLOBE_ZOOM ? 'mercator' : 'globe'\r\n\r\n // Memoize the inline style object that gets passed to <Map> for a stable prop identity.\r\n const mapContainerStyle = React.useMemo(\r\n () => ({ width, height, backgroundColor: 'black' }),\r\n [width, height],\r\n )\r\n\r\n // Adaptive pixel ratio. A hardcoded 2 doubled fragment-shader cost on 1× DPR\r\n // desktops for zero visual gain; capping at 2 keeps phones (DPR 3-4) effective.\r\n const pixelRatio = React.useMemo(\r\n () => Math.min(typeof window !== 'undefined' ? window.devicePixelRatio : 1, 2),\r\n [],\r\n )\r\n\r\n const mapRef = React.useRef<MapRef>(null)\r\n const { dispatch: mapDispatch, state: mapState } = React.useContext(MapContext)\r\n\r\n // Keep the projection in sync with zoom at all times — not only while the\r\n // map-settings sidebar is mounted. The globe projection degrades past\r\n // MAX_GLOBE_ZOOM, so we force mercator regardless of which panels are open.\r\n const activeMap = mapState?.map?.map\r\n\r\n React.useEffect(() => {\r\n if (!activeMap) return\r\n\r\n const enforceProjectionForZoom = () => {\r\n if (activeMap.getZoom() <= MAX_GLOBE_ZOOM) return\r\n\r\n const projection = activeMap.getProjection()\r\n const currentType =\r\n typeof projection === 'string'\r\n ? projection\r\n : (projection as { type?: string; name?: string })?.type ?? (projection as { type?: string; name?: string })?.name\r\n\r\n if (currentType !== 'mercator') {\r\n activeMap.setProjection({ type: 'mercator' })\r\n }\r\n }\r\n\r\n enforceProjectionForZoom()\r\n activeMap.on('zoom', enforceProjectionForZoom)\r\n\r\n return () => {\r\n activeMap.off('zoom', enforceProjectionForZoom)\r\n }\r\n }, [activeMap])\r\n\r\n const handleMapLoad = () => {\r\n const map = mapRef.current.getMap()\r\n\r\n if (map.getZoom() > MAX_GLOBE_ZOOM) {\r\n map.setProjection({ type: 'mercator' })\r\n }\r\n\r\n // Only dispatch SET_MAP after map is fully loaded\r\n if (mapRef.current) {\r\n mapDispatch({\r\n type: 'SET_MAP',\r\n payload: { map },\r\n })\r\n }\r\n // initilize a new click manager\r\n const mapClickManager = new MapClickManager(map)\r\n mapDispatch({\r\n type: 'ADD_MAP_CLICK_MANAGER',\r\n payload: { mapClickManager },\r\n })\r\n\r\n const mapHoverManager = new MapHoverManager(map)\r\n mapDispatch({\r\n type: 'ADD_MAP_HOVER_MANAGER',\r\n payload: { mapHoverManager },\r\n })\r\n\r\n // update current Location with URL params or fallback to theme location\r\n const updatedLocation: CurrentLocation = {\r\n // Then override with URL params (this ensures URL params take precedence)\r\n lat: searchParams.has('lat') ? Number.parseFloat(searchParams.get('lat')) : organization.lat ?? CANADA_DEFAULTS.lat,\r\n lng: searchParams.has('lng') ? Number.parseFloat(searchParams.get('lng')) : organization.long ?? CANADA_DEFAULTS.long,\r\n bearing: searchParams.has('bearing') ? Number.parseFloat(searchParams.get('bearing')) : organization.bearing ?? 0,\r\n pitch: searchParams.has('pitch') ? Number.parseFloat(searchParams.get('pitch')) : organization.pitch ?? 0,\r\n zoom: searchParams.has('zoom') ? Number.parseFloat(searchParams.get('zoom')) : organization.zoom ?? CANADA_DEFAULTS.zoom,\r\n // Add location details from URL params if available\r\n countrySubdivision: searchParams.has('countrySubdivision') ? searchParams.get('countrySubdivision') : (organization.countrySubdivision ?? ''),\r\n municipality: searchParams.has('municipality') ? searchParams.get('municipality') : (organization.municipality ?? ''),\r\n address: searchParams.has('address') ? searchParams.get('address') : '', // organization.address,\r\n site: searchParams.has('site') ? searchParams.get('site') : String(organization.locationSiteId ?? ''),\r\n id: String(organization.id),\r\n }\r\n\r\n mapDispatch({\r\n type: 'UPDATE_LOCATION',\r\n payload: { currentLocation: updatedLocation },\r\n })\r\n\r\n // Set map as loaded after all dispatches are complete\r\n setIsMapLoaded(true)\r\n }\r\n\r\n // Enable the perf HUD by appending ?debug=1 to the URL. Never reaches\r\n // production users unless they explicitly opt in.\r\n const isDebug = searchParams.get('debug') === '1'\r\n\r\n // useCallback so the onDblClick prop identity is stable across renders of\r\n // MapViewer; a new function each render caused react-map-gl to detach/re-attach\r\n // the listener. The console.log is intentional dev-only coordinate debugging.\r\n const onDblClick = React.useCallback((e) => {\r\n if (process.env.NODE_ENV === 'production') return\r\n const { lng, lat } = e.lngLat\r\n const elevation = mapRef.current?.queryTerrainElevation([lng, lat]) || 0\r\n const coordinates = { lng, lat, elevation, zoom: mapRef.current?.getZoom() }\r\n // eslint-disable-next-line no-console -- intentional dev-mode coordinate logging\r\n console.log('📍 Map coordinates:', coordinates)\r\n }, [])\r\n\r\n const mapStyle = mapState?.map.mapStyle ?? DEFAULT_MAP_STYLE;\r\n\r\n return (\r\n <>\r\n <Map\r\n id=\"map-component\"\r\n mapStyle={mapStyle.url}\r\n mapLib={maplibregl}\r\n onLoad={handleMapLoad}\r\n ref={mapRef}\r\n style={mapContainerStyle}\r\n initialViewState={viewState}\r\n maxPitch={60}\r\n minZoom={organization?.minZoom ?? CANADA_DEFAULTS.zoom}\r\n maxBounds={resolveBounds(organization?.maxBounds)}\r\n projection={initialProjection}\r\n doubleClickZoom={false}\r\n onDblClick={onDblClick}\r\n pixelRatio={pixelRatio}\r\n >\r\n <NavigationControl visualizePitch />\r\n <SettingsButton />\r\n {isMapLoaded\r\n && (\r\n <>\r\n <MapLayers organization={organization} maptilerKey={maptilerKey} />\r\n {/* Bottom-left stack: legend above the layers/styling card, gap auto-managed by flex. */}\r\n <div className=\"absolute bottom-[10px] left-3 z-10 flex flex-col gap-2 pointer-events-none\">\r\n {/* Portal slot for on-map WMS time controls; display:contents so an\r\n empty slot adds no flex item / gap, but a mounted control stacks\r\n above the legend + dataset-manager cards. */}\r\n <div id=\"wms-time-slot\" style={{ display: 'contents' }} />\r\n <MapLegendHost />\r\n <DatasetManagerMenu />\r\n </div>\r\n </>\r\n )}\r\n </Map>\r\n <StatsOverlay mapRef={mapRef} enabled={isDebug} />\r\n </>\r\n\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","_b","_c"]}
@@ -1 +1 @@
1
- {"version":3,"file":"arcGISDatasets.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/datasets/src/arcGISDatasets.ts"],"names":[],"mappings":"AAKA,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAMxF,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAA;AAI3E,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AA8CD,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,cAAc,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,EAAE,CAAC,CAwQpB;AAED,MAAM,WAAW,cAAc;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,CAAA;CACxD;AAED,wBAAgB,cAAc,IAAI,cAAc,CAmB/C"}
1
+ {"version":3,"file":"arcGISDatasets.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/datasets/src/arcGISDatasets.ts"],"names":[],"mappings":"AAKA,OAAO,EAAwB,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAMxF,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAA;AAI3E,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AA8CD,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,cAAc,EACtB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,EAAE,CAAC,CAsQpB;AAED,MAAM,WAAW,cAAc;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,CAAA;CACxD;AAED,wBAAgB,cAAc,IAAI,cAAc,CAmB/C"}
@@ -53,19 +53,16 @@ async function withConcurrencyLimit(items, limit, fn) {
53
53
  return results;
54
54
  }
55
55
  async function fetchArcGISDatasets(portal, rowsPerPage) {
56
- var _a, _b;
57
56
  const { apiUrl, countrySubdivision, municipality, group } = portal;
58
57
  try {
59
58
  const baseUrl = (apiUrl || "").replace(/\/+$/, "");
60
59
  const servicesUrl = `${baseUrl}/services?f=pjson`;
61
- console.log(`[ArcGIS] Fetching services for portal "${portal.name}": ${servicesUrl}`);
62
60
  const response = await fetchWithTimeout(servicesUrl);
63
61
  if (!response.ok) {
64
62
  console.error(`[ArcGIS] "${portal.name}" services request failed \u2014 status ${response.status}`);
65
63
  throw new Error(`HTTP error! status: ${response.status}`);
66
64
  }
67
65
  const data = await response.json();
68
- console.log(`[ArcGIS] "${portal.name}" \u2014 ${(_b = (_a = data.services) == null ? void 0 : _a.length) != null ? _b : 0} services found`);
69
66
  const transformedDatasets = [];
70
67
  const processService = async (service) => {
71
68
  const url = `${baseUrl}/services/${service.name}/${service.type}`;
@@ -82,12 +79,12 @@ async function fetchArcGISDatasets(portal, rowsPerPage) {
82
79
  serviceInfo = await serviceRes.value.json();
83
80
  const layers = serviceInfo.layers && serviceInfo.layers.length > 0 ? serviceInfo.layers.filter((l) => l.type === "Feature Layer") : [{ id: 0, name: null, geometryType: null }];
84
81
  const hasNonNullGeometry = (featuresUrl, cacheKey) => withCache(cacheKey, 24 * 60 * 60 * 1e3, async () => {
85
- var _a2, _b2;
82
+ var _a, _b;
86
83
  try {
87
84
  const res = await fetchWithTimeout(`${featuresUrl}&resultRecordCount=1`);
88
85
  if (!res.ok) return false;
89
86
  const d = await res.json();
90
- if (((_a2 = d == null ? void 0 : d.error) == null ? void 0 : _a2.code) || ((_b2 = d == null ? void 0 : d.error) == null ? void 0 : _b2.message)) return false;
87
+ if (((_a = d == null ? void 0 : d.error) == null ? void 0 : _a.code) || ((_b = d == null ? void 0 : d.error) == null ? void 0 : _b.message)) return false;
91
88
  if (!d || d.type !== "FeatureCollection" || !Array.isArray(d.features)) return false;
92
89
  return d.features.some((f) => f && f.geometry);
93
90
  } catch (e) {
@@ -96,21 +93,21 @@ async function fetchArcGISDatasets(portal, rowsPerPage) {
96
93
  });
97
94
  const layerResults = await Promise.allSettled(
98
95
  layers.map(async (layer) => {
99
- var _a2, _b2, _c;
96
+ var _a, _b, _c;
100
97
  const layerIndex = layer.id;
101
98
  const featuresUrl = `${url}/${layerIndex}/query?outFields=*&where=1%3D1&f=geojson`;
102
99
  const featureInfoUrl = `${url}/${layerIndex}?f=pjson`;
103
100
  const validKey = buildValidationKey(
104
101
  "arcgis",
105
102
  `${service.name}_${layerIndex}`,
106
- ((_a2 = serviceInfo == null ? void 0 : serviceInfo.documentInfo) == null ? void 0 : _a2.ModifiedTime) || (extraInfo == null ? void 0 : extraInfo.modified) || void 0
103
+ ((_a = serviceInfo == null ? void 0 : serviceInfo.documentInfo) == null ? void 0 : _a.ModifiedTime) || (extraInfo == null ? void 0 : extraInfo.modified) || void 0
107
104
  );
108
105
  const hasGeom = await hasNonNullGeometry(featuresUrl, validKey);
109
106
  if (!hasGeom) return null;
110
- const modTime = ((_b2 = serviceInfo == null ? void 0 : serviceInfo.documentInfo) == null ? void 0 : _b2.ModifiedTime) || (extraInfo == null ? void 0 : extraInfo.modified) || "";
107
+ const modTime = ((_b = serviceInfo == null ? void 0 : serviceInfo.documentInfo) == null ? void 0 : _b.ModifiedTime) || (extraInfo == null ? void 0 : extraInfo.modified) || "";
111
108
  const getFeatures = async (options) => {
112
- var _a3;
113
- const zoom = (_a3 = options == null ? void 0 : options.zoom) != null ? _a3 : 10;
109
+ var _a2;
110
+ const zoom = (_a2 = options == null ? void 0 : options.zoom) != null ? _a2 : 10;
114
111
  const bbox = options == null ? void 0 : options.bbox;
115
112
  const pageSize = zoom < 6 ? 500 : zoom < 10 ? 1e3 : 2e3;
116
113
  let spatialFilter = "";
@@ -150,8 +147,8 @@ async function fetchArcGISDatasets(portal, rowsPerPage) {
150
147
  `${baseQuery}&resultOffset=${pageSize * (i + 1)}&resultRecordCount=${pageSize}`,
151
148
  15e3
152
149
  ).then((r) => r.ok ? r.json() : null).then((p) => {
153
- var _a4;
154
- return (_a4 = p == null ? void 0 : p.features) != null ? _a4 : [];
150
+ var _a3;
151
+ return (_a3 = p == null ? void 0 : p.features) != null ? _a3 : [];
155
152
  }).catch(() => [])
156
153
  )
157
154
  );
@@ -209,9 +206,9 @@ async function fetchArcGISDatasets(portal, rowsPerPage) {
209
206
  return "string";
210
207
  };
211
208
  const mapped = featureData.fields.map((field) => {
212
- var _a3;
209
+ var _a2;
213
210
  const rawEsriType = field.type;
214
- const inferred = nameBasedType(field) || ((_a3 = typeMap[rawEsriType]) == null ? void 0 : _a3.type) || inferFieldType(field);
211
+ const inferred = nameBasedType(field) || ((_a2 = typeMap[rawEsriType]) == null ? void 0 : _a2.type) || inferFieldType(field);
215
212
  return __spreadProps(__spreadValues({}, field), { esriType: rawEsriType, type: inferred });
216
213
  });
217
214
  setCache(fieldsKey, mapped, 24 * 60 * 60 * 1e3);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../src/core/components/viewers/map/datasets/src/arcGISDatasets.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport { type AllGeoJSON } from '@turf/turf'\r\n\r\nimport { DataManagementSystem, type OpenDataPortal } from '../../../../../types/dbTypes'\r\nimport { layerColorByName } from '../../utils/stringToColour'\r\nimport { formatName, stripHtml } from '../utils'\r\n\r\nimport { buildValidationKey, getCache, setCache, withCache } from './cache'\r\n\r\nimport type { Dataset, FieldType } from '../../../../../types/datasetTypes'\r\n\r\nconst inFlightFeatureRequests = new Map<string, Promise<AllGeoJSON>>()\r\n\r\nexport type ViewportOptions = {\r\n bbox?: [number, number, number, number] // [west, south, east, north]\r\n zoom?: number\r\n}\r\n\r\nasync function fetchWithTimeout(url: string, timeout = 10_000): Promise<Response> {\r\n const controller = new AbortController()\r\n const timeoutId = setTimeout(() => controller.abort(), timeout)\r\n try {\r\n const response = await fetch(url, { signal: controller.signal })\r\n clearTimeout(timeoutId)\r\n return response\r\n }\r\n catch (error) {\r\n clearTimeout(timeoutId)\r\n throw error\r\n }\r\n}\r\n\r\n/**\r\n * Run `fn` over `items` with at most `limit` concurrent executions.\r\n * Preserves order of results matching input order.\r\n */\r\nasync function withConcurrencyLimit<T, R>(\r\n items: T[],\r\n limit: number,\r\n fn: (item: T) => Promise<R>,\r\n): Promise<PromiseSettledResult<R>[]> {\r\n const results: PromiseSettledResult<R>[] = new Array(items.length)\r\n let next = 0\r\n\r\n async function worker() {\r\n while (next < items.length) {\r\n const i = next++\r\n try {\r\n results[i] = { status: 'fulfilled', value: await fn(items[i]) }\r\n }\r\n catch (reason) {\r\n results[i] = { status: 'rejected', reason }\r\n }\r\n }\r\n }\r\n\r\n await Promise.all(\r\n Array.from({ length: Math.min(limit, items.length) }, worker),\r\n )\r\n return results\r\n}\r\n\r\nexport async function fetchArcGISDatasets(\r\n portal: OpenDataPortal,\r\n rowsPerPage: number,\r\n): Promise<Dataset[]> {\r\n const { apiUrl, countrySubdivision, municipality, group } = portal\r\n\r\n try {\r\n const baseUrl = (apiUrl || '').replace(/\\/+$/, '')\r\n const servicesUrl = `${baseUrl}/services?f=pjson`\r\n console.log(`[ArcGIS] Fetching services for portal \"${portal.name}\": ${servicesUrl}`)\r\n\r\n const response = await fetchWithTimeout(servicesUrl)\r\n if (!response.ok) {\r\n console.error(`[ArcGIS] \"${portal.name}\" services request failed — status ${response.status}`)\r\n throw new Error(`HTTP error! status: ${response.status}`)\r\n }\r\n\r\n const data = await response.json()\r\n console.log(`[ArcGIS] \"${portal.name}\" — ${data.services?.length ?? 0} services found`)\r\n\r\n const transformedDatasets: Dataset[] = []\r\n\r\n const processService = async (service: any): Promise<Dataset[]> => {\r\n const url = `${baseUrl}/services/${service.name}/${service.type}`\r\n const infoUrl = `${url}/info/itemInfo?f=pjson`\r\n\r\n const [infoRes, serviceRes] = await Promise.allSettled([\r\n fetchWithTimeout(infoUrl),\r\n fetchWithTimeout(`${url}?f=pjson`),\r\n ])\r\n\r\n let extraInfo: any = {}\r\n let serviceInfo: any = {}\r\n\r\n if (infoRes.status === 'fulfilled' && infoRes.value.ok)\r\n extraInfo = await infoRes.value.json()\r\n if (serviceRes.status === 'fulfilled' && serviceRes.value.ok)\r\n serviceInfo = await serviceRes.value.json()\r\n\r\n const layers = serviceInfo.layers && serviceInfo.layers.length > 0\r\n ? serviceInfo.layers.filter((l: any) => l.type === 'Feature Layer')\r\n : [{ id: 0, name: null, geometryType: null }]\r\n\r\n const hasNonNullGeometry = (featuresUrl: string, cacheKey: string): Promise<boolean> =>\r\n withCache<boolean>(cacheKey, 24 * 60 * 60 * 1000, async () => {\r\n try {\r\n const res = await fetchWithTimeout(`${featuresUrl}&resultRecordCount=1`)\r\n if (!res.ok) return false\r\n const d = await res.json()\r\n if (d?.error?.code || d?.error?.message) return false\r\n if (!d || d.type !== 'FeatureCollection' || !Array.isArray(d.features)) return false\r\n return d.features.some((f: any) => f && f.geometry)\r\n }\r\n catch { return false }\r\n })\r\n\r\n // Layers within a service are few (2-5 typically) — parallel is fine here\r\n const layerResults = await Promise.allSettled(\r\n layers.map(async (layer: any): Promise<Dataset | null> => {\r\n const layerIndex = layer.id\r\n const featuresUrl = `${url}/${layerIndex}/query?outFields=*&where=1%3D1&f=geojson`\r\n const featureInfoUrl = `${url}/${layerIndex}?f=pjson`\r\n\r\n const validKey = buildValidationKey(\r\n 'arcgis',\r\n `${service.name}_${layerIndex}`,\r\n serviceInfo?.documentInfo?.ModifiedTime || extraInfo?.modified || undefined,\r\n )\r\n const hasGeom = await hasNonNullGeometry(featuresUrl, validKey)\r\n if (!hasGeom) return null\r\n\r\n const modTime = serviceInfo?.documentInfo?.ModifiedTime || extraInfo?.modified || ''\r\n\r\n /**\r\n * getFeatures — viewport-aware, paginated.\r\n * If `bbox` is provided, only features intersecting the viewport are fetched.\r\n * Automatically paginates beyond the per-page limit.\r\n */\r\n const getFeatures = async (options?: ViewportOptions): Promise<AllGeoJSON> => {\r\n const zoom = options?.zoom ?? 10\r\n const bbox = options?.bbox\r\n\r\n // Page size scales with zoom: fewer records at low zoom (overview), more at high zoom (detail)\r\n const pageSize = zoom < 6 ? 500 : zoom < 10 ? 1000 : 2000\r\n\r\n // Build spatial filter string for ArcGIS when viewport is available\r\n let spatialFilter = ''\r\n if (bbox) {\r\n const [west, south, east, north] = bbox\r\n const geomStr = encodeURIComponent(\r\n JSON.stringify({ xmin: west, ymin: south, xmax: east, ymax: north, spatialReference: { wkid: 4326 } }),\r\n )\r\n spatialFilter = `&geometry=${geomStr}&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelIntersects&inSR=4326`\r\n }\r\n\r\n // Round bbox to 0.1° grid to maximise cache hits while panning\r\n const bboxKey = bbox\r\n ? bbox.map(n => (Math.round(n * 10) / 10).toFixed(1)).join(',')\r\n : 'global'\r\n const zoomBucket = Math.floor(zoom / 2)\r\n const featuresKey = `features:arcgis:${service.name}_${layerIndex}:${bboxKey}:z${zoomBucket}:${modTime}`\r\n\r\n const cached = getCache<AllGeoJSON>(featuresKey)\r\n if (cached) return cached\r\n\r\n const inFlight = inFlightFeatureRequests.get(featuresKey)\r\n if (inFlight) return inFlight\r\n\r\n const baseQuery = `${url}/${layerIndex}/query?outFields=*&where=1%3D1&f=geojson${spatialFilter}`\r\n\r\n const request = (async () => {\r\n try {\r\n const firstRes = await fetchWithTimeout(`${baseQuery}&resultOffset=0&resultRecordCount=${pageSize}`, 15_000)\r\n if (!firstRes.ok) return { type: 'FeatureCollection', features: [] } as AllGeoJSON\r\n\r\n const firstPage = await firstRes.json()\r\n if (!firstPage?.features) return { type: 'FeatureCollection', features: [] } as AllGeoJSON\r\n\r\n const allFeatures = [...firstPage.features]\r\n\r\n // If the server returned fewer features than the requested page size, the first page is complete.\r\n // This avoids an unnecessary count request for small datasets that have already finished loading.\r\n if (firstPage.exceededTransferLimit && firstPage.features.length >= pageSize) {\r\n try {\r\n const countRes = await fetchWithTimeout(`${baseQuery}&returnCountOnly=true&f=json`, 5_000)\r\n if (countRes.ok) {\r\n const { count: total } = await countRes.json()\r\n if (total > pageSize) {\r\n // Cap at 10 additional pages (~20 000 records max) to avoid browser memory issues\r\n const numPages = Math.min(Math.ceil((total - pageSize) / pageSize), 10)\r\n const morePages = await Promise.all(\r\n Array.from({ length: numPages }, (_, i) =>\r\n fetchWithTimeout(\r\n `${baseQuery}&resultOffset=${pageSize * (i + 1)}&resultRecordCount=${pageSize}`,\r\n 15_000,\r\n )\r\n .then(r => r.ok ? r.json() : null)\r\n .then(p => p?.features ?? [])\r\n .catch(() => []),\r\n ),\r\n )\r\n for (const page of morePages) allFeatures.push(...page)\r\n }\r\n }\r\n }\r\n catch { /* use first page only */ }\r\n }\r\n\r\n const result = { type: 'FeatureCollection', features: allFeatures } as AllGeoJSON\r\n // Viewport-constrained results cached for 15 min; global results for 1 hr\r\n setCache(featuresKey, result, bbox ? 15 * 60 * 1000 : 60 * 60 * 1000)\r\n return result\r\n }\r\n catch (error) {\r\n console.error(`ArcGIS: Error fetching features for layer ${layerIndex}:`, error)\r\n return { type: 'FeatureCollection', features: [] } as AllGeoJSON\r\n }\r\n finally {\r\n inFlightFeatureRequests.delete(featuresKey)\r\n }\r\n })()\r\n\r\n inFlightFeatureRequests.set(featuresKey, request)\r\n return request\r\n }\r\n\r\n const getFeaturesData = async () => {\r\n try {\r\n const res = await fetchWithTimeout(`${url}/${layerIndex}?f=pjson`)\r\n return res.ok ? res.json() : undefined\r\n }\r\n catch { return undefined }\r\n }\r\n\r\n const getFields = async () => {\r\n try {\r\n const fieldsKey = `fields:arcgis:${service.name}:${layerIndex}:${modTime}`\r\n const cached = getCache<any[]>(fieldsKey)\r\n if (cached) return cached\r\n\r\n const res = await fetchWithTimeout(featureInfoUrl)\r\n if (!res.ok) return []\r\n const featureData = await res.json()\r\n if (!featureData.fields) return []\r\n\r\n const typeMap = esriFieldTypes()\r\n\r\n const nameBasedType = (raw: any): FieldType | undefined => {\r\n const lc = (raw.name || '').toLowerCase()\r\n if (/(percentage|percent|ratio|average)/.test(lc)) return 'number'\r\n if (/(date|year|month|day|time)/.test(lc)) return 'datetime'\r\n return undefined\r\n }\r\n\r\n const inferFieldType = (raw: any): FieldType => {\r\n const norm = ([raw.type, raw.actualType, raw.sqlType, raw.esriType] as (string | undefined)[])\r\n .filter(Boolean).map(v => String(v).toLowerCase())\r\n if (norm.some(v => v.includes('boolean') || v === 'bool' || v === 'esrifieldtypeboolean')) return 'boolean'\r\n if (norm.some(v => /(double|float|integer|smallint|single|numeric|number|decimal)/.test(v)\r\n || ['esrifieldtypeinteger', 'esrifieldtypesmallinteger', 'esrifieldtypedouble', 'esrifieldtypefloat', 'esrifieldtypesingle'].includes(v))) return 'number'\r\n if (norm.some(v => /(date|time|timestamp)/.test(v))) return 'datetime'\r\n if (norm.some(v => /(globalid|guid|objectid|^oid$|_id$|id$)/.test(v))) return 'id'\r\n if (norm.some(v => v.includes('blob'))) return 'blob'\r\n if (norm.some(v => v.includes('raster') || v.includes('geometry'))) return 'object'\r\n return 'string'\r\n }\r\n\r\n const mapped = featureData.fields.map((field: any) => {\r\n const rawEsriType = field.type\r\n const inferred = nameBasedType(field) || typeMap[rawEsriType]?.type || inferFieldType(field)\r\n return { ...field, esriType: rawEsriType, type: inferred }\r\n })\r\n setCache(fieldsKey, mapped, 24 * 60 * 60 * 1000)\r\n return mapped\r\n }\r\n catch { return [] }\r\n }\r\n\r\n const baseName = formatName(service.name)\r\n const layerName = layer.name || `Layer ${layerIndex}`\r\n const name = layers.length > 1 ? `${baseName} - ${layerName}` : baseName\r\n\r\n return {\r\n id: extraInfo.id ? `${extraInfo.id}_${layerIndex}` : `${service.name}_${layerIndex}`,\r\n name,\r\n type: Array.isArray(service.layers) && service.layers[0]?.geometryType\r\n ? service.layers[0].geometryType\r\n : extraInfo.type || 'Feature Layer',\r\n datasetType: 'GeoJSON',\r\n dataManagementSystem: DataManagementSystem.Arcgis,\r\n url,\r\n license: extraInfo.licenseInfo || 'Unknown',\r\n description: extraInfo.description ? stripHtml(extraInfo.description) : 'No description available',\r\n publisher: extraInfo.owner || 'Unknown',\r\n contact: extraInfo.contact || 'Unknown',\r\n keywords: extraInfo.tags || extraInfo.typedKeywords || [],\r\n subject: extraInfo.subject || [],\r\n countrySubdivision,\r\n municipality,\r\n getFields,\r\n getFeatures,\r\n getFeaturesData,\r\n group,\r\n portal,\r\n layerColor: layerColorByName(name),\r\n } satisfies Dataset\r\n }),\r\n )\r\n\r\n return layerResults\r\n .filter((r): r is PromiseFulfilledResult<Dataset> => r.status === 'fulfilled' && r.value !== null)\r\n .map(r => r.value)\r\n }\r\n\r\n // Process at most 5 services concurrently — prevents ArcGIS rate-limiting\r\n const serviceResults = await withConcurrencyLimit(data.services, 5, processService)\r\n\r\n for (const result of serviceResults) {\r\n if (result.status === 'fulfilled') transformedDatasets.push(...result.value)\r\n }\r\n\r\n return transformedDatasets\r\n }\r\n catch (error) {\r\n console.error(`[ArcGIS] Failed to fetch datasets for portal \"${portal.name}\":`, error)\r\n return []\r\n }\r\n}\r\n\r\nexport interface EsriFieldTypes {\r\n [key: string]: { description: string, type: FieldType }\r\n}\r\n\r\nexport function esriFieldTypes(): EsriFieldTypes {\r\n return {\r\n esriFieldTypeString: { description: 'Text Field', type: 'string' },\r\n esriFieldTypeGlobalID: { description: 'Global ID', type: 'id' },\r\n esriFieldTypeGUID: { description: 'Global UID', type: 'id' },\r\n esriFieldTypeSmallInteger: { description: '16-bit Integer', type: 'number' },\r\n esriFieldTypeInteger: { description: '32-bit Integer', type: 'number' },\r\n esriFieldTypeSingle: { description: 'Single Precision Float', type: 'number' },\r\n esriFieldTypeDouble: { description: 'Double Precision Float', type: 'number' },\r\n esriFieldTypeDate: { description: 'Date/Time', type: 'datetime' },\r\n esriFieldTypedOnly: { description: 'Date', type: 'datetime' },\r\n esriFieldTypeTimeOnly: { description: 'Time', type: 'string' },\r\n esriFieldTypeTimestampOffset: { description: 'Timestamp', type: 'string' },\r\n esriFieldTypeBlob: { description: 'Binary', type: 'blob' },\r\n esriFieldTypeRaster: { description: 'Raster', type: 'object' },\r\n esriFieldTypeXML: { description: 'XML', type: 'string' },\r\n esriFieldTypeGeometry: { description: 'Spatial Geometry', type: 'object' },\r\n esriFieldTypeOID: { description: 'Object ID', type: 'id' },\r\n }\r\n}\r\n"],"mappings":"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","names":["_a","_b"]}
1
+ {"version":3,"sources":["../../../../../../../src/core/components/viewers/map/datasets/src/arcGISDatasets.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport { type AllGeoJSON } from '@turf/turf'\r\n\r\nimport { DataManagementSystem, type OpenDataPortal } from '../../../../../types/dbTypes'\r\nimport { layerColorByName } from '../../utils/stringToColour'\r\nimport { formatName, stripHtml } from '../utils'\r\n\r\nimport { buildValidationKey, getCache, setCache, withCache } from './cache'\r\n\r\nimport type { Dataset, FieldType } from '../../../../../types/datasetTypes'\r\n\r\nconst inFlightFeatureRequests = new Map<string, Promise<AllGeoJSON>>()\r\n\r\nexport type ViewportOptions = {\r\n bbox?: [number, number, number, number] // [west, south, east, north]\r\n zoom?: number\r\n}\r\n\r\nasync function fetchWithTimeout(url: string, timeout = 10_000): Promise<Response> {\r\n const controller = new AbortController()\r\n const timeoutId = setTimeout(() => controller.abort(), timeout)\r\n try {\r\n const response = await fetch(url, { signal: controller.signal })\r\n clearTimeout(timeoutId)\r\n return response\r\n }\r\n catch (error) {\r\n clearTimeout(timeoutId)\r\n throw error\r\n }\r\n}\r\n\r\n/**\r\n * Run `fn` over `items` with at most `limit` concurrent executions.\r\n * Preserves order of results matching input order.\r\n */\r\nasync function withConcurrencyLimit<T, R>(\r\n items: T[],\r\n limit: number,\r\n fn: (item: T) => Promise<R>,\r\n): Promise<PromiseSettledResult<R>[]> {\r\n const results: PromiseSettledResult<R>[] = new Array(items.length)\r\n let next = 0\r\n\r\n async function worker() {\r\n while (next < items.length) {\r\n const i = next++\r\n try {\r\n results[i] = { status: 'fulfilled', value: await fn(items[i]) }\r\n }\r\n catch (reason) {\r\n results[i] = { status: 'rejected', reason }\r\n }\r\n }\r\n }\r\n\r\n await Promise.all(\r\n Array.from({ length: Math.min(limit, items.length) }, worker),\r\n )\r\n return results\r\n}\r\n\r\nexport async function fetchArcGISDatasets(\r\n portal: OpenDataPortal,\r\n rowsPerPage: number,\r\n): Promise<Dataset[]> {\r\n const { apiUrl, countrySubdivision, municipality, group } = portal\r\n\r\n try {\r\n const baseUrl = (apiUrl || '').replace(/\\/+$/, '')\r\n const servicesUrl = `${baseUrl}/services?f=pjson`\r\n\r\n const response = await fetchWithTimeout(servicesUrl)\r\n if (!response.ok) {\r\n console.error(`[ArcGIS] \"${portal.name}\" services request failed — status ${response.status}`)\r\n throw new Error(`HTTP error! status: ${response.status}`)\r\n }\r\n\r\n const data = await response.json()\r\n\r\n const transformedDatasets: Dataset[] = []\r\n\r\n const processService = async (service: any): Promise<Dataset[]> => {\r\n const url = `${baseUrl}/services/${service.name}/${service.type}`\r\n const infoUrl = `${url}/info/itemInfo?f=pjson`\r\n\r\n const [infoRes, serviceRes] = await Promise.allSettled([\r\n fetchWithTimeout(infoUrl),\r\n fetchWithTimeout(`${url}?f=pjson`),\r\n ])\r\n\r\n let extraInfo: any = {}\r\n let serviceInfo: any = {}\r\n\r\n if (infoRes.status === 'fulfilled' && infoRes.value.ok)\r\n extraInfo = await infoRes.value.json()\r\n if (serviceRes.status === 'fulfilled' && serviceRes.value.ok)\r\n serviceInfo = await serviceRes.value.json()\r\n\r\n const layers = serviceInfo.layers && serviceInfo.layers.length > 0\r\n ? serviceInfo.layers.filter((l: any) => l.type === 'Feature Layer')\r\n : [{ id: 0, name: null, geometryType: null }]\r\n\r\n const hasNonNullGeometry = (featuresUrl: string, cacheKey: string): Promise<boolean> =>\r\n withCache<boolean>(cacheKey, 24 * 60 * 60 * 1000, async () => {\r\n try {\r\n const res = await fetchWithTimeout(`${featuresUrl}&resultRecordCount=1`)\r\n if (!res.ok) return false\r\n const d = await res.json()\r\n if (d?.error?.code || d?.error?.message) return false\r\n if (!d || d.type !== 'FeatureCollection' || !Array.isArray(d.features)) return false\r\n return d.features.some((f: any) => f && f.geometry)\r\n }\r\n catch { return false }\r\n })\r\n\r\n // Layers within a service are few (2-5 typically) — parallel is fine here\r\n const layerResults = await Promise.allSettled(\r\n layers.map(async (layer: any): Promise<Dataset | null> => {\r\n const layerIndex = layer.id\r\n const featuresUrl = `${url}/${layerIndex}/query?outFields=*&where=1%3D1&f=geojson`\r\n const featureInfoUrl = `${url}/${layerIndex}?f=pjson`\r\n\r\n const validKey = buildValidationKey(\r\n 'arcgis',\r\n `${service.name}_${layerIndex}`,\r\n serviceInfo?.documentInfo?.ModifiedTime || extraInfo?.modified || undefined,\r\n )\r\n const hasGeom = await hasNonNullGeometry(featuresUrl, validKey)\r\n if (!hasGeom) return null\r\n\r\n const modTime = serviceInfo?.documentInfo?.ModifiedTime || extraInfo?.modified || ''\r\n\r\n /**\r\n * getFeatures — viewport-aware, paginated.\r\n * If `bbox` is provided, only features intersecting the viewport are fetched.\r\n * Automatically paginates beyond the per-page limit.\r\n */\r\n const getFeatures = async (options?: ViewportOptions): Promise<AllGeoJSON> => {\r\n const zoom = options?.zoom ?? 10\r\n const bbox = options?.bbox\r\n\r\n // Page size scales with zoom: fewer records at low zoom (overview), more at high zoom (detail)\r\n const pageSize = zoom < 6 ? 500 : zoom < 10 ? 1000 : 2000\r\n\r\n // Build spatial filter string for ArcGIS when viewport is available\r\n let spatialFilter = ''\r\n if (bbox) {\r\n const [west, south, east, north] = bbox\r\n const geomStr = encodeURIComponent(\r\n JSON.stringify({ xmin: west, ymin: south, xmax: east, ymax: north, spatialReference: { wkid: 4326 } }),\r\n )\r\n spatialFilter = `&geometry=${geomStr}&geometryType=esriGeometryEnvelope&spatialRel=esriSpatialRelIntersects&inSR=4326`\r\n }\r\n\r\n // Round bbox to 0.1° grid to maximise cache hits while panning\r\n const bboxKey = bbox\r\n ? bbox.map(n => (Math.round(n * 10) / 10).toFixed(1)).join(',')\r\n : 'global'\r\n const zoomBucket = Math.floor(zoom / 2)\r\n const featuresKey = `features:arcgis:${service.name}_${layerIndex}:${bboxKey}:z${zoomBucket}:${modTime}`\r\n\r\n const cached = getCache<AllGeoJSON>(featuresKey)\r\n if (cached) return cached\r\n\r\n const inFlight = inFlightFeatureRequests.get(featuresKey)\r\n if (inFlight) return inFlight\r\n\r\n const baseQuery = `${url}/${layerIndex}/query?outFields=*&where=1%3D1&f=geojson${spatialFilter}`\r\n\r\n const request = (async () => {\r\n try {\r\n const firstRes = await fetchWithTimeout(`${baseQuery}&resultOffset=0&resultRecordCount=${pageSize}`, 15_000)\r\n if (!firstRes.ok) return { type: 'FeatureCollection', features: [] } as AllGeoJSON\r\n\r\n const firstPage = await firstRes.json()\r\n if (!firstPage?.features) return { type: 'FeatureCollection', features: [] } as AllGeoJSON\r\n\r\n const allFeatures = [...firstPage.features]\r\n\r\n // If the server returned fewer features than the requested page size, the first page is complete.\r\n // This avoids an unnecessary count request for small datasets that have already finished loading.\r\n if (firstPage.exceededTransferLimit && firstPage.features.length >= pageSize) {\r\n try {\r\n const countRes = await fetchWithTimeout(`${baseQuery}&returnCountOnly=true&f=json`, 5_000)\r\n if (countRes.ok) {\r\n const { count: total } = await countRes.json()\r\n if (total > pageSize) {\r\n // Cap at 10 additional pages (~20 000 records max) to avoid browser memory issues\r\n const numPages = Math.min(Math.ceil((total - pageSize) / pageSize), 10)\r\n const morePages = await Promise.all(\r\n Array.from({ length: numPages }, (_, i) =>\r\n fetchWithTimeout(\r\n `${baseQuery}&resultOffset=${pageSize * (i + 1)}&resultRecordCount=${pageSize}`,\r\n 15_000,\r\n )\r\n .then(r => r.ok ? r.json() : null)\r\n .then(p => p?.features ?? [])\r\n .catch(() => []),\r\n ),\r\n )\r\n for (const page of morePages) allFeatures.push(...page)\r\n }\r\n }\r\n }\r\n catch { /* use first page only */ }\r\n }\r\n\r\n const result = { type: 'FeatureCollection', features: allFeatures } as AllGeoJSON\r\n // Viewport-constrained results cached for 15 min; global results for 1 hr\r\n setCache(featuresKey, result, bbox ? 15 * 60 * 1000 : 60 * 60 * 1000)\r\n return result\r\n }\r\n catch (error) {\r\n console.error(`ArcGIS: Error fetching features for layer ${layerIndex}:`, error)\r\n return { type: 'FeatureCollection', features: [] } as AllGeoJSON\r\n }\r\n finally {\r\n inFlightFeatureRequests.delete(featuresKey)\r\n }\r\n })()\r\n\r\n inFlightFeatureRequests.set(featuresKey, request)\r\n return request\r\n }\r\n\r\n const getFeaturesData = async () => {\r\n try {\r\n const res = await fetchWithTimeout(`${url}/${layerIndex}?f=pjson`)\r\n return res.ok ? res.json() : undefined\r\n }\r\n catch { return undefined }\r\n }\r\n\r\n const getFields = async () => {\r\n try {\r\n const fieldsKey = `fields:arcgis:${service.name}:${layerIndex}:${modTime}`\r\n const cached = getCache<any[]>(fieldsKey)\r\n if (cached) return cached\r\n\r\n const res = await fetchWithTimeout(featureInfoUrl)\r\n if (!res.ok) return []\r\n const featureData = await res.json()\r\n if (!featureData.fields) return []\r\n\r\n const typeMap = esriFieldTypes()\r\n\r\n const nameBasedType = (raw: any): FieldType | undefined => {\r\n const lc = (raw.name || '').toLowerCase()\r\n if (/(percentage|percent|ratio|average)/.test(lc)) return 'number'\r\n if (/(date|year|month|day|time)/.test(lc)) return 'datetime'\r\n return undefined\r\n }\r\n\r\n const inferFieldType = (raw: any): FieldType => {\r\n const norm = ([raw.type, raw.actualType, raw.sqlType, raw.esriType] as (string | undefined)[])\r\n .filter(Boolean).map(v => String(v).toLowerCase())\r\n if (norm.some(v => v.includes('boolean') || v === 'bool' || v === 'esrifieldtypeboolean')) return 'boolean'\r\n if (norm.some(v => /(double|float|integer|smallint|single|numeric|number|decimal)/.test(v)\r\n || ['esrifieldtypeinteger', 'esrifieldtypesmallinteger', 'esrifieldtypedouble', 'esrifieldtypefloat', 'esrifieldtypesingle'].includes(v))) return 'number'\r\n if (norm.some(v => /(date|time|timestamp)/.test(v))) return 'datetime'\r\n if (norm.some(v => /(globalid|guid|objectid|^oid$|_id$|id$)/.test(v))) return 'id'\r\n if (norm.some(v => v.includes('blob'))) return 'blob'\r\n if (norm.some(v => v.includes('raster') || v.includes('geometry'))) return 'object'\r\n return 'string'\r\n }\r\n\r\n const mapped = featureData.fields.map((field: any) => {\r\n const rawEsriType = field.type\r\n const inferred = nameBasedType(field) || typeMap[rawEsriType]?.type || inferFieldType(field)\r\n return { ...field, esriType: rawEsriType, type: inferred }\r\n })\r\n setCache(fieldsKey, mapped, 24 * 60 * 60 * 1000)\r\n return mapped\r\n }\r\n catch { return [] }\r\n }\r\n\r\n const baseName = formatName(service.name)\r\n const layerName = layer.name || `Layer ${layerIndex}`\r\n const name = layers.length > 1 ? `${baseName} - ${layerName}` : baseName\r\n\r\n return {\r\n id: extraInfo.id ? `${extraInfo.id}_${layerIndex}` : `${service.name}_${layerIndex}`,\r\n name,\r\n type: Array.isArray(service.layers) && service.layers[0]?.geometryType\r\n ? service.layers[0].geometryType\r\n : extraInfo.type || 'Feature Layer',\r\n datasetType: 'GeoJSON',\r\n dataManagementSystem: DataManagementSystem.Arcgis,\r\n url,\r\n license: extraInfo.licenseInfo || 'Unknown',\r\n description: extraInfo.description ? stripHtml(extraInfo.description) : 'No description available',\r\n publisher: extraInfo.owner || 'Unknown',\r\n contact: extraInfo.contact || 'Unknown',\r\n keywords: extraInfo.tags || extraInfo.typedKeywords || [],\r\n subject: extraInfo.subject || [],\r\n countrySubdivision,\r\n municipality,\r\n getFields,\r\n getFeatures,\r\n getFeaturesData,\r\n group,\r\n portal,\r\n layerColor: layerColorByName(name),\r\n } satisfies Dataset\r\n }),\r\n )\r\n\r\n return layerResults\r\n .filter((r): r is PromiseFulfilledResult<Dataset> => r.status === 'fulfilled' && r.value !== null)\r\n .map(r => r.value)\r\n }\r\n\r\n // Process at most 5 services concurrently — prevents ArcGIS rate-limiting\r\n const serviceResults = await withConcurrencyLimit(data.services, 5, processService)\r\n\r\n for (const result of serviceResults) {\r\n if (result.status === 'fulfilled') transformedDatasets.push(...result.value)\r\n }\r\n\r\n return transformedDatasets\r\n }\r\n catch (error) {\r\n console.error(`[ArcGIS] Failed to fetch datasets for portal \"${portal.name}\":`, error)\r\n return []\r\n }\r\n}\r\n\r\nexport interface EsriFieldTypes {\r\n [key: string]: { description: string, type: FieldType }\r\n}\r\n\r\nexport function esriFieldTypes(): EsriFieldTypes {\r\n return {\r\n esriFieldTypeString: { description: 'Text Field', type: 'string' },\r\n esriFieldTypeGlobalID: { description: 'Global ID', type: 'id' },\r\n esriFieldTypeGUID: { description: 'Global UID', type: 'id' },\r\n esriFieldTypeSmallInteger: { description: '16-bit Integer', type: 'number' },\r\n esriFieldTypeInteger: { description: '32-bit Integer', type: 'number' },\r\n esriFieldTypeSingle: { description: 'Single Precision Float', type: 'number' },\r\n esriFieldTypeDouble: { description: 'Double Precision Float', type: 'number' },\r\n esriFieldTypeDate: { description: 'Date/Time', type: 'datetime' },\r\n esriFieldTypedOnly: { description: 'Date', type: 'datetime' },\r\n esriFieldTypeTimeOnly: { description: 'Time', type: 'string' },\r\n esriFieldTypeTimestampOffset: { description: 'Timestamp', type: 'string' },\r\n esriFieldTypeBlob: { description: 'Binary', type: 'blob' },\r\n esriFieldTypeRaster: { description: 'Raster', type: 'object' },\r\n esriFieldTypeXML: { description: 'XML', type: 'string' },\r\n esriFieldTypeGeometry: { description: 'Spatial Geometry', type: 'object' },\r\n esriFieldTypeOID: { description: 'Object ID', type: 'id' },\r\n }\r\n}\r\n"],"mappings":"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","names":["_a"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ckanDatasets.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/datasets/src/ckanDatasets.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAA;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAOlE,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,OAAO,EAAE,CAAC,CA8QpB;AAED,MAAM,WAAW,cAAc;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,CAAA;CACxD"}
1
+ {"version":3,"file":"ckanDatasets.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/datasets/src/ckanDatasets.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAA;AAC3E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAA;AAOlE,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,OAAO,EAAE,CAAC,CA4QpB;AAED,MAAM,WAAW,cAAc;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,SAAS,CAAA;KAAE,CAAA;CACxD"}
@@ -122,12 +122,9 @@ async function fetchCkanDatasets(portal) {
122
122
  return [];
123
123
  };
124
124
  const getFeatures = async () => {
125
- var _a2, _b2;
126
125
  const featuresKey = `features:ckan:${geoJsonResource.id}:${pkg.metadata_modified || pkg.metadata_created || ""}`;
127
126
  const cached = getCache(featuresKey);
128
127
  if (cached) {
129
- const cachedCount = "features" in cached ? (_b2 = (_a2 = cached.features) == null ? void 0 : _a2.length) != null ? _b2 : 0 : 0;
130
- console.log(`\u2705 CKAN getFeatures: Returning ${cachedCount} cached features for "${pkg.name}"`);
131
128
  return cached;
132
129
  }
133
130
  const limit = 5e3;
@@ -145,10 +142,10 @@ async function fetchCkanDatasets(portal) {
145
142
  let featuresCollection;
146
143
  if (data2.result && Array.isArray(data2.result.records)) {
147
144
  const features = data2.result.records.map((properties) => {
148
- var _a3;
145
+ var _a2;
149
146
  try {
150
147
  let geometry;
151
- geometry = ((_a3 = properties.geometry) == null ? void 0 : _a3.type) ? properties.geometry : JSON.parse(properties.geometry);
148
+ geometry = ((_a2 = properties.geometry) == null ? void 0 : _a2.type) ? properties.geometry : JSON.parse(properties.geometry);
152
149
  return {
153
150
  type: "Feature",
154
151
  geometry,