@collabdt/core 0.0.41 → 0.0.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (265) hide show
  1. package/README.md +1 -1
  2. package/dist/core/components/Toolbar.d.ts.map +1 -1
  3. package/dist/core/components/Toolbar.js.map +1 -1
  4. package/dist/core/components/ToolbarBody.js.map +1 -1
  5. package/dist/core/components/TopNavigationBar.js.map +1 -1
  6. package/dist/core/components/authentication/ForgotPassword.js.map +1 -1
  7. package/dist/core/components/authentication/Signin.js.map +1 -1
  8. package/dist/core/components/authentication/Signup.js.map +1 -1
  9. package/dist/core/components/settings/src/OrganizationSkeleton.js.map +1 -1
  10. package/dist/core/components/settings/src/SettingsSkeleton.js.map +1 -1
  11. package/dist/core/components/ui/Comments/CollapsibleCommentItem.d.ts.map +1 -1
  12. package/dist/core/components/ui/Comments/CollapsibleCommentItem.js.map +1 -1
  13. package/dist/core/components/ui/Comments/CommentsSection.d.ts.map +1 -1
  14. package/dist/core/components/ui/Comments/CommentsSection.js.map +1 -1
  15. package/dist/core/components/ui/DataTable.d.ts.map +1 -1
  16. package/dist/core/components/ui/DataTable.js +7 -0
  17. package/dist/core/components/ui/DataTable.js.map +1 -1
  18. package/dist/core/components/ui/FilesManager/src/FileItemComponent.d.ts.map +1 -1
  19. package/dist/core/components/ui/FilesManager/src/FileItemComponent.js.map +1 -1
  20. package/dist/core/components/ui/FilesManager/src/FileMarker.d.ts +5 -2
  21. package/dist/core/components/ui/FilesManager/src/FileMarker.d.ts.map +1 -1
  22. package/dist/core/components/ui/FilesManager/src/FileMarker.js +84 -21
  23. package/dist/core/components/ui/FilesManager/src/FileMarker.js.map +1 -1
  24. package/dist/core/components/ui/FilesManager/src/convertIfcToFragmentsFile.d.ts.map +1 -1
  25. package/dist/core/components/ui/FilesManager/src/convertIfcToFragmentsFile.js.map +1 -1
  26. package/dist/core/components/ui/FilesManager/src/useFileUploadHandler.d.ts.map +1 -1
  27. package/dist/core/components/ui/FilesManager/src/useFileUploadHandler.js.map +1 -1
  28. package/dist/core/components/ui/Icons/IfcIcon.d.ts.map +1 -1
  29. package/dist/core/components/ui/Icons/IfcIcon.js.map +1 -1
  30. package/dist/core/components/ui/InfoSidebar/index.d.ts.map +1 -1
  31. package/dist/core/components/ui/InfoSidebar/index.js.map +1 -1
  32. package/dist/core/components/ui/Navbar.d.ts.map +1 -1
  33. package/dist/core/components/ui/Navbar.js.map +1 -1
  34. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts.map +1 -1
  35. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js.map +1 -1
  36. package/dist/core/components/ui/Sensors/SensorTagsSection.d.ts.map +1 -1
  37. package/dist/core/components/ui/Sensors/SensorTagsSection.js.map +1 -1
  38. package/dist/core/components/ui/Sensors/SensorsSection.d.ts.map +1 -1
  39. package/dist/core/components/ui/Sensors/SensorsSection.js.map +1 -1
  40. package/dist/core/components/ui/ShareFeature/ShareToolSubmenu.d.ts.map +1 -1
  41. package/dist/core/components/ui/ShareFeature/ShareToolSubmenu.js.map +1 -1
  42. package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js +2 -2
  43. package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js.map +1 -1
  44. package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.js +2 -2
  45. package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.js.map +1 -1
  46. package/dist/core/components/viewers/Viewer.d.ts.map +1 -1
  47. package/dist/core/components/viewers/Viewer.js +5 -1
  48. package/dist/core/components/viewers/Viewer.js.map +1 -1
  49. package/dist/core/components/viewers/bim/BimToolbar.d.ts.map +1 -1
  50. package/dist/core/components/viewers/bim/BimToolbar.js.map +1 -1
  51. package/dist/core/components/viewers/bim/BimViewer.d.ts.map +1 -1
  52. package/dist/core/components/viewers/bim/BimViewer.js +14 -5
  53. package/dist/core/components/viewers/bim/BimViewer.js.map +1 -1
  54. package/dist/core/components/viewers/bim/src/BimLoadingState/index.d.ts.map +1 -1
  55. package/dist/core/components/viewers/bim/src/BimLoadingState/index.js +6 -0
  56. package/dist/core/components/viewers/bim/src/BimLoadingState/index.js.map +1 -1
  57. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
  58. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js +168 -39
  59. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js.map +1 -1
  60. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
  61. package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
  62. package/dist/core/components/viewers/bim/src/BimSidebar/src/LayersTab/src/FloorplanSection.d.ts.map +1 -1
  63. package/dist/core/components/viewers/bim/src/BimSidebar/src/LayersTab/src/FloorplanSection.js +1 -1
  64. package/dist/core/components/viewers/bim/src/BimSidebar/src/LayersTab/src/FloorplanSection.js.map +1 -1
  65. package/dist/core/components/viewers/bim/src/DXFLoader/index.d.ts +14 -37
  66. package/dist/core/components/viewers/bim/src/DXFLoader/index.d.ts.map +1 -1
  67. package/dist/core/components/viewers/bim/src/DXFLoader/index.js +31 -318
  68. package/dist/core/components/viewers/bim/src/DXFLoader/index.js.map +1 -1
  69. package/dist/core/components/viewers/bim/src/FloorplanTool/index.d.ts +66 -7
  70. package/dist/core/components/viewers/bim/src/FloorplanTool/index.d.ts.map +1 -1
  71. package/dist/core/components/viewers/bim/src/FloorplanTool/index.js +253 -21
  72. package/dist/core/components/viewers/bim/src/FloorplanTool/index.js.map +1 -1
  73. package/dist/core/components/viewers/bim/src/ModelManager/index.d.ts.map +1 -1
  74. package/dist/core/components/viewers/bim/src/ModelManager/index.js +9 -0
  75. package/dist/core/components/viewers/bim/src/ModelManager/index.js.map +1 -1
  76. package/dist/core/components/viewers/bim/src/SimpleBimViewer.d.ts.map +1 -1
  77. package/dist/core/components/viewers/bim/src/SimpleBimViewer.js.map +1 -1
  78. package/dist/core/components/viewers/bim/src/lib/TrueNorthPopover.d.ts +3 -2
  79. package/dist/core/components/viewers/bim/src/lib/TrueNorthPopover.d.ts.map +1 -1
  80. package/dist/core/components/viewers/bim/src/lib/TrueNorthPopover.js.map +1 -1
  81. package/dist/core/components/viewers/bim/src/lib/useFriendlyIfcClassName.d.ts.map +1 -1
  82. package/dist/core/components/viewers/bim/src/lib/useFriendlyIfcClassName.js +3 -4
  83. package/dist/core/components/viewers/bim/src/lib/useFriendlyIfcClassName.js.map +1 -1
  84. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts.map +1 -1
  85. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js +40 -18
  86. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js.map +1 -1
  87. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.d.ts +2 -5
  88. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.d.ts.map +1 -1
  89. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.js +45 -59
  90. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/AddDxf.js.map +1 -1
  91. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js +1 -0
  92. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js.map +1 -1
  93. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.d.ts +10 -1
  94. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.d.ts.map +1 -1
  95. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.js +25 -73
  96. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileHandler.js.map +1 -1
  97. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.d.ts +7 -3
  98. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.d.ts.map +1 -1
  99. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.js +42 -78
  100. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/FileMarkerUtils.js.map +1 -1
  101. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/Position3DCard.d.ts.map +1 -1
  102. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/Position3DCard.js +52 -75
  103. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/Position3DCard.js.map +1 -1
  104. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.d.ts +15 -3
  105. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.d.ts.map +1 -1
  106. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.js +165 -105
  107. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useFilePlacement.js.map +1 -1
  108. package/dist/core/components/viewers/index.d.ts.map +1 -1
  109. package/dist/core/components/viewers/index.js.map +1 -1
  110. package/dist/core/components/viewers/map/MapViewer.d.ts.map +1 -1
  111. package/dist/core/components/viewers/map/MapViewer.js +1 -0
  112. package/dist/core/components/viewers/map/MapViewer.js.map +1 -1
  113. package/dist/core/components/viewers/map/datasets/DatasetManager/index.d.ts.map +1 -1
  114. package/dist/core/components/viewers/map/datasets/DatasetManager/index.js +4 -3
  115. package/dist/core/components/viewers/map/datasets/DatasetManager/index.js.map +1 -1
  116. package/dist/core/components/viewers/map/datasets/RowActions.d.ts.map +1 -1
  117. package/dist/core/components/viewers/map/datasets/RowActions.js +148 -0
  118. package/dist/core/components/viewers/map/datasets/RowActions.js.map +1 -1
  119. package/dist/core/components/viewers/map/datasets/index.d.ts.map +1 -1
  120. package/dist/core/components/viewers/map/datasets/index.js +32 -15
  121. package/dist/core/components/viewers/map/datasets/index.js.map +1 -1
  122. package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.d.ts +4 -0
  123. package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.d.ts.map +1 -0
  124. package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.js +43 -0
  125. package/dist/core/components/viewers/map/datasets/src/builtinLiveDatasets.js.map +1 -0
  126. package/dist/core/components/viewers/map/datasets/src/localDatasets.d.ts.map +1 -1
  127. package/dist/core/components/viewers/map/datasets/src/localDatasets.js +39 -3
  128. package/dist/core/components/viewers/map/datasets/src/localDatasets.js.map +1 -1
  129. package/dist/core/components/viewers/map/datasets/src/minioDatasets.d.ts +1 -1
  130. package/dist/core/components/viewers/map/datasets/src/minioDatasets.d.ts.map +1 -1
  131. package/dist/core/components/viewers/map/datasets/src/minioDatasets.js +2 -1
  132. package/dist/core/components/viewers/map/datasets/src/minioDatasets.js.map +1 -1
  133. package/dist/core/components/viewers/map/datasets/src/publishedTiles.d.ts +47 -0
  134. package/dist/core/components/viewers/map/datasets/src/publishedTiles.d.ts.map +1 -0
  135. package/dist/core/components/viewers/map/datasets/src/publishedTiles.js +114 -0
  136. package/dist/core/components/viewers/map/datasets/src/publishedTiles.js.map +1 -0
  137. package/dist/core/components/viewers/map/datasets/src/wmsTime.d.ts +49 -0
  138. package/dist/core/components/viewers/map/datasets/src/wmsTime.d.ts.map +1 -0
  139. package/dist/core/components/viewers/map/datasets/src/wmsTime.js +100 -0
  140. package/dist/core/components/viewers/map/datasets/src/wmsTime.js.map +1 -0
  141. package/dist/core/components/viewers/map/src/Geocoder.d.ts.map +1 -1
  142. package/dist/core/components/viewers/map/src/Geocoder.js +9 -9
  143. package/dist/core/components/viewers/map/src/Geocoder.js.map +1 -1
  144. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.d.ts.map +1 -1
  145. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js +25 -43
  146. package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js.map +1 -1
  147. package/dist/core/components/viewers/map/src/MapLayers/index.d.ts.map +1 -1
  148. package/dist/core/components/viewers/map/src/MapLayers/index.js.map +1 -1
  149. package/dist/core/components/viewers/map/src/MapLayers/src/BimLayer/index.d.ts.map +1 -1
  150. package/dist/core/components/viewers/map/src/MapLayers/src/BimLayer/index.js +19 -2
  151. package/dist/core/components/viewers/map/src/MapLayers/src/BimLayer/index.js.map +1 -1
  152. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.d.ts +9 -0
  153. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.d.ts.map +1 -0
  154. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.js +28 -0
  155. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/countryLayerUtils.js.map +1 -0
  156. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.d.ts.map +1 -1
  157. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js +1 -16
  158. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js.map +1 -1
  159. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/FileModelLayer/FileModelLayer.d.ts.map +1 -1
  160. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/FileModelLayer/FileModelLayer.js.map +1 -1
  161. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.d.ts.map +1 -1
  162. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.js +31 -2
  163. package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/utils/CustomModelLayer.js.map +1 -1
  164. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.d.ts +21 -0
  165. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.d.ts.map +1 -0
  166. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.js +111 -0
  167. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/WmsTimeControl.js.map +1 -0
  168. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.d.ts.map +1 -1
  169. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.js +77 -2
  170. package/dist/core/components/viewers/map/src/MapLayers/src/OpenDataLayer/src/index.js.map +1 -1
  171. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
  172. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.js.map +1 -1
  173. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
  174. package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
  175. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.d.ts.map +1 -1
  176. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js +10 -3
  177. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js.map +1 -1
  178. package/dist/core/components/viewers/map/utils/geocoder.d.ts +6 -2
  179. package/dist/core/components/viewers/map/utils/geocoder.d.ts.map +1 -1
  180. package/dist/core/components/viewers/map/utils/geocoder.js +10 -62
  181. package/dist/core/components/viewers/map/utils/geocoder.js.map +1 -1
  182. package/dist/core/components/viewers/map/utils/geocoding/adapters.d.ts +5 -0
  183. package/dist/core/components/viewers/map/utils/geocoding/adapters.d.ts.map +1 -0
  184. package/dist/core/components/viewers/map/utils/geocoding/adapters.js +192 -0
  185. package/dist/core/components/viewers/map/utils/geocoding/adapters.js.map +1 -0
  186. package/dist/core/components/viewers/map/utils/geocoding/config.d.ts +6 -0
  187. package/dist/core/components/viewers/map/utils/geocoding/config.d.ts.map +1 -0
  188. package/dist/core/components/viewers/map/utils/geocoding/config.js +14 -0
  189. package/dist/core/components/viewers/map/utils/geocoding/config.js.map +1 -0
  190. package/dist/core/components/viewers/map/utils/geocoding/index.d.ts +8 -0
  191. package/dist/core/components/viewers/map/utils/geocoding/index.d.ts.map +1 -0
  192. package/dist/core/components/viewers/map/utils/geocoding/index.js +44 -0
  193. package/dist/core/components/viewers/map/utils/geocoding/index.js.map +1 -0
  194. package/dist/core/components/viewers/map/utils/geocoding/osm.d.ts +6 -0
  195. package/dist/core/components/viewers/map/utils/geocoding/osm.d.ts.map +1 -0
  196. package/dist/core/components/viewers/map/utils/geocoding/osm.js +39 -0
  197. package/dist/core/components/viewers/map/utils/geocoding/osm.js.map +1 -0
  198. package/dist/core/components/viewers/map/utils/geocoding/pelias.d.ts +8 -0
  199. package/dist/core/components/viewers/map/utils/geocoding/pelias.d.ts.map +1 -0
  200. package/dist/core/components/viewers/map/utils/geocoding/pelias.js +35 -0
  201. package/dist/core/components/viewers/map/utils/geocoding/pelias.js.map +1 -0
  202. package/dist/core/components/viewers/pointcloud/PointCloudToolbar.d.ts.map +1 -1
  203. package/dist/core/components/viewers/pointcloud/PointCloudToolbar.js.map +1 -1
  204. package/dist/core/components/viewers/pointcloud/PointCloudViewer.js +1 -3
  205. package/dist/core/components/viewers/pointcloud/PointCloudViewer.js.map +1 -1
  206. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.d.ts.map +1 -1
  207. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js +2 -3
  208. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js.map +1 -1
  209. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
  210. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/FilesSection.js +8 -2
  211. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/FilesSection.js.map +1 -1
  212. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.d.ts.map +1 -1
  213. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.js.map +1 -1
  214. package/dist/core/components/viewers/pointcloud/src/tools/PerformanceSettingsTools/NodeSizeSelectionTool.js +9 -9
  215. package/dist/core/components/viewers/pointcloud/src/tools/PerformanceSettingsTools/NodeSizeSelectionTool.js.map +1 -1
  216. package/dist/core/hooks/provider.js.map +1 -1
  217. package/dist/core/plugins/host/provider.d.ts.map +1 -1
  218. package/dist/core/plugins/host/provider.js.map +1 -1
  219. package/dist/core/store/AppConfig/context.d.ts.map +1 -1
  220. package/dist/core/store/AppConfig/context.js.map +1 -1
  221. package/dist/core/store/BIM/context.d.ts.map +1 -1
  222. package/dist/core/store/BIM/context.js.map +1 -1
  223. package/dist/core/store/BIM/reducer.d.ts +0 -1
  224. package/dist/core/store/BIM/reducer.d.ts.map +1 -1
  225. package/dist/core/store/BIM/reducer.js +0 -4
  226. package/dist/core/store/BIM/reducer.js.map +1 -1
  227. package/dist/core/store/Buildings/context.d.ts.map +1 -1
  228. package/dist/core/store/Buildings/context.js.map +1 -1
  229. package/dist/core/store/Content/context.d.ts.map +1 -1
  230. package/dist/core/store/Content/context.js.map +1 -1
  231. package/dist/core/store/Datasets/context.d.ts.map +1 -1
  232. package/dist/core/store/Datasets/context.js +2 -1
  233. package/dist/core/store/Datasets/context.js.map +1 -1
  234. package/dist/core/store/Datasets/reducer.d.ts +2 -0
  235. package/dist/core/store/Datasets/reducer.d.ts.map +1 -1
  236. package/dist/core/store/Datasets/reducer.js +9 -4
  237. package/dist/core/store/Datasets/reducer.js.map +1 -1
  238. package/dist/core/store/Files/context.d.ts.map +1 -1
  239. package/dist/core/store/Files/context.js.map +1 -1
  240. package/dist/core/store/Map/context.d.ts.map +1 -1
  241. package/dist/core/store/Map/context.js.map +1 -1
  242. package/dist/core/store/Menus/context.d.ts.map +1 -1
  243. package/dist/core/store/Menus/context.js.map +1 -1
  244. package/dist/core/store/Permissions/context.d.ts.map +1 -1
  245. package/dist/core/store/Permissions/context.js.map +1 -1
  246. package/dist/core/store/PointCloud/context.d.ts.map +1 -1
  247. package/dist/core/store/PointCloud/context.js.map +1 -1
  248. package/dist/core/store/Tools/context.d.ts.map +1 -1
  249. package/dist/core/store/Tools/context.js.map +1 -1
  250. package/dist/core/types/datasetTypes.d.ts +8 -1
  251. package/dist/core/types/datasetTypes.d.ts.map +1 -1
  252. package/dist/core/types/dbTypes.d.ts +13 -13
  253. package/dist/core/types/dbTypes.d.ts.map +1 -1
  254. package/dist/core/types/dbTypes.js +13 -13
  255. package/dist/core/types/dbTypes.js.map +1 -1
  256. package/dist/core/types/index.d.ts +1 -1
  257. package/dist/core/types/index.d.ts.map +1 -1
  258. package/dist/core/types/index.js.map +1 -1
  259. package/dist/core/utils/imageUtils.js +1 -1
  260. package/dist/core/utils/imageUtils.js.map +1 -1
  261. package/package.json +2 -1
  262. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.d.ts +0 -3
  263. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.d.ts.map +0 -1
  264. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.js +0 -173
  265. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudViewer-old.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/core/components/viewers/bim/BimToolbar.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { bimToolbarTools } from './src/tools/bimToolbar'\nimport { ToolbarBody } from '../../ToolbarBody'\n\n// Audit Phase 1.A (F-1e): lives in the BIM viewer folder so the dynamic\n// import in Toolbar.tsx ties this component into the same async chunk\n// graph as BimViewer (F-1) / BimLayer (F-1b). bimToolbarTools() imports\n// the BIM tool registry which transitively pulls @thatopen — keeping all\n// of it behind this lazy boundary is what allows Phase 1.A to drop\n// @thatopen out of the eager bundle.\nexport function BimToolbar() {\n return <ToolbarBody viewer=\"bim\" tools={bimToolbarTools()} />\n}\n"],"mappings":";AAaS;AAVT,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAQrB,SAAS,aAAa;AAC3B,SAAO,oBAAC,eAAY,QAAO,OAAM,OAAO,gBAAgB,GAAG;AAC7D;","names":[]}
1
+ {"version":3,"sources":["../../../../../src/core/components/viewers/bim/BimToolbar.tsx"],"sourcesContent":["'use client'\n\nimport * as React from 'react'\nimport { bimToolbarTools } from './src/tools/bimToolbar'\nimport { ToolbarBody } from '../../ToolbarBody'\n\nexport function BimToolbar() {\n return <ToolbarBody viewer=\"bim\" tools={bimToolbarTools()} />\n}\n"],"mappings":";AAOS;AAJT,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAErB,SAAS,aAAa;AAC3B,SAAO,oBAAC,eAAY,QAAO,OAAM,OAAO,gBAAgB,GAAG;AAC7D;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"file":"BimViewer.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/viewers/bim/BimViewer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAmB/B,wBAAgB,SAAS,sBAiOxB"}
1
+ {"version":3,"file":"BimViewer.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/viewers/bim/BimViewer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAmB/B,wBAAgB,SAAS,sBA2PxB"}
@@ -29,9 +29,10 @@ function BimViewer() {
29
29
  const containerRef = React.useRef(null);
30
30
  const workerUrlRef = React.useRef(null);
31
31
  const resizeObserverRef = React.useRef(null);
32
+ const componentsRef = React.useRef(null);
32
33
  const createViewer = React.useCallback(
33
- async () => {
34
- if (!containerRef.current || bimComponents) return;
34
+ async (isCancelled) => {
35
+ if (!containerRef.current || componentsRef.current) return;
35
36
  const container = containerRef.current;
36
37
  const components = new OBC.Components();
37
38
  const worlds = components.get(OBC.Worlds);
@@ -95,6 +96,11 @@ function BimViewer() {
95
96
  await world.scene.updateShadows();
96
97
  });
97
98
  world.scene.three.background = null;
99
+ if (isCancelled()) {
100
+ components.dispose();
101
+ return;
102
+ }
103
+ componentsRef.current = components;
98
104
  bimDispatch({
99
105
  type: "SET_COMPONENTS",
100
106
  payload: { bimComponents: components, world, fragments }
@@ -123,13 +129,16 @@ function BimViewer() {
123
129
  []
124
130
  );
125
131
  React.useEffect(() => {
126
- createViewer();
132
+ let cancelled = false;
133
+ createViewer(() => cancelled);
127
134
  return () => {
135
+ cancelled = true;
128
136
  if (resizeObserverRef.current) {
129
137
  resizeObserverRef.current.disconnect();
130
138
  }
131
- if (bimComponents) {
132
- bimComponents.dispose();
139
+ if (componentsRef.current) {
140
+ componentsRef.current.dispose();
141
+ componentsRef.current = null;
133
142
  }
134
143
  bimDispatch({
135
144
  type: "DISPOSE-BIM"
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/core/components/viewers/bim/BimViewer.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport * as React from \"react\";\r\nimport * as OBC from \"@thatopen/components\";\r\nimport * as OBF from \"@thatopen/components-front\"\r\nimport * as THREE from \"three\";\r\nimport { useTranslations, useLocale } from 'next-intl';\r\nimport { ToolsContext, BimContext, MenusContext } from \"../../../store\";\r\n\r\nimport { CurrentWorld } from \"./src/CurrentWorld\";\r\nimport { CurrentCamera } from './src/CurrentCamera';\r\nimport { Highlighter } from \"./src/Highlighter\";\r\nimport { FloorplanTool } from \"./src/FloorplanTool\";\r\nimport { ElevationsTool } from \"./src/ElevationsTool\";\r\nimport { ViewModeCoordinator } from \"./src/lib/ViewModeCoordinator\";\r\n\r\nimport { PropertiesMenu } from \"./src/propertiesMenu\";\r\nimport { BimLoadingState } from \"./src/BimLoadingState\";\r\nimport { ViewportGizmo } from \"./src/ViewportGizmo\";\r\nimport { useBimCoordinateSystem } from \"../useCoordinateSystem\";\r\n\r\nexport function BimViewer() {\r\n\r\n const t = useTranslations('ViewportGizmo');\r\n const locale = useLocale();\r\n\r\n const { dispatch: bimDispatch, state: bimState } = React.useContext(BimContext);\r\n const { bimComponents } = bimState.bim;\r\n\r\n const { dispatch: toolsDispatch, state: toolsState } = React.useContext(ToolsContext);\r\n const { currentToolId } = toolsState.tools;\r\n\r\n const { state: menusState } = React.useContext(MenusContext);\r\n const { currentViewer } = menusState.menus;\r\n \r\n\r\n const containerRef = React.useRef<HTMLDivElement>(null);\r\n const workerUrlRef = React.useRef<string | null>(null);\r\n const resizeObserverRef = React.useRef<ResizeObserver | null>(null);\r\n\r\n const createViewer = React.useCallback(\r\n async () => {\r\n if (!containerRef.current || bimComponents) return;\r\n\r\n const container = containerRef.current;\r\n const components = new OBC.Components();\r\n const worlds = components.get(OBC.Worlds);\r\n const world = worlds.create<\r\n OBC.ShadowedScene,\r\n OBC.OrthoPerspectiveCamera,\r\n OBF.PostproductionRenderer\r\n >();\r\n\r\n world.scene = new OBC.ShadowedScene(components);\r\n\r\n world.renderer = new OBF.PostproductionRenderer(components, container);\r\n world.camera = new OBC.OrthoPerspectiveCamera(components);\r\n\r\n components.init();\r\n\r\n world.scene.setup();\r\n world.scene.three.background = null;\r\n\r\n const grids = components.get(OBC.Grids);\r\n const grid = grids.create(world);\r\n\r\n if (grid) {\r\n bimDispatch({\r\n \"type\": \"SET_GRID\",\r\n \"payload\": { grid }\r\n });\r\n }\r\n\r\n const axesHelper = new THREE.AxesHelper(5);\r\n world.scene.three.add(axesHelper);\r\n\r\n const fragments = components.get(OBC.FragmentsManager);\r\n\r\n const githubUrl =\r\n \"https://thatopen.github.io/engine_fragment/resources/worker.mjs\";\r\n const fetchedUrl = await fetch(githubUrl);\r\n const workerBlob = await fetchedUrl.blob();\r\n const workerFile = new File([workerBlob], \"worker.mjs\", {\r\n type: \"text/javascript\",\r\n });\r\n const workerUrl = URL.createObjectURL(workerFile);\r\n workerUrlRef.current = workerUrl; // Store reference for cleanup\r\n fragments.init(workerUrl);\r\n\r\n world.camera.controls.addEventListener(\"control\", () =>\r\n fragments.core.update(),\r\n );\r\n\r\n world.camera.controls.restThreshold = 0.005;\r\n world.camera.controls.addEventListener(\"rest\", () =>\r\n fragments.core.update(true)\r\n );\r\n\r\n components.get(CurrentWorld).world = world;\r\n components.get(CurrentCamera).camera = world.camera;\r\n components.get(Highlighter);\r\n components.get(ViewModeCoordinator);\r\n components.get(FloorplanTool);\r\n components.get(ElevationsTool);\r\n\r\n // Grid injection is safe here — fragments.core is initialized.\r\n if (grid) {\r\n components.get(FloorplanTool).setGrid(grid);\r\n components.get(ElevationsTool).setGrid(grid);\r\n }\r\n\r\n // Enable shadows\r\n world.renderer.three.shadowMap.enabled = true;\r\n world.renderer.three.shadowMap.type = THREE.PCFSoftShadowMap;\r\n world.scene.setup({\r\n shadows: {\r\n cascade: 1,\r\n resolution: 1024,\r\n },\r\n });\r\n\r\n world.scene.distanceRenderer.excludedObjects.add(grid.three);\r\n\r\n await world.scene.updateShadows();\r\n\r\n world.camera.controls.addEventListener(\"rest\", async () => {\r\n await world.scene.updateShadows();\r\n });\r\n\r\n world.scene.three.background = null;\r\n\r\n bimDispatch({\r\n type: \"SET_COMPONENTS\",\r\n payload: { bimComponents: components, world, fragments }\r\n });\r\n\r\n // Ensure canvas takes full container size\r\n const canvas = container.querySelector('canvas');\r\n if (canvas) {\r\n canvas.style.width = '100%';\r\n canvas.style.height = '100%';\r\n canvas.style.display = 'block';\r\n }\r\n\r\n // Handle resize using container dimensions\r\n const handleResize = () => {\r\n const width = container.clientWidth;\r\n const height = container.clientHeight;\r\n if (width && height) {\r\n world.renderer?.resize(new THREE.Vector2(width, height));\r\n }\r\n };\r\n \r\n // Initial resize\r\n handleResize();\r\n \r\n // Watch for container size changes using ResizeObserver. This\r\n // already covers the window-resize case: when the window resizes,\r\n // the flex layout reshapes this container, and ResizeObserver\r\n // fires.\r\n const resizeObserver = new ResizeObserver(() => {\r\n handleResize();\r\n });\r\n resizeObserver.observe(container);\r\n resizeObserverRef.current = resizeObserver;\r\n\r\n // Audit Phase 1.E (F-18 / F-B6): the previous\r\n // `window.addEventListener('resize', handleResize)` here had no\r\n // matching removeEventListener — every BimViewer mount leaked a\r\n // listener (Phase 0 baseline measured ~+9 listeners/min during\r\n // active use). Removed entirely; the ResizeObserver above is\r\n // sufficient for the redraw case.\r\n }, []\r\n );\r\n\r\n React.useEffect(() => {\r\n createViewer();\r\n\r\n // Cleanup function to properly dispose of components when unmounting\r\n return () => {\r\n if (resizeObserverRef.current) {\r\n resizeObserverRef.current.disconnect();\r\n }\r\n if (bimComponents) {\r\n bimComponents.dispose();\r\n }\r\n bimDispatch({\r\n type: \"DISPOSE-BIM\"\r\n });\r\n };\r\n }, []);\r\n\r\n // Enforce Y-up coordinate system for Three.js / camera-controls.\r\n // Runs whenever the world (and its controls) becomes available, and resets on unmount.\r\n useBimCoordinateSystem(bimState.bim.world?.camera?.controls ?? null);\r\n\r\n // Control ViewportGizmo based on current viewer\r\n React.useEffect(() => {\r\n if (!bimComponents) return;\r\n\r\n const viewportGizmo = bimComponents.get(ViewportGizmo);\r\n\r\n viewportGizmo.setLabels({\r\n top: t('top'),\r\n right: t('right'),\r\n bottom: t('bottom'),\r\n left: t('left'),\r\n front: t('front'),\r\n back: t('back')\r\n });\r\n\r\n if (!viewportGizmo) return;\r\n\r\n if (currentViewer === 'bim') {\r\n viewportGizmo.enabled = true;\r\n viewportGizmo.add();\r\n } else {\r\n viewportGizmo.enabled = false;\r\n viewportGizmo.remove();\r\n }\r\n }, [bimComponents, currentViewer, locale, t]);\r\n\r\n return (\r\n <div\r\n style={{\r\n position: \"relative\",\r\n width: \"100%\",\r\n height: \"100%\",\r\n overflow: \"hidden\"\r\n }}\r\n >\r\n <BimLoadingState />\r\n <div\r\n className=\"bim-container\"\r\n id=\"bim-viewer-container\"\r\n ref={containerRef}\r\n style={{\r\n width: \"100%\",\r\n height: \"100%\",\r\n position: \"relative\",\r\n background: \"radial-gradient(circle, rgba(255, 255, 255, 1) 50%, rgba(220, 220, 220, 1) 100%)\",\r\n }}\r\n />\r\n <PropertiesMenu />\r\n </div>\r\n );\r\n}"],"mappings":";AA+NQ,SAQI,KARJ;AA7NR,YAAY,WAAW;AACvB,YAAY,SAAS;AACrB,YAAY,SAAS;AACrB,YAAY,WAAW;AACvB,SAAS,iBAAiB,iBAAiB;AAC3C,SAAS,cAAc,YAAY,oBAAoB;AAEvD,SAAS,oBAAoB;AAC7B,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAC5B,SAAS,qBAAqB;AAC9B,SAAS,sBAAsB;AAC/B,SAAS,2BAA2B;AAEpC,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB;AAChC,SAAS,qBAAqB;AAC9B,SAAS,8BAA8B;AAEhC,SAAS,YAAY;AArB5B;AAuBI,QAAM,IAAI,gBAAgB,eAAe;AACzC,QAAM,SAAS,UAAU;AAEzB,QAAM,EAAE,UAAU,aAAa,OAAO,SAAS,IAAI,MAAM,WAAW,UAAU;AAC9E,QAAM,EAAE,cAAc,IAAI,SAAS;AAEnC,QAAM,EAAE,UAAU,eAAe,OAAO,WAAW,IAAI,MAAM,WAAW,YAAY;AACpF,QAAM,EAAE,cAAc,IAAI,WAAW;AAErC,QAAM,EAAE,OAAO,WAAW,IAAI,MAAM,WAAW,YAAY;AAC3D,QAAM,EAAE,cAAc,IAAI,WAAW;AAGrC,QAAM,eAAe,MAAM,OAAuB,IAAI;AACtD,QAAM,eAAe,MAAM,OAAsB,IAAI;AACrD,QAAM,oBAAoB,MAAM,OAA8B,IAAI;AAElE,QAAM,eAAe,MAAM;AAAA,IACvB,YAAY;AACR,UAAI,CAAC,aAAa,WAAW,cAAe;AAE5C,YAAM,YAAY,aAAa;AAC/B,YAAM,aAAa,IAAI,IAAI,WAAW;AACtC,YAAM,SAAS,WAAW,IAAI,IAAI,MAAM;AACxC,YAAM,QAAQ,OAAO,OAInB;AAEF,YAAM,QAAQ,IAAI,IAAI,cAAc,UAAU;AAE9C,YAAM,WAAW,IAAI,IAAI,uBAAuB,YAAY,SAAS;AACrE,YAAM,SAAS,IAAI,IAAI,uBAAuB,UAAU;AAExD,iBAAW,KAAK;AAEhB,YAAM,MAAM,MAAM;AAClB,YAAM,MAAM,MAAM,aAAa;AAE/B,YAAM,QAAQ,WAAW,IAAI,IAAI,KAAK;AACtC,YAAM,OAAO,MAAM,OAAO,KAAK;AAE/B,UAAI,MAAM;AACN,oBAAY;AAAA,UACR,QAAQ;AAAA,UACR,WAAW,EAAE,KAAK;AAAA,QACtB,CAAC;AAAA,MACL;AAEA,YAAM,aAAa,IAAI,MAAM,WAAW,CAAC;AACzC,YAAM,MAAM,MAAM,IAAI,UAAU;AAEhC,YAAM,YAAY,WAAW,IAAI,IAAI,gBAAgB;AAErD,YAAM,YACF;AACJ,YAAM,aAAa,MAAM,MAAM,SAAS;AACxC,YAAM,aAAa,MAAM,WAAW,KAAK;AACzC,YAAM,aAAa,IAAI,KAAK,CAAC,UAAU,GAAG,cAAc;AAAA,QACpD,MAAM;AAAA,MACV,CAAC;AACD,YAAM,YAAY,IAAI,gBAAgB,UAAU;AAChD,mBAAa,UAAU;AACvB,gBAAU,KAAK,SAAS;AAExB,YAAM,OAAO,SAAS;AAAA,QAAiB;AAAA,QAAW,MAC9C,UAAU,KAAK,OAAO;AAAA,MAC1B;AAEA,YAAM,OAAO,SAAS,gBAAgB;AACtC,YAAM,OAAO,SAAS;AAAA,QAAiB;AAAA,QAAQ,MAC3C,UAAU,KAAK,OAAO,IAAI;AAAA,MAC9B;AAEA,iBAAW,IAAI,YAAY,EAAE,QAAQ;AACrC,iBAAW,IAAI,aAAa,EAAE,SAAS,MAAM;AAC7C,iBAAW,IAAI,WAAW;AAC1B,iBAAW,IAAI,mBAAmB;AAClC,iBAAW,IAAI,aAAa;AAC5B,iBAAW,IAAI,cAAc;AAG7B,UAAI,MAAM;AACN,mBAAW,IAAI,aAAa,EAAE,QAAQ,IAAI;AAC1C,mBAAW,IAAI,cAAc,EAAE,QAAQ,IAAI;AAAA,MAC/C;AAGA,YAAM,SAAS,MAAM,UAAU,UAAU;AACzC,YAAM,SAAS,MAAM,UAAU,OAAO,MAAM;AAC5C,YAAM,MAAM,MAAM;AAAA,QACd,SAAS;AAAA,UACL,SAAS;AAAA,UACT,YAAY;AAAA,QAChB;AAAA,MACJ,CAAC;AAED,YAAM,MAAM,iBAAiB,gBAAgB,IAAI,KAAK,KAAK;AAE3D,YAAM,MAAM,MAAM,cAAc;AAEhC,YAAM,OAAO,SAAS,iBAAiB,QAAQ,YAAY;AACvD,cAAM,MAAM,MAAM,cAAc;AAAA,MACpC,CAAC;AAED,YAAM,MAAM,MAAM,aAAa;AAE/B,kBAAY;AAAA,QACR,MAAM;AAAA,QACN,SAAS,EAAE,eAAe,YAAY,OAAO,UAAU;AAAA,MAC3D,CAAC;AAGD,YAAM,SAAS,UAAU,cAAc,QAAQ;AAC/C,UAAI,QAAQ;AACR,eAAO,MAAM,QAAQ;AACrB,eAAO,MAAM,SAAS;AACtB,eAAO,MAAM,UAAU;AAAA,MAC3B;AAGA,YAAM,eAAe,MAAM;AAjJvC,YAAAA;AAkJgB,cAAM,QAAQ,UAAU;AACxB,cAAM,SAAS,UAAU;AACzB,YAAI,SAAS,QAAQ;AACjB,WAAAA,MAAA,MAAM,aAAN,gBAAAA,IAAgB,OAAO,IAAI,MAAM,QAAQ,OAAO,MAAM;AAAA,QAC1D;AAAA,MACJ;AAGA,mBAAa;AAMb,YAAM,iBAAiB,IAAI,eAAe,MAAM;AAC5C,qBAAa;AAAA,MACjB,CAAC;AACD,qBAAe,QAAQ,SAAS;AAChC,wBAAkB,UAAU;AAAA,IAQhC;AAAA,IAAG,CAAC;AAAA,EACR;AAEA,QAAM,UAAU,MAAM;AAClB,iBAAa;AAGb,WAAO,MAAM;AACT,UAAI,kBAAkB,SAAS;AAC3B,0BAAkB,QAAQ,WAAW;AAAA,MACzC;AACA,UAAI,eAAe;AACf,sBAAc,QAAQ;AAAA,MAC1B;AACA,kBAAY;AAAA,QACR,MAAM;AAAA,MACV,CAAC;AAAA,IACL;AAAA,EACJ,GAAG,CAAC,CAAC;AAIL,0BAAuB,0BAAS,IAAI,UAAb,mBAAoB,WAApB,mBAA4B,aAA5B,YAAwC,IAAI;AAGnE,QAAM,UAAU,MAAM;AAClB,QAAI,CAAC,cAAe;AAEpB,UAAM,gBAAgB,cAAc,IAAI,aAAa;AAErD,kBAAc,UAAU;AAAA,MACpB,KAAK,EAAE,KAAK;AAAA,MACZ,OAAO,EAAE,OAAO;AAAA,MAChB,QAAQ,EAAE,QAAQ;AAAA,MAClB,MAAM,EAAE,MAAM;AAAA,MACd,OAAO,EAAE,OAAO;AAAA,MAChB,MAAM,EAAE,MAAM;AAAA,IAClB,CAAC;AAED,QAAI,CAAC,cAAe;AAEpB,QAAI,kBAAkB,OAAO;AACzB,oBAAc,UAAU;AACxB,oBAAc,IAAI;AAAA,IACtB,OAAO;AACH,oBAAc,UAAU;AACxB,oBAAc,OAAO;AAAA,IACzB;AAAA,EACJ,GAAG,CAAC,eAAe,eAAe,QAAQ,CAAC,CAAC;AAE5C,SACI;AAAA,IAAC;AAAA;AAAA,MACG,OAAO;AAAA,QACH,UAAU;AAAA,QACV,OAAO;AAAA,QACP,QAAQ;AAAA,QACR,UAAU;AAAA,MACd;AAAA,MAEA;AAAA,4BAAC,mBAAgB;AAAA,QACjB;AAAA,UAAC;AAAA;AAAA,YACG,WAAU;AAAA,YACV,IAAG;AAAA,YACH,KAAK;AAAA,YACL,OAAO;AAAA,cACH,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,UAAU;AAAA,cACV,YAAY;AAAA,YAChB;AAAA;AAAA,QACJ;AAAA,QACA,oBAAC,kBAAe;AAAA;AAAA;AAAA,EACpB;AAER;","names":["_a"]}
1
+ {"version":3,"sources":["../../../../../src/core/components/viewers/bim/BimViewer.tsx"],"sourcesContent":["\"use client\";\r\n\r\nimport * as React from \"react\";\r\nimport * as OBC from \"@thatopen/components\";\r\nimport * as OBF from \"@thatopen/components-front\"\r\nimport * as THREE from \"three\";\r\nimport { useTranslations, useLocale } from 'next-intl';\r\nimport { ToolsContext, BimContext, MenusContext } from \"../../../store\";\r\n\r\nimport { CurrentWorld } from \"./src/CurrentWorld\";\r\nimport { CurrentCamera } from './src/CurrentCamera';\r\nimport { Highlighter } from \"./src/Highlighter\";\r\nimport { FloorplanTool } from \"./src/FloorplanTool\";\r\nimport { ElevationsTool } from \"./src/ElevationsTool\";\r\nimport { ViewModeCoordinator } from \"./src/lib/ViewModeCoordinator\";\r\n\r\nimport { PropertiesMenu } from \"./src/propertiesMenu\";\r\nimport { BimLoadingState } from \"./src/BimLoadingState\";\r\nimport { ViewportGizmo } from \"./src/ViewportGizmo\";\r\nimport { useBimCoordinateSystem } from \"../useCoordinateSystem\";\r\n\r\nexport function BimViewer() {\r\n\r\n const t = useTranslations('ViewportGizmo');\r\n const locale = useLocale();\r\n\r\n const { dispatch: bimDispatch, state: bimState } = React.useContext(BimContext);\r\n const { bimComponents } = bimState.bim;\r\n\r\n const { dispatch: toolsDispatch, state: toolsState } = React.useContext(ToolsContext);\r\n const { currentToolId } = toolsState.tools;\r\n\r\n const { state: menusState } = React.useContext(MenusContext);\r\n const { currentViewer } = menusState.menus;\r\n \r\n\r\n const containerRef = React.useRef<HTMLDivElement>(null);\r\n const workerUrlRef = React.useRef<string | null>(null);\r\n const resizeObserverRef = React.useRef<ResizeObserver | null>(null);\r\n // Tracks the Components instance THIS mount created, so cleanup disposes the\r\n // real one and the create-guard can't be defeated by a stale [] closure.\r\n const componentsRef = React.useRef<OBC.Components | null>(null);\r\n\r\n const createViewer = React.useCallback(\r\n async (isCancelled: () => boolean) => {\r\n // Re-entrancy guard keyed to the ref we actually set — NOT the stale\r\n // `bimComponents` from this useCallback's [] closure (always null on\r\n // first run, so it could never stop a second init). Without this,\r\n // React StrictMode (dev) and rapid viewer remounts (prod) build a\r\n // second Components + PostproductionRenderer — a second <canvas> —\r\n // and whichever instance wins the SET_COMPONENTS race may be the one\r\n // whose canvas was detached on remount. Models then load into a scene\r\n // that is never painted: the spatial tree builds (metadata) but no\r\n // geometry shows and floorplan nav drives the dead world's camera.\r\n if (!containerRef.current || componentsRef.current) return;\r\n\r\n const container = containerRef.current;\r\n const components = new OBC.Components();\r\n const worlds = components.get(OBC.Worlds);\r\n const world = worlds.create<\r\n OBC.ShadowedScene,\r\n OBC.OrthoPerspectiveCamera,\r\n OBF.PostproductionRenderer\r\n >();\r\n\r\n world.scene = new OBC.ShadowedScene(components);\r\n\r\n world.renderer = new OBF.PostproductionRenderer(components, container);\r\n world.camera = new OBC.OrthoPerspectiveCamera(components);\r\n\r\n components.init();\r\n\r\n world.scene.setup();\r\n world.scene.three.background = null;\r\n\r\n const grids = components.get(OBC.Grids);\r\n const grid = grids.create(world);\r\n\r\n if (grid) {\r\n bimDispatch({\r\n \"type\": \"SET_GRID\",\r\n \"payload\": { grid }\r\n });\r\n }\r\n\r\n const axesHelper = new THREE.AxesHelper(5);\r\n world.scene.three.add(axesHelper);\r\n\r\n const fragments = components.get(OBC.FragmentsManager);\r\n\r\n const githubUrl =\r\n \"https://thatopen.github.io/engine_fragment/resources/worker.mjs\";\r\n const fetchedUrl = await fetch(githubUrl);\r\n const workerBlob = await fetchedUrl.blob();\r\n const workerFile = new File([workerBlob], \"worker.mjs\", {\r\n type: \"text/javascript\",\r\n });\r\n const workerUrl = URL.createObjectURL(workerFile);\r\n workerUrlRef.current = workerUrl; // Store reference for cleanup\r\n fragments.init(workerUrl);\r\n\r\n world.camera.controls.addEventListener(\"control\", () =>\r\n fragments.core.update(),\r\n );\r\n\r\n world.camera.controls.restThreshold = 0.005;\r\n world.camera.controls.addEventListener(\"rest\", () =>\r\n fragments.core.update(true)\r\n );\r\n\r\n components.get(CurrentWorld).world = world;\r\n components.get(CurrentCamera).camera = world.camera;\r\n components.get(Highlighter);\r\n components.get(ViewModeCoordinator);\r\n components.get(FloorplanTool);\r\n components.get(ElevationsTool);\r\n\r\n // Grid injection is safe here — fragments.core is initialized.\r\n if (grid) {\r\n components.get(FloorplanTool).setGrid(grid);\r\n components.get(ElevationsTool).setGrid(grid);\r\n }\r\n\r\n // Enable shadows\r\n world.renderer.three.shadowMap.enabled = true;\r\n world.renderer.three.shadowMap.type = THREE.PCFSoftShadowMap;\r\n world.scene.setup({\r\n shadows: {\r\n cascade: 1,\r\n resolution: 1024,\r\n },\r\n });\r\n\r\n world.scene.distanceRenderer.excludedObjects.add(grid.three);\r\n\r\n await world.scene.updateShadows();\r\n\r\n world.camera.controls.addEventListener(\"rest\", async () => {\r\n await world.scene.updateShadows();\r\n });\r\n\r\n world.scene.three.background = null;\r\n\r\n // If this init was superseded (StrictMode re-run) or the viewer\r\n // unmounted while we awaited the worker fetch / shadow update, throw\r\n // this instance away instead of publishing it. Prevents an orphaned\r\n // world (whose canvas is detached) from winning the store and starving\r\n // the visible canvas of geometry.\r\n if (isCancelled()) {\r\n components.dispose();\r\n return;\r\n }\r\n componentsRef.current = components;\r\n bimDispatch({\r\n type: \"SET_COMPONENTS\",\r\n payload: { bimComponents: components, world, fragments }\r\n });\r\n\r\n // Ensure canvas takes full container size\r\n const canvas = container.querySelector('canvas');\r\n if (canvas) {\r\n canvas.style.width = '100%';\r\n canvas.style.height = '100%';\r\n canvas.style.display = 'block';\r\n }\r\n\r\n // Handle resize using container dimensions\r\n const handleResize = () => {\r\n const width = container.clientWidth;\r\n const height = container.clientHeight;\r\n if (width && height) {\r\n world.renderer?.resize(new THREE.Vector2(width, height));\r\n }\r\n };\r\n \r\n // Initial resize\r\n handleResize();\r\n \r\n // Watch for container size changes using ResizeObserver. This\r\n // already covers the window-resize case: when the window resizes,\r\n // the flex layout reshapes this container, and ResizeObserver\r\n // fires.\r\n const resizeObserver = new ResizeObserver(() => {\r\n handleResize();\r\n });\r\n resizeObserver.observe(container);\r\n resizeObserverRef.current = resizeObserver;\r\n\r\n // The ResizeObserver above is sufficient for redraws. A window\r\n // 'resize' listener here previously leaked on every mount (no matching\r\n // removeEventListener), so it was removed.\r\n }, []\r\n );\r\n\r\n React.useEffect(() => {\r\n let cancelled = false;\r\n createViewer(() => cancelled);\r\n\r\n // Cleanup: mark this init cancelled (so an in-flight createViewer disposes\r\n // itself instead of publishing), and dispose the instance we actually\r\n // created (componentsRef). The old `if (bimComponents)` read the stale []\r\n // closure value (null at mount), so the real Components was never disposed\r\n // — leaking its renderer/canvas and letting orphans race the store.\r\n return () => {\r\n cancelled = true;\r\n if (resizeObserverRef.current) {\r\n resizeObserverRef.current.disconnect();\r\n }\r\n if (componentsRef.current) {\r\n componentsRef.current.dispose();\r\n componentsRef.current = null;\r\n }\r\n bimDispatch({\r\n type: \"DISPOSE-BIM\"\r\n });\r\n };\r\n }, []);\r\n\r\n // Enforce Y-up coordinate system for Three.js / camera-controls.\r\n // Runs whenever the world (and its controls) becomes available, and resets on unmount.\r\n useBimCoordinateSystem(bimState.bim.world?.camera?.controls ?? null);\r\n\r\n // Control ViewportGizmo based on current viewer\r\n React.useEffect(() => {\r\n if (!bimComponents) return;\r\n\r\n const viewportGizmo = bimComponents.get(ViewportGizmo);\r\n\r\n viewportGizmo.setLabels({\r\n top: t('top'),\r\n right: t('right'),\r\n bottom: t('bottom'),\r\n left: t('left'),\r\n front: t('front'),\r\n back: t('back')\r\n });\r\n\r\n if (!viewportGizmo) return;\r\n\r\n if (currentViewer === 'bim') {\r\n viewportGizmo.enabled = true;\r\n viewportGizmo.add();\r\n } else {\r\n viewportGizmo.enabled = false;\r\n viewportGizmo.remove();\r\n }\r\n }, [bimComponents, currentViewer, locale, t]);\r\n\r\n return (\r\n <div\r\n style={{\r\n position: \"relative\",\r\n width: \"100%\",\r\n height: \"100%\",\r\n overflow: \"hidden\"\r\n }}\r\n >\r\n <BimLoadingState />\r\n <div\r\n className=\"bim-container\"\r\n id=\"bim-viewer-container\"\r\n ref={containerRef}\r\n style={{\r\n width: \"100%\",\r\n height: \"100%\",\r\n position: \"relative\",\r\n background: \"radial-gradient(circle, rgba(255, 255, 255, 1) 50%, rgba(220, 220, 220, 1) 100%)\",\r\n }}\r\n />\r\n <PropertiesMenu />\r\n </div>\r\n );\r\n}"],"mappings":"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","names":["_a"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/bim/src/BimLoadingState/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAiBzB,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,YAAY,GAAG,YAAY,CAAA;AAEpG,wBAAgB,eAAe,sBA2Z9B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/bim/src/BimLoadingState/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,OAAO,CAAA;AAiBzB,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,OAAO,GAAG,YAAY,GAAG,YAAY,CAAA;AAEpG,wBAAgB,eAAe,sBAoa9B"}
@@ -136,9 +136,11 @@ function BimLoadingState() {
136
136
  const loadModels = bimComponents.get(LoadModels);
137
137
  const { sharing } = setCameraLookAt(world, searchParams);
138
138
  loadModels.sharing = sharing;
139
+ let loadedCount = 0;
139
140
  for (const bimFile of bimFiles) {
140
141
  try {
141
142
  await loadModels.load(bimFile.url, bimFile.name);
143
+ loadedCount++;
142
144
  if ((bimFile.x != null || bimFile.y != null || bimFile.z != null) && fragments) {
143
145
  const fragModel = fragments.core.models.list.get(bimFile.name);
144
146
  if (fragModel) {
@@ -154,6 +156,10 @@ function BimLoadingState() {
154
156
  if (fragments) {
155
157
  fragments.core.update(true);
156
158
  }
159
+ if (loadedCount === 0) {
160
+ setCurrentState("error");
161
+ return;
162
+ }
157
163
  for (const bimFile of bimFiles) {
158
164
  bimDispatch({ type: "SET_MODEL_UI_STATE", payload: { fileId: bimFile.id, isVisible: true } });
159
165
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../src/core/components/viewers/bim/src/BimLoadingState/index.tsx"],"sourcesContent":["'use client'\r\n\r\nimport React from 'react'\r\nimport { Button } from '../../../../ui/Button'\r\nimport { Card, CardContent, CardHeader } from '../../../../ui/Card'\r\nimport { Input } from '../../../../ui/Input'\r\nimport { LoadingSpinner } from '../../../../ui/LoadingSpinner'\r\nimport { Upload, Box, Building2, Search, X, SquareArrowOutUpRight } from 'lucide-react'\r\nimport { BimContext, BuildingsContext, usePermissions } from '../../../../../store'\r\nimport { LoadModels } from '../LoadModels'\r\nimport { useTranslations } from 'next-intl'\r\nimport { useFilesByBuildingId, useUploadFileToBuilding } from '../../../../../hooks/files/files'\r\nimport { useFileUploadHandler } from '../../../../ui/FilesManager/src/useFileUploadHandler'\r\nimport type { DbFile as DbFile } from '../../../../../types/dbTypes'\r\nimport { cn } from '../../../../../utils/utils'\r\nimport { useSearchParams, useRouter } from 'next/navigation'\r\nimport { useBuilding, useBuildings } from '../../../../../hooks/buildings/buildings'\r\nimport { setCameraLookAt } from '../../utils/setCameraLookAt'\r\n\r\nexport type bimViewerState = 'opening' | 'loading' | 'ready' | 'error' | 'noBimFiles' | 'noBuilding'\r\n\r\nexport function BimLoadingState() {\r\n const t = useTranslations('BimLoadingState')\r\n // Permissions\r\n const { ability } = usePermissions()\r\n\r\n const { state: bimState, dispatch: bimDispatch } = React.useContext(BimContext)\r\n const { bimComponents, world, fragments } = bimState.bim\r\n const { state: buildingState, dispatch: buildingDispatch } = React.useContext(BuildingsContext)\r\n const { building: storeBuilding } = buildingState.buildings\r\n\r\n const searchParams = useSearchParams()\r\n const buildingId = searchParams.get(\"buildingId\")\r\n const { building: urlBuilding, isLoading: buildingLoading, isError: buildingError } = useBuilding(buildingId ? Number(buildingId) : null)\r\n const { buildings, isLoading: buildingsLoading } = useBuildings()\r\n\r\n // Determine the current building to use\r\n const building = storeBuilding || urlBuilding\r\n\r\n React.useEffect(() => {\r\n if (!storeBuilding && urlBuilding ) {\r\n buildingDispatch({ type: \"SET-CURRENT-BUILDING\", payload: { building: urlBuilding } })\r\n }\r\n }, [urlBuilding, storeBuilding, buildingDispatch])\r\n\r\n const router = useRouter()\r\n const fileInputRef = React.useRef<HTMLInputElement>(null)\r\n\r\n // Upload file hooks\r\n const { uploadFile } = useUploadFileToBuilding(building?.id)\r\n\r\n // Use the reusable upload handler\r\n const { handleFileUpload } = useFileUploadHandler({\r\n buildingId: building?.id,\r\n tag: 'bim-file',\r\n isVisible: true,\r\n uploadFile,\r\n })\r\n\r\n const [currentState, setCurrentState] = React.useState<bimViewerState>('opening')\r\n const [hasLoadedModels, setHasLoadedModels] = React.useState(false)\r\n const [cameraHasMoved, setCameraHasMoved] = React.useState(false)\r\n const isLoadingModelsRef = React.useRef(false)\r\n const [searchTerm, setSearchTerm] = React.useState('')\r\n const [searchResults, setSearchResults] = React.useState<any[]>([])\r\n const [selectedBuilding, setSelectedBuilding] = React.useState<any>(null)\r\n \r\n const { files, isLoading: filesLoading } = useFilesByBuildingId(building?.id)\r\n const bimFiles: DbFile[] = React.useMemo(() => (\r\n files.filter(file => {\r\n const ext = file?.extension?.toLowerCase()\r\n return ext === 'frag' || ext === 'ifc'\r\n })\r\n ), [files])\r\n\r\n // Fuzzy search function for buildings\r\n const fuzzySearchBuildings = React.useCallback((buildings: any[], searchTerm: string) => {\r\n if (!searchTerm.trim()) return buildings.slice(0, 10)\r\n \r\n const fuzzySearchScore = (search: string, text: string): number => {\r\n if (!search || !text) return 0\r\n const searchLower = search.toLowerCase()\r\n const textLower = text.toLowerCase()\r\n \r\n // Exact match gets highest score\r\n if (textLower === searchLower) return 1000\r\n // Starts with search term gets high score\r\n if (textLower.startsWith(searchLower)) return 800\r\n // Contains search term gets medium score\r\n if (textLower.includes(searchLower)) return 600\r\n \r\n return 0\r\n }\r\n\r\n return buildings\r\n .map((building) => {\r\n const address = building.buildingAddress || ''\r\n const name = building.buildingName || ''\r\n const id = building.id.toString()\r\n \r\n const addressScore = fuzzySearchScore(searchTerm, address)\r\n const nameScore = fuzzySearchScore(searchTerm, name)\r\n const idScore = fuzzySearchScore(searchTerm, id)\r\n \r\n const maxScore = Math.max(addressScore, nameScore, idScore)\r\n return { ...building, searchScore: maxScore }\r\n })\r\n .filter(building => building.searchScore > 0)\r\n .sort((a, b) => b.searchScore - a.searchScore)\r\n .slice(0, 10)\r\n }, [])\r\n\r\n // Handle search\r\n const handleSearch = React.useCallback((term: string) => {\r\n setSearchTerm(term)\r\n if (buildings) {\r\n setSearchResults(fuzzySearchBuildings(buildings, term))\r\n }\r\n }, [buildings, fuzzySearchBuildings])\r\n\r\n const shouldShow = (currentState === 'opening' || currentState === 'noBimFiles' || currentState === 'loading' || currentState === 'noBuilding') && !cameraHasMoved\r\n\r\n // Once models have loaded, start a fallback timer to dismiss the card if camera doesn't move\r\n React.useEffect(() => {\r\n if (currentState === 'loading' && hasLoadedModels) {\r\n const fallbackTimer = setTimeout(() => {\r\n setCameraHasMoved(true)\r\n setCurrentState('ready')\r\n }, 5000)\r\n\r\n return () => clearTimeout(fallbackTimer)\r\n }\r\n }, [currentState, hasLoadedModels])\r\n\r\n // Set up camera movement detection\r\n React.useEffect(() => {\r\n if (bimState.bim.world?.camera?.controls) {\r\n const controls = bimState.bim.world.camera.controls\r\n\r\n const handleCameraChange = () => {\r\n setCameraHasMoved(true)\r\n if (hasLoadedModels) {\r\n setCurrentState('ready')\r\n }\r\n }\r\n\r\n // Listen for camera control event (when user moves the camera)\r\n controls.addEventListener('control', handleCameraChange)\r\n\r\n return () => {\r\n controls.removeEventListener('control', handleCameraChange)\r\n }\r\n }\r\n }, [bimState.bim.world, hasLoadedModels])\r\n\r\n const loadBimModels = React.useCallback(async () => {\r\n if (!bimComponents || bimFiles.length === 0) return\r\n if (isLoadingModelsRef.current) return\r\n\r\n isLoadingModelsRef.current = true\r\n\r\n try {\r\n // State should already be 'loading' when this is called\r\n const loadModels = bimComponents.get(LoadModels)\r\n\r\n const {sharing} = setCameraLookAt(world, searchParams)\r\n loadModels.sharing = sharing\r\n\r\n for (const bimFile of bimFiles) {\r\n try {\r\n await loadModels.load(bimFile.url, bimFile.name)\r\n // Apply saved 3D position after load (setupModel resets to origin)\r\n if ((bimFile.x != null || bimFile.y != null || bimFile.z != null) && fragments) {\r\n const fragModel = fragments.core.models.list.get(bimFile.name)\r\n if (fragModel) {\r\n fragModel.object.position.set(bimFile.x ?? 0, bimFile.y ?? 0, bimFile.z ?? 0)\r\n if (bimFile.rotation != null) fragModel.object.rotation.y = bimFile.rotation\r\n fragModel.object.updateMatrixWorld(true)\r\n }\r\n }\r\n } catch (e) {\r\n console.error(\"Error loading BIM file\", bimFile.name, e)\r\n }\r\n }\r\n\r\n // Force update the fragments to render geometry immediately\r\n if (fragments) {\r\n fragments.core.update(true)\r\n }\r\n\r\n // Mark each loaded file as visible in the BIM store so ModelsSection reflects it\r\n for (const bimFile of bimFiles) {\r\n bimDispatch({ type: 'SET_MODEL_UI_STATE', payload: { fileId: bimFile.id, isVisible: true } })\r\n }\r\n\r\n // Signal that models have loaded — the fallback timer will dismiss the card\r\n setHasLoadedModels(true)\r\n } catch (error) {\r\n console.error('Error loading BIM models:', error)\r\n setCurrentState('error')\r\n } finally {\r\n isLoadingModelsRef.current = false\r\n }\r\n }, [bimComponents, bimFiles, fragments])\r\n\r\n // Handle initial state transitions\r\n React.useEffect(() => {\r\n // If no bimComponents available, stay in opening state\r\n if (!bimComponents) {\r\n setCurrentState('opening')\r\n setHasLoadedModels(false)\r\n return\r\n }\r\n\r\n // If building is loading, stay in opening state\r\n if (buildingLoading) {\r\n setCurrentState('opening')\r\n return\r\n }\r\n\r\n // If building failed to load or no buildingId provided, show noBuilding state\r\n if (buildingError || (!buildingId && !building)) {\r\n setCurrentState('noBuilding')\r\n setHasLoadedModels(false)\r\n return\r\n }\r\n\r\n // If we have a building but files are still loading, stay in opening state\r\n if (building && filesLoading) {\r\n setCurrentState('opening')\r\n return\r\n }\r\n\r\n // If we've already loaded models (or are currently loading), don't reload\r\n if (hasLoadedModels) {\r\n return\r\n }\r\n\r\n // If we have a building but no BIM files, show noBimFiles state\r\n if (building && bimFiles.length === 0) {\r\n setCurrentState('noBimFiles')\r\n return\r\n }\r\n\r\n // We have BIM files, set to loading and start loading them\r\n if (building && bimFiles.length > 0) {\r\n setCurrentState('loading')\r\n setCameraHasMoved(false) // Reset camera moved state for new model\r\n loadBimModels()\r\n }\r\n }, [bimComponents, building, buildingLoading, buildingError, buildingId, filesLoading, bimFiles.length, loadBimModels, hasLoadedModels])\r\n\r\n // Don't render if not visible\r\n if (!shouldShow) {\r\n return null\r\n }\r\n\r\n const handleUploadClick = () => {\r\n fileInputRef.current?.click()\r\n }\r\n\r\n const handleBuildingSelect = (building: any) => {\r\n const url = new URL(window.location.href)\r\n url.searchParams.set('buildingId', building.id.toString())\r\n buildingDispatch({ type: 'SET-CURRENT-BUILDING', payload: { building } })\r\n setSelectedBuilding(building)\r\n setSearchTerm('')\r\n setSearchResults([])\r\n router.push(url.toString())\r\n }\r\n\r\n const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {\r\n const files = event.target.files\r\n if (!files || files.length === 0) return\r\n\r\n const file = files[0]\r\n\r\n try {\r\n const modelId = file.name\r\n setCurrentState('loading')\r\n setCameraHasMoved(false) // Reset camera moved state for new upload\r\n await handleFileUpload(file)\r\n\r\n window.dispatchEvent(new CustomEvent('bim-model-loaded-from-file', { detail: { modelId } }))\r\n bimDispatch({\r\n type: 'SET_MODEL', payload: { modelId },\r\n })\r\n setCurrentState('ready')\r\n }\r\n catch (error) {\r\n console.error('Error uploading file:', error)\r\n setCurrentState('error')\r\n }\r\n }\r\n\r\n return (\r\n <>\r\n <div className=\"absolute z-10 inset-0 bg-background/50 backdrop-blur-[1px] flex items-center justify-center pointer-events-none\">\r\n <Card className={cn(\"w-[536px] pointer-events-auto flex flex-col justify-start items-center gap-2\")}>\r\n <CardHeader className=\"flex justify-center items-center\">\r\n <div className=\"w-12 h-12 p-2 bg-card rounded-md shadow-sm border border-border flex justify-center items-center\">\r\n {currentState === 'noBuilding' ? (\r\n <Building2 className={cn(\"w-4 h-5 text-foreground\", buildingsLoading && \"animate-pulse\")} strokeWidth={2} />\r\n ) : (\r\n <Box className={cn(\"w-4 h-5 text-foreground\", currentState === 'opening' && \"animate-pulse\")} strokeWidth={2} />\r\n )}\r\n </div>\r\n </CardHeader>\r\n\r\n <CardContent className=\"self-stretch flex flex-col justify-start items-center gap-6 pt-0\">\r\n <div className=\"self-stretch flex flex-col justify-start items-center gap-2\">\r\n <div className=\"self-stretch text-center text-foreground text-xl font-semibold font-['Inter'] leading-7 flex items-center justify-center gap-2\">\r\n {currentState === 'opening' ? (\r\n <>\r\n {t('openingText')}\r\n <LoadingSpinner size={20} />\r\n </>\r\n ) : currentState === 'loading' ? (\r\n <>\r\n {t('loadingBimModel')}\r\n <LoadingSpinner size={20} />\r\n </>\r\n ) : currentState === 'noBuilding' ? (\r\n <>\r\n {t('noBuilding')}\r\n </>\r\n ) : (\r\n t('noBIMLoaded')\r\n )}\r\n </div>\r\n {(currentState === 'noBimFiles' || currentState === 'noBuilding') && (\r\n <div className=\"self-stretch text-center text-muted-foreground text-sm font-normal font-['Inter'] leading-tight\">\r\n {currentState === 'noBuilding' ? t('selectBuildingHelpText') : t('helpText')}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {currentState === 'noBuilding' && (\r\n <div className=\"self-stretch flex flex-col gap-3 justify-centre items-center\">\r\n {buildingsLoading ? (\r\n <div className=\"flex items-center justify-center gap-2 text-muted-foreground\">\r\n <LoadingSpinner size={16} />\r\n <span>{t('loadingBuildings') || 'Loading buildings...'}</span>\r\n </div>\r\n ) : buildings && buildings.length > 0 ? (\r\n <div className=\"w-full relative\">\r\n {selectedBuilding ? (\r\n <div className=\"relative flex justify-end items-center\">\r\n <Input\r\n type=\"text\"\r\n value={\r\n 'Building: '\r\n + (selectedBuilding.buildingName && selectedBuilding.buildingAddress\r\n ? `${selectedBuilding.buildingName}, ${selectedBuilding.buildingAddress}`\r\n : selectedBuilding.buildingName || selectedBuilding.buildingAddress || `Building ${selectedBuilding.id}`)\r\n }\r\n readOnly\r\n className=\"w-full\"\r\n />\r\n <X \r\n className=\"absolute right-2 cursor-pointer w-4 h-4 text-muted-foreground hover:text-foreground\" \r\n onClick={() => {\r\n setSelectedBuilding(null)\r\n setSearchTerm('')\r\n setSearchResults([])\r\n }} \r\n />\r\n </div>\r\n ) : (\r\n <div className=\"relative\">\r\n <Search className=\"absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground w-4 h-4\" />\r\n <Input\r\n placeholder={t('searchBuildings') || 'Search buildings...'}\r\n value={searchTerm}\r\n onChange={(e) => handleSearch(e.target.value)}\r\n className=\"w-full pl-10\"\r\n disabled={!ability.can('read', 'Building')}\r\n />\r\n </div>\r\n )}\r\n \r\n {/* Search results dropdown */}\r\n {searchResults.length > 0 && searchTerm !== '' && !selectedBuilding && (\r\n <div className=\"absolute top-full left-0 right-0 mt-1 bg-background border border-border rounded-md shadow-lg max-h-60 overflow-y-auto z-20\">\r\n {searchResults.map(building => (\r\n <div\r\n key={building.id}\r\n className=\"px-3 py-2 text-sm cursor-pointer hover:bg-muted transition-colors flex gap-2 items-center\"\r\n onClick={() => handleBuildingSelect(building)}\r\n >\r\n <SquareArrowOutUpRight className=\"w-3 h-3\" />\r\n {building.buildingName\r\n ? `${building.buildingName}, ${building.buildingAddress}`\r\n : building.buildingAddress || `Building ${building.id}`}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n ) : (\r\n <div className=\"text-muted-foreground text-center\">\r\n {t('noBuildings') || 'No buildings available'}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {currentState === 'noBimFiles' && (\r\n <div className=\"self-stretch flex justify-center items-center gap-3\">\r\n <Input\r\n ref={fileInputRef}\r\n type=\"file\"\r\n accept=\".ifc,.frag\"\r\n onChange={handleFileChange}\r\n className=\"hidden\"\r\n />\r\n <Button\r\n onClick={handleUploadClick}\r\n size=\"sm\"\r\n className=\"gap-2\"\r\n disabled={!ability.can('create', 'File')}\r\n >\r\n <Upload className=\"w-4 h-4\" />\r\n {t('uploadButton')}\r\n </Button>\r\n </div>\r\n )}\r\n </CardContent>\r\n </Card>\r\n </div>\r\n </>\r\n )\r\n}\r\n"],"mappings":"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","names":["buildings","searchTerm","building","files"]}
1
+ {"version":3,"sources":["../../../../../../../src/core/components/viewers/bim/src/BimLoadingState/index.tsx"],"sourcesContent":["'use client'\r\n\r\nimport React from 'react'\r\nimport { Button } from '../../../../ui/Button'\r\nimport { Card, CardContent, CardHeader } from '../../../../ui/Card'\r\nimport { Input } from '../../../../ui/Input'\r\nimport { LoadingSpinner } from '../../../../ui/LoadingSpinner'\r\nimport { Upload, Box, Building2, Search, X, SquareArrowOutUpRight } from 'lucide-react'\r\nimport { BimContext, BuildingsContext, usePermissions } from '../../../../../store'\r\nimport { LoadModels } from '../LoadModels'\r\nimport { useTranslations } from 'next-intl'\r\nimport { useFilesByBuildingId, useUploadFileToBuilding } from '../../../../../hooks/files/files'\r\nimport { useFileUploadHandler } from '../../../../ui/FilesManager/src/useFileUploadHandler'\r\nimport type { DbFile as DbFile } from '../../../../../types/dbTypes'\r\nimport { cn } from '../../../../../utils/utils'\r\nimport { useSearchParams, useRouter } from 'next/navigation'\r\nimport { useBuilding, useBuildings } from '../../../../../hooks/buildings/buildings'\r\nimport { setCameraLookAt } from '../../utils/setCameraLookAt'\r\n\r\nexport type bimViewerState = 'opening' | 'loading' | 'ready' | 'error' | 'noBimFiles' | 'noBuilding'\r\n\r\nexport function BimLoadingState() {\r\n const t = useTranslations('BimLoadingState')\r\n // Permissions\r\n const { ability } = usePermissions()\r\n\r\n const { state: bimState, dispatch: bimDispatch } = React.useContext(BimContext)\r\n const { bimComponents, world, fragments } = bimState.bim\r\n const { state: buildingState, dispatch: buildingDispatch } = React.useContext(BuildingsContext)\r\n const { building: storeBuilding } = buildingState.buildings\r\n\r\n const searchParams = useSearchParams()\r\n const buildingId = searchParams.get(\"buildingId\")\r\n const { building: urlBuilding, isLoading: buildingLoading, isError: buildingError } = useBuilding(buildingId ? Number(buildingId) : null)\r\n const { buildings, isLoading: buildingsLoading } = useBuildings()\r\n\r\n // Determine the current building to use\r\n const building = storeBuilding || urlBuilding\r\n\r\n React.useEffect(() => {\r\n if (!storeBuilding && urlBuilding ) {\r\n buildingDispatch({ type: \"SET-CURRENT-BUILDING\", payload: { building: urlBuilding } })\r\n }\r\n }, [urlBuilding, storeBuilding, buildingDispatch])\r\n\r\n const router = useRouter()\r\n const fileInputRef = React.useRef<HTMLInputElement>(null)\r\n\r\n // Upload file hooks\r\n const { uploadFile } = useUploadFileToBuilding(building?.id)\r\n\r\n // Use the reusable upload handler\r\n const { handleFileUpload } = useFileUploadHandler({\r\n buildingId: building?.id,\r\n tag: 'bim-file',\r\n isVisible: true,\r\n uploadFile,\r\n })\r\n\r\n const [currentState, setCurrentState] = React.useState<bimViewerState>('opening')\r\n const [hasLoadedModels, setHasLoadedModels] = React.useState(false)\r\n const [cameraHasMoved, setCameraHasMoved] = React.useState(false)\r\n const isLoadingModelsRef = React.useRef(false)\r\n const [searchTerm, setSearchTerm] = React.useState('')\r\n const [searchResults, setSearchResults] = React.useState<any[]>([])\r\n const [selectedBuilding, setSelectedBuilding] = React.useState<any>(null)\r\n \r\n const { files, isLoading: filesLoading } = useFilesByBuildingId(building?.id)\r\n const bimFiles: DbFile[] = React.useMemo(() => (\r\n files.filter(file => {\r\n const ext = file?.extension?.toLowerCase()\r\n return ext === 'frag' || ext === 'ifc'\r\n })\r\n ), [files])\r\n\r\n // Fuzzy search function for buildings\r\n const fuzzySearchBuildings = React.useCallback((buildings: any[], searchTerm: string) => {\r\n if (!searchTerm.trim()) return buildings.slice(0, 10)\r\n \r\n const fuzzySearchScore = (search: string, text: string): number => {\r\n if (!search || !text) return 0\r\n const searchLower = search.toLowerCase()\r\n const textLower = text.toLowerCase()\r\n \r\n // Exact match gets highest score\r\n if (textLower === searchLower) return 1000\r\n // Starts with search term gets high score\r\n if (textLower.startsWith(searchLower)) return 800\r\n // Contains search term gets medium score\r\n if (textLower.includes(searchLower)) return 600\r\n \r\n return 0\r\n }\r\n\r\n return buildings\r\n .map((building) => {\r\n const address = building.buildingAddress || ''\r\n const name = building.buildingName || ''\r\n const id = building.id.toString()\r\n \r\n const addressScore = fuzzySearchScore(searchTerm, address)\r\n const nameScore = fuzzySearchScore(searchTerm, name)\r\n const idScore = fuzzySearchScore(searchTerm, id)\r\n \r\n const maxScore = Math.max(addressScore, nameScore, idScore)\r\n return { ...building, searchScore: maxScore }\r\n })\r\n .filter(building => building.searchScore > 0)\r\n .sort((a, b) => b.searchScore - a.searchScore)\r\n .slice(0, 10)\r\n }, [])\r\n\r\n // Handle search\r\n const handleSearch = React.useCallback((term: string) => {\r\n setSearchTerm(term)\r\n if (buildings) {\r\n setSearchResults(fuzzySearchBuildings(buildings, term))\r\n }\r\n }, [buildings, fuzzySearchBuildings])\r\n\r\n const shouldShow = (currentState === 'opening' || currentState === 'noBimFiles' || currentState === 'loading' || currentState === 'noBuilding') && !cameraHasMoved\r\n\r\n // Once models have loaded, start a fallback timer to dismiss the card if camera doesn't move\r\n React.useEffect(() => {\r\n if (currentState === 'loading' && hasLoadedModels) {\r\n const fallbackTimer = setTimeout(() => {\r\n setCameraHasMoved(true)\r\n setCurrentState('ready')\r\n }, 5000)\r\n\r\n return () => clearTimeout(fallbackTimer)\r\n }\r\n }, [currentState, hasLoadedModels])\r\n\r\n // Set up camera movement detection\r\n React.useEffect(() => {\r\n if (bimState.bim.world?.camera?.controls) {\r\n const controls = bimState.bim.world.camera.controls\r\n\r\n const handleCameraChange = () => {\r\n setCameraHasMoved(true)\r\n if (hasLoadedModels) {\r\n setCurrentState('ready')\r\n }\r\n }\r\n\r\n // Listen for camera control event (when user moves the camera)\r\n controls.addEventListener('control', handleCameraChange)\r\n\r\n return () => {\r\n controls.removeEventListener('control', handleCameraChange)\r\n }\r\n }\r\n }, [bimState.bim.world, hasLoadedModels])\r\n\r\n const loadBimModels = React.useCallback(async () => {\r\n if (!bimComponents || bimFiles.length === 0) return\r\n if (isLoadingModelsRef.current) return\r\n\r\n isLoadingModelsRef.current = true\r\n\r\n try {\r\n // State should already be 'loading' when this is called\r\n const loadModels = bimComponents.get(LoadModels)\r\n\r\n const {sharing} = setCameraLookAt(world, searchParams)\r\n loadModels.sharing = sharing\r\n\r\n let loadedCount = 0\r\n for (const bimFile of bimFiles) {\r\n try {\r\n await loadModels.load(bimFile.url, bimFile.name)\r\n loadedCount++\r\n // Apply saved 3D position after load (setupModel resets to origin)\r\n if ((bimFile.x != null || bimFile.y != null || bimFile.z != null) && fragments) {\r\n const fragModel = fragments.core.models.list.get(bimFile.name)\r\n if (fragModel) {\r\n fragModel.object.position.set(bimFile.x ?? 0, bimFile.y ?? 0, bimFile.z ?? 0)\r\n if (bimFile.rotation != null) fragModel.object.rotation.y = bimFile.rotation\r\n fragModel.object.updateMatrixWorld(true)\r\n }\r\n }\r\n } catch (e) {\r\n console.error(\"Error loading BIM file\", bimFile.name, e)\r\n }\r\n }\r\n\r\n // Force update the fragments to render geometry immediately\r\n if (fragments) {\r\n fragments.core.update(true)\r\n }\r\n\r\n // If every file failed to load, surface an error instead of silently\r\n // dismissing the card as though the models were there.\r\n if (loadedCount === 0) {\r\n setCurrentState('error')\r\n return\r\n }\r\n\r\n // Mark each loaded file as visible in the BIM store so ModelsSection reflects it\r\n for (const bimFile of bimFiles) {\r\n bimDispatch({ type: 'SET_MODEL_UI_STATE', payload: { fileId: bimFile.id, isVisible: true } })\r\n }\r\n\r\n // Signal that models have loaded — the fallback timer will dismiss the card\r\n setHasLoadedModels(true)\r\n } catch (error) {\r\n console.error('Error loading BIM models:', error)\r\n setCurrentState('error')\r\n } finally {\r\n isLoadingModelsRef.current = false\r\n }\r\n }, [bimComponents, bimFiles, fragments])\r\n\r\n // Handle initial state transitions\r\n React.useEffect(() => {\r\n // If no bimComponents available, stay in opening state\r\n if (!bimComponents) {\r\n setCurrentState('opening')\r\n setHasLoadedModels(false)\r\n return\r\n }\r\n\r\n // If building is loading, stay in opening state\r\n if (buildingLoading) {\r\n setCurrentState('opening')\r\n return\r\n }\r\n\r\n // If building failed to load or no buildingId provided, show noBuilding state\r\n if (buildingError || (!buildingId && !building)) {\r\n setCurrentState('noBuilding')\r\n setHasLoadedModels(false)\r\n return\r\n }\r\n\r\n // If we have a building but files are still loading, stay in opening state\r\n if (building && filesLoading) {\r\n setCurrentState('opening')\r\n return\r\n }\r\n\r\n // If we've already loaded models (or are currently loading), don't reload\r\n if (hasLoadedModels) {\r\n return\r\n }\r\n\r\n // If we have a building but no BIM files, show noBimFiles state\r\n if (building && bimFiles.length === 0) {\r\n setCurrentState('noBimFiles')\r\n return\r\n }\r\n\r\n // We have BIM files, set to loading and start loading them\r\n if (building && bimFiles.length > 0) {\r\n setCurrentState('loading')\r\n setCameraHasMoved(false) // Reset camera moved state for new model\r\n loadBimModels()\r\n }\r\n }, [bimComponents, building, buildingLoading, buildingError, buildingId, filesLoading, bimFiles.length, loadBimModels, hasLoadedModels])\r\n\r\n // Don't render if not visible\r\n if (!shouldShow) {\r\n return null\r\n }\r\n\r\n const handleUploadClick = () => {\r\n fileInputRef.current?.click()\r\n }\r\n\r\n const handleBuildingSelect = (building: any) => {\r\n const url = new URL(window.location.href)\r\n url.searchParams.set('buildingId', building.id.toString())\r\n buildingDispatch({ type: 'SET-CURRENT-BUILDING', payload: { building } })\r\n setSelectedBuilding(building)\r\n setSearchTerm('')\r\n setSearchResults([])\r\n router.push(url.toString())\r\n }\r\n\r\n const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {\r\n const files = event.target.files\r\n if (!files || files.length === 0) return\r\n\r\n const file = files[0]\r\n\r\n try {\r\n const modelId = file.name\r\n setCurrentState('loading')\r\n setCameraHasMoved(false) // Reset camera moved state for new upload\r\n await handleFileUpload(file)\r\n\r\n window.dispatchEvent(new CustomEvent('bim-model-loaded-from-file', { detail: { modelId } }))\r\n bimDispatch({\r\n type: 'SET_MODEL', payload: { modelId },\r\n })\r\n setCurrentState('ready')\r\n }\r\n catch (error) {\r\n console.error('Error uploading file:', error)\r\n setCurrentState('error')\r\n }\r\n }\r\n\r\n return (\r\n <>\r\n <div className=\"absolute z-10 inset-0 bg-background/50 backdrop-blur-[1px] flex items-center justify-center pointer-events-none\">\r\n <Card className={cn(\"w-[536px] pointer-events-auto flex flex-col justify-start items-center gap-2\")}>\r\n <CardHeader className=\"flex justify-center items-center\">\r\n <div className=\"w-12 h-12 p-2 bg-card rounded-md shadow-sm border border-border flex justify-center items-center\">\r\n {currentState === 'noBuilding' ? (\r\n <Building2 className={cn(\"w-4 h-5 text-foreground\", buildingsLoading && \"animate-pulse\")} strokeWidth={2} />\r\n ) : (\r\n <Box className={cn(\"w-4 h-5 text-foreground\", currentState === 'opening' && \"animate-pulse\")} strokeWidth={2} />\r\n )}\r\n </div>\r\n </CardHeader>\r\n\r\n <CardContent className=\"self-stretch flex flex-col justify-start items-center gap-6 pt-0\">\r\n <div className=\"self-stretch flex flex-col justify-start items-center gap-2\">\r\n <div className=\"self-stretch text-center text-foreground text-xl font-semibold font-['Inter'] leading-7 flex items-center justify-center gap-2\">\r\n {currentState === 'opening' ? (\r\n <>\r\n {t('openingText')}\r\n <LoadingSpinner size={20} />\r\n </>\r\n ) : currentState === 'loading' ? (\r\n <>\r\n {t('loadingBimModel')}\r\n <LoadingSpinner size={20} />\r\n </>\r\n ) : currentState === 'noBuilding' ? (\r\n <>\r\n {t('noBuilding')}\r\n </>\r\n ) : (\r\n t('noBIMLoaded')\r\n )}\r\n </div>\r\n {(currentState === 'noBimFiles' || currentState === 'noBuilding') && (\r\n <div className=\"self-stretch text-center text-muted-foreground text-sm font-normal font-['Inter'] leading-tight\">\r\n {currentState === 'noBuilding' ? t('selectBuildingHelpText') : t('helpText')}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {currentState === 'noBuilding' && (\r\n <div className=\"self-stretch flex flex-col gap-3 justify-centre items-center\">\r\n {buildingsLoading ? (\r\n <div className=\"flex items-center justify-center gap-2 text-muted-foreground\">\r\n <LoadingSpinner size={16} />\r\n <span>{t('loadingBuildings') || 'Loading buildings...'}</span>\r\n </div>\r\n ) : buildings && buildings.length > 0 ? (\r\n <div className=\"w-full relative\">\r\n {selectedBuilding ? (\r\n <div className=\"relative flex justify-end items-center\">\r\n <Input\r\n type=\"text\"\r\n value={\r\n 'Building: '\r\n + (selectedBuilding.buildingName && selectedBuilding.buildingAddress\r\n ? `${selectedBuilding.buildingName}, ${selectedBuilding.buildingAddress}`\r\n : selectedBuilding.buildingName || selectedBuilding.buildingAddress || `Building ${selectedBuilding.id}`)\r\n }\r\n readOnly\r\n className=\"w-full\"\r\n />\r\n <X \r\n className=\"absolute right-2 cursor-pointer w-4 h-4 text-muted-foreground hover:text-foreground\" \r\n onClick={() => {\r\n setSelectedBuilding(null)\r\n setSearchTerm('')\r\n setSearchResults([])\r\n }} \r\n />\r\n </div>\r\n ) : (\r\n <div className=\"relative\">\r\n <Search className=\"absolute left-3 top-1/2 transform -translate-y-1/2 text-muted-foreground w-4 h-4\" />\r\n <Input\r\n placeholder={t('searchBuildings') || 'Search buildings...'}\r\n value={searchTerm}\r\n onChange={(e) => handleSearch(e.target.value)}\r\n className=\"w-full pl-10\"\r\n disabled={!ability.can('read', 'Building')}\r\n />\r\n </div>\r\n )}\r\n \r\n {/* Search results dropdown */}\r\n {searchResults.length > 0 && searchTerm !== '' && !selectedBuilding && (\r\n <div className=\"absolute top-full left-0 right-0 mt-1 bg-background border border-border rounded-md shadow-lg max-h-60 overflow-y-auto z-20\">\r\n {searchResults.map(building => (\r\n <div\r\n key={building.id}\r\n className=\"px-3 py-2 text-sm cursor-pointer hover:bg-muted transition-colors flex gap-2 items-center\"\r\n onClick={() => handleBuildingSelect(building)}\r\n >\r\n <SquareArrowOutUpRight className=\"w-3 h-3\" />\r\n {building.buildingName\r\n ? `${building.buildingName}, ${building.buildingAddress}`\r\n : building.buildingAddress || `Building ${building.id}`}\r\n </div>\r\n ))}\r\n </div>\r\n )}\r\n </div>\r\n ) : (\r\n <div className=\"text-muted-foreground text-center\">\r\n {t('noBuildings') || 'No buildings available'}\r\n </div>\r\n )}\r\n </div>\r\n )}\r\n\r\n {currentState === 'noBimFiles' && (\r\n <div className=\"self-stretch flex justify-center items-center gap-3\">\r\n <Input\r\n ref={fileInputRef}\r\n type=\"file\"\r\n accept=\".ifc,.frag\"\r\n onChange={handleFileChange}\r\n className=\"hidden\"\r\n />\r\n <Button\r\n onClick={handleUploadClick}\r\n size=\"sm\"\r\n className=\"gap-2\"\r\n disabled={!ability.can('create', 'File')}\r\n >\r\n <Upload className=\"w-4 h-4\" />\r\n {t('uploadButton')}\r\n </Button>\r\n </div>\r\n )}\r\n </CardContent>\r\n </Card>\r\n </div>\r\n </>\r\n )\r\n}\r\n"],"mappings":"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","names":["buildings","searchTerm","building","files"]}
@@ -1 +1 @@
1
- {"version":3,"file":"FilesSection.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAgB9B,OAAO,EAAE,MAAM,IAAI,KAAK,EAAE,MAAM,uCAAuC,CAAA;AASvE,UAAU,iBAAiB;IACzB,KAAK,EAAE,KAAK,EAAE,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAOD,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAU,EAAE,EAAE,iBAAiB,qBAkbpE"}
1
+ {"version":3,"file":"FilesSection.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAmB9B,OAAO,EAAE,MAAM,IAAI,KAAK,EAAE,MAAM,uCAAuC,CAAA;AAQvE,UAAU,iBAAiB;IACzB,KAAK,EAAE,KAAK,EAAE,CAAA;IACd,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAUD,wBAAgB,YAAY,CAAC,EAAE,KAAK,EAAE,KAAU,EAAE,EAAE,iBAAiB,qBA+iBpE"}
@@ -22,6 +22,7 @@ import * as React from "react";
22
22
  import * as LR from "lucide-react";
23
23
  import { BimContext, BuildingsContext, MenusContext } from "../../../../../../../../store";
24
24
  import { ModelManager } from "../../../../ModelManager";
25
+ import { DXFManager } from "../../../../DXFLoader";
25
26
  import * as THREE from "three";
26
27
  import { GizmoController } from "../../../../../utils/GizmoController";
27
28
  import { CurrentWorld } from "../../../../CurrentWorld";
@@ -34,12 +35,14 @@ import { useUploadFileToBuilding, useDeleteFile, useFile } from "../../../../../
34
35
  import { useFileUploadHandler, useFileDeleteHandler, FileItemComponent, useFileActions, useCommonFileUpload } from "../../../../../../../ui/FilesManager";
35
36
  import { IDSManager } from "../../../../IDSManager";
36
37
  import { BCFTopicsManager } from "../../../../BCFTopicsManager";
38
+ import { createFileMarker, removeMarker } from "../../../../tools/AddToBim/src/FileMarkerUtils";
37
39
  const OPTIONS_3D = ["download", "view", "move", "info", "delete"];
38
40
  const OPTIONS_NON_3D = ["download", "view", "delete"];
39
41
  const is3DFile = (ext) => {
40
42
  if (!ext) return false;
41
43
  return ["glb", "gltf", "fbx", "obj", "collada"].includes(ext.toLowerCase());
42
44
  };
45
+ const isPlaceable = (ext) => is3DFile(ext) || (ext == null ? void 0 : ext.toLowerCase()) === "dxf";
43
46
  function FilesSection({ files, query = "" }) {
44
47
  const t = useTranslations("FileSelection");
45
48
  const { state: bimState, dispatch: bimDispatch } = React.useContext(BimContext);
@@ -72,7 +75,8 @@ function FilesSection({ files, query = "" }) {
72
75
  })
73
76
  );
74
77
  return files.filter((file) => file.tag !== "user").filter((file) => file.type !== "map-file").map((file) => {
75
- let isVisible = visibilityMap.has(file.id) ? visibilityMap.get(file.id) : false;
78
+ var _a;
79
+ let isVisible = visibilityMap.has(file.id) ? visibilityMap.get(file.id) : (_a = file.isVisible) != null ? _a : false;
76
80
  if (file.extension === "ids" && activeIDSFileId === file.id) {
77
81
  isVisible = true;
78
82
  } else if (file.extension === "ids" && activeIDSFileId !== null && activeIDSFileId !== file.id) {
@@ -114,6 +118,48 @@ function FilesSection({ files, query = "" }) {
114
118
  React.useEffect(() => {
115
119
  modelManagerRef.current = modelManager;
116
120
  }, [modelManager]);
121
+ const dxfManager = React.useMemo(() => {
122
+ if (!bimComponents) return null;
123
+ try {
124
+ return bimComponents.get(DXFManager);
125
+ } catch (e) {
126
+ return null;
127
+ }
128
+ }, [bimComponents]);
129
+ const dxfGroupsRef = React.useRef(/* @__PURE__ */ new Map());
130
+ const markersRef = React.useRef(/* @__PURE__ */ new Map());
131
+ const [loadedTick, setLoadedTick] = React.useState(0);
132
+ const toggleDxfVisibility = React.useCallback(async (file, visible) => {
133
+ if (!dxfManager || !bimComponents) return;
134
+ const world = bimComponents.get(CurrentWorld).world;
135
+ if (!world) return;
136
+ const key = file.id.toString();
137
+ const existing = dxfGroupsRef.current.get(key);
138
+ if (visible) {
139
+ if (existing) {
140
+ existing.visible = true;
141
+ return;
142
+ }
143
+ try {
144
+ const res = await fetch(`/api/presignedUrlDownload/${file.id}`);
145
+ if (!res.ok) throw new Error(`Failed to get download URL: ${res.status}`);
146
+ const { presignedUrl } = await res.json();
147
+ const group = await dxfManager.parse(presignedUrl);
148
+ group.name = key;
149
+ const placed = file.x != null && file.y != null && file.z != null;
150
+ group.position.copy(placed ? new THREE.Vector3(file.x, file.y, file.z) : new THREE.Vector3());
151
+ group.scale.setScalar(1e-3);
152
+ if (file.rotation != null) group.rotation.y = file.rotation;
153
+ world.scene.three.add(group);
154
+ dxfGroupsRef.current.set(key, group);
155
+ setLoadedTick((t2) => t2 + 1);
156
+ } catch (err) {
157
+ console.error(`[FilesSection] Failed to load DXF "${file.name}":`, err);
158
+ }
159
+ } else if (existing) {
160
+ existing.visible = false;
161
+ }
162
+ }, [dxfManager, bimComponents]);
117
163
  const gizmoControllersRef = React.useRef(/* @__PURE__ */ new Map());
118
164
  const [moveFileId, setMoveFileId] = React.useState(null);
119
165
  const { updateFile } = useFile(moveFileId);
@@ -193,7 +239,12 @@ function FilesSection({ files, query = "" }) {
193
239
  }
194
240
  if (fragments) fragments.core.update(true);
195
241
  }
196
- }, [bimComponents, menusDispatch, bimState, bimDispatch, modelManager, fragments]);
242
+ if (file.extension === "dxf") {
243
+ await toggleDxfVisibility(file, newVisibility);
244
+ if (fragments) fragments.core.update(true);
245
+ }
246
+ setLoadedTick((t2) => t2 + 1);
247
+ }, [bimComponents, menusDispatch, bimState, bimDispatch, modelManager, fragments, toggleDxfVisibility]);
197
248
  const highlighter = React.useMemo(() => {
198
249
  if (!bimComponents) return null;
199
250
  try {
@@ -281,6 +332,44 @@ function FilesSection({ files, query = "" }) {
281
332
  if (cursor) cursor.cursor = "";
282
333
  };
283
334
  }, [placingFile, bimComponents, raycast]);
335
+ const getSceneObject = React.useCallback((file) => {
336
+ var _a, _b, _c;
337
+ if (file.extension === "dxf") return (_a = dxfGroupsRef.current.get(file.id.toString())) != null ? _a : null;
338
+ return (_c = (_b = modelManager == null ? void 0 : modelManager.getModelByName(file.name)) == null ? void 0 : _b.model) != null ? _c : null;
339
+ }, [modelManager]);
340
+ const editObject = React.useCallback((file, mode = "translate") => {
341
+ if (!bimComponents) return;
342
+ const world = bimComponents.get(CurrentWorld).world;
343
+ if (!world) return;
344
+ const obj = getSceneObject(file);
345
+ if (!obj) return;
346
+ const key = file.id.toString();
347
+ const existing = gizmoControllersRef.current.get(key);
348
+ if (existing) {
349
+ existing.setMode(mode);
350
+ return;
351
+ }
352
+ const gizmo = new GizmoController(world);
353
+ const cleanup = (save) => {
354
+ if (save) {
355
+ const { x, y, z } = obj.position;
356
+ const rotation = obj.rotation.y;
357
+ updateFileRef.current({ x, y, z, rotation }).catch((err) => console.error(`Failed to save position for "${file.name}":`, err));
358
+ file.x = x;
359
+ file.y = y;
360
+ file.z = z;
361
+ file.rotation = rotation;
362
+ }
363
+ gizmoControllersRef.current.delete(key);
364
+ setMoveFileId(null);
365
+ };
366
+ gizmo.onAccept = () => cleanup(true);
367
+ gizmo.onCancel = () => cleanup(false);
368
+ gizmo.setMode(mode);
369
+ setMoveFileId(file.id);
370
+ gizmo.attach(obj);
371
+ gizmoControllersRef.current.set(key, gizmo);
372
+ }, [bimComponents, getSceneObject]);
284
373
  const handleBimMove = React.useCallback((file) => {
285
374
  const isPlaced = file.x != null && file.y != null && file.z != null;
286
375
  if (!isPlaced) {
@@ -288,37 +377,12 @@ function FilesSection({ files, query = "" }) {
288
377
  setMoveFileId(file.id);
289
378
  return;
290
379
  }
291
- if (!bimComponents || !modelManager) return;
292
- const world = bimComponents.get(CurrentWorld).world;
293
- if (!world) return;
294
- const modelInfo = modelManager.getModelByName(file.name);
295
- if (!modelInfo) return;
296
- const existing = gizmoControllersRef.current.get(file.name);
297
- if (existing) {
298
- existing.dispose();
299
- gizmoControllersRef.current.delete(file.name);
300
- } else {
301
- const gizmo = new GizmoController(world);
302
- const cleanupGizmo = (savePosition) => {
303
- if (savePosition) {
304
- const { x, y, z } = modelInfo.model.position;
305
- const rotation = modelInfo.model.rotation.y;
306
- updateFileRef.current({ x, y, z, rotation }).catch((err) => console.error(`Failed to save position for "${file.name}":`, err));
307
- file.x = x;
308
- file.y = y;
309
- file.z = z;
310
- file.rotation = rotation;
311
- }
312
- gizmoControllersRef.current.delete(file.name);
313
- setMoveFileId(null);
314
- };
315
- gizmo.onAccept = () => cleanupGizmo(true);
316
- gizmo.onCancel = () => cleanupGizmo(false);
317
- setMoveFileId(file.id);
318
- gizmo.attach(modelInfo.model);
319
- gizmoControllersRef.current.set(file.name, gizmo);
380
+ if (file.extension === "dxf" && !dxfGroupsRef.current.has(file.id.toString())) {
381
+ void toggleDxfVisibility(file, true).then(() => editObject(file, "translate"));
382
+ return;
320
383
  }
321
- }, [bimComponents, modelManager]);
384
+ editObject(file, "translate");
385
+ }, [editObject, toggleDxfVisibility]);
322
386
  const { handleAction, deleteDialog } = useFileActions({
323
387
  files: localFiles,
324
388
  setFiles: setLocalFiles,
@@ -352,9 +416,8 @@ function FilesSection({ files, query = "" }) {
352
416
  onCheckedChange: async (checked) => {
353
417
  var _a;
354
418
  setLocalFiles((prev) => prev.map((f) => __spreadProps(__spreadValues({}, f), { isVisible: checked })));
355
- if (modelManager) {
356
- for (const f of localFiles) {
357
- if (!is3DFile(f.extension)) continue;
419
+ for (const f of localFiles) {
420
+ if (is3DFile(f.extension) && modelManager) {
358
421
  const existingModel = modelManager.getModelByName(f.name);
359
422
  if (checked) {
360
423
  if (existingModel) {
@@ -374,14 +437,80 @@ function FilesSection({ files, query = "" }) {
374
437
  console.error(`[FilesSection] Failed to load model "${f.name}":`, err);
375
438
  }
376
439
  }
377
- } else {
378
- if (existingModel) existingModel.model.visible = false;
440
+ } else if (existingModel) {
441
+ existingModel.model.visible = false;
379
442
  }
443
+ } else if (f.extension === "dxf") {
444
+ await toggleDxfVisibility(f, checked);
380
445
  }
381
- if (fragments) fragments.core.update(true);
382
446
  }
447
+ if (fragments) fragments.core.update(true);
448
+ setLoadedTick((t2) => t2 + 1);
383
449
  }
384
450
  });
451
+ const makeMarkerInput = React.useCallback((file, position) => {
452
+ var _a;
453
+ return {
454
+ id: file.id.toString(),
455
+ file: new File([], file.name, { type: (_a = file.mimeType) != null ? _a : "" }),
456
+ position
457
+ };
458
+ }, []);
459
+ React.useEffect(() => {
460
+ if (!bimComponents) return;
461
+ const world = bimComponents.get(CurrentWorld).world;
462
+ if (!world) return;
463
+ const wanted = new Map(
464
+ localFiles.filter((f) => f.isVisible && isPlaceable(f.extension)).map((f) => [f.id.toString(), f])
465
+ );
466
+ for (const [key, entry] of markersRef.current) {
467
+ if (!wanted.has(key)) {
468
+ removeMarker(entry.marker, world);
469
+ markersRef.current.delete(key);
470
+ }
471
+ }
472
+ for (const [key, file] of wanted) {
473
+ if (markersRef.current.has(key)) continue;
474
+ const obj = getSceneObject(file);
475
+ if (!obj) continue;
476
+ const marker = createFileMarker(makeMarkerInput(file, obj.position.clone()), obj, world, (action) => {
477
+ if (action === "delete") {
478
+ handleAction("delete", file);
479
+ return;
480
+ }
481
+ editObject(file, action === "move" ? "translate" : action);
482
+ });
483
+ if (marker) markersRef.current.set(key, { marker, file });
484
+ }
485
+ }, [localFiles, loadedTick, bimComponents, getSceneObject, editObject, handleAction, makeMarkerInput]);
486
+ React.useEffect(() => {
487
+ if (!bimComponents) return;
488
+ let raf = 0;
489
+ const worldPos = new THREE.Vector3();
490
+ const tick = () => {
491
+ markersRef.current.forEach(({ marker, file }, key) => {
492
+ const obj = getSceneObject(file);
493
+ if (!obj) {
494
+ marker.visible = false;
495
+ return;
496
+ }
497
+ obj.getWorldPosition(worldPos);
498
+ marker.position.set(worldPos.x, worldPos.y + 0.2, worldPos.z);
499
+ marker.visible = !gizmoControllersRef.current.has(key);
500
+ });
501
+ raf = requestAnimationFrame(tick);
502
+ };
503
+ raf = requestAnimationFrame(tick);
504
+ return () => cancelAnimationFrame(raf);
505
+ }, [bimComponents, getSceneObject]);
506
+ const markersCleanupRef = React.useRef(markersRef.current);
507
+ React.useEffect(() => {
508
+ const markers = markersCleanupRef.current;
509
+ return () => {
510
+ markers.forEach(({ marker }) => removeMarker(marker));
511
+ markers.clear();
512
+ };
513
+ }, []);
385
514
  return /* @__PURE__ */ jsxs(Fragment, { children: [
386
515
  /* @__PURE__ */ jsx(
387
516
  CollapsibleSection,
@@ -398,7 +527,7 @@ function FilesSection({ files, query = "" }) {
398
527
  {
399
528
  file: item,
400
529
  onAction: handleAction,
401
- options: is3DFile(item.extension) ? OPTIONS_3D : OPTIONS_NON_3D,
530
+ options: isPlaceable(item.extension) ? OPTIONS_3D : OPTIONS_NON_3D,
402
531
  translationKey: "FileSelection",
403
532
  confirmDelete: false
404
533
  },