@collabdt/core 0.0.56 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/README.md +4 -26
  2. package/dist/core/components/AppSidebarContent.d.ts +2 -1
  3. package/dist/core/components/AppSidebarContent.d.ts.map +1 -1
  4. package/dist/core/components/AppSidebarContent.js +10 -7
  5. package/dist/core/components/AppSidebarContent.js.map +1 -1
  6. package/dist/core/components/Toolbar.d.ts +7 -1
  7. package/dist/core/components/Toolbar.d.ts.map +1 -1
  8. package/dist/core/components/Toolbar.js +3 -3
  9. package/dist/core/components/Toolbar.js.map +1 -1
  10. package/dist/core/components/TopNavigationBar.d.ts +6 -1
  11. package/dist/core/components/TopNavigationBar.d.ts.map +1 -1
  12. package/dist/core/components/TopNavigationBar.js +2 -2
  13. package/dist/core/components/TopNavigationBar.js.map +1 -1
  14. package/dist/core/components/authentication/AuthPage.d.ts +2 -1
  15. package/dist/core/components/authentication/AuthPage.d.ts.map +1 -1
  16. package/dist/core/components/authentication/AuthPage.js +3 -5
  17. package/dist/core/components/authentication/AuthPage.js.map +1 -1
  18. package/dist/core/components/authentication/Signin.d.ts +2 -1
  19. package/dist/core/components/authentication/Signin.d.ts.map +1 -1
  20. package/dist/core/components/authentication/Signin.js +2 -2
  21. package/dist/core/components/authentication/Signin.js.map +1 -1
  22. package/dist/core/components/organizationConfig/src/organizationConfigContent.d.ts.map +1 -1
  23. package/dist/core/components/organizationConfig/src/organizationConfigContent.js +109 -36
  24. package/dist/core/components/organizationConfig/src/organizationConfigContent.js.map +1 -1
  25. package/dist/core/components/settings/index.d.ts +3 -1
  26. package/dist/core/components/settings/index.d.ts.map +1 -1
  27. package/dist/core/components/settings/index.js +2 -2
  28. package/dist/core/components/settings/index.js.map +1 -1
  29. package/dist/core/components/settings/src/AccountSettingsPanel.d.ts.map +1 -1
  30. package/dist/core/components/settings/src/AccountSettingsPanel.js +9 -2
  31. package/dist/core/components/settings/src/AccountSettingsPanel.js.map +1 -1
  32. package/dist/core/components/settings/src/OrganizationSettingsPanel.d.ts +5 -1
  33. package/dist/core/components/settings/src/OrganizationSettingsPanel.d.ts.map +1 -1
  34. package/dist/core/components/settings/src/OrganizationSettingsPanel.js +7 -5
  35. package/dist/core/components/settings/src/OrganizationSettingsPanel.js.map +1 -1
  36. package/dist/core/components/settings/src/SettingsContent.d.ts +2 -1
  37. package/dist/core/components/settings/src/SettingsContent.d.ts.map +1 -1
  38. package/dist/core/components/settings/src/SettingsContent.js +2 -2
  39. package/dist/core/components/settings/src/SettingsContent.js.map +1 -1
  40. package/dist/core/components/support/BugReportDialog.d.ts +3 -2
  41. package/dist/core/components/support/BugReportDialog.d.ts.map +1 -1
  42. package/dist/core/components/support/BugReportDialog.js +103 -25
  43. package/dist/core/components/support/BugReportDialog.js.map +1 -1
  44. package/dist/core/components/support/FeatureRequestDialog.d.ts +3 -1
  45. package/dist/core/components/support/FeatureRequestDialog.d.ts.map +1 -1
  46. package/dist/core/components/support/FeatureRequestDialog.js +39 -4
  47. package/dist/core/components/support/FeatureRequestDialog.js.map +1 -1
  48. package/dist/core/components/support/SupportMenu.d.ts.map +1 -1
  49. package/dist/core/components/support/SupportMenu.js +1 -4
  50. package/dist/core/components/support/SupportMenu.js.map +1 -1
  51. package/dist/core/components/ui/AnimatedBackground.d.ts +2 -1
  52. package/dist/core/components/ui/AnimatedBackground.d.ts.map +1 -1
  53. package/dist/core/components/ui/AnimatedBackground.js +2 -5
  54. package/dist/core/components/ui/AnimatedBackground.js.map +1 -1
  55. package/dist/core/components/ui/InfoSidebar/Container.d.ts +3 -1
  56. package/dist/core/components/ui/InfoSidebar/Container.d.ts.map +1 -1
  57. package/dist/core/components/ui/InfoSidebar/Container.js +4 -2
  58. package/dist/core/components/ui/InfoSidebar/Container.js.map +1 -1
  59. package/dist/core/components/ui/InfoSidebar/Header.d.ts +3 -2
  60. package/dist/core/components/ui/InfoSidebar/Header.d.ts.map +1 -1
  61. package/dist/core/components/ui/InfoSidebar/Header.js +5 -6
  62. package/dist/core/components/ui/InfoSidebar/Header.js.map +1 -1
  63. package/dist/core/components/ui/InfoSidebar/index.d.ts +7 -1
  64. package/dist/core/components/ui/InfoSidebar/index.d.ts.map +1 -1
  65. package/dist/core/components/ui/InfoSidebar/index.js +4 -4
  66. package/dist/core/components/ui/InfoSidebar/index.js.map +1 -1
  67. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts +2 -1
  68. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts.map +1 -1
  69. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js +3 -4
  70. package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js.map +1 -1
  71. package/dist/core/components/ui/Sensors/SensorsSection.d.ts +3 -1
  72. package/dist/core/components/ui/Sensors/SensorsSection.d.ts.map +1 -1
  73. package/dist/core/components/ui/Sensors/SensorsSection.js +3 -1
  74. package/dist/core/components/ui/Sensors/SensorsSection.js.map +1 -1
  75. package/dist/core/components/ui/Sidebar.d.ts +8 -0
  76. package/dist/core/components/ui/Sidebar.d.ts.map +1 -1
  77. package/dist/core/components/ui/Sidebar.js +21 -7
  78. package/dist/core/components/ui/Sidebar.js.map +1 -1
  79. package/dist/core/components/ui/ToolbarButton.js +18 -1
  80. package/dist/core/components/ui/ToolbarButton.js.map +1 -1
  81. package/dist/core/components/viewers/Data/DataMenu.d.ts +5 -1
  82. package/dist/core/components/viewers/Data/DataMenu.d.ts.map +1 -1
  83. package/dist/core/components/viewers/Data/DataMenu.js +15 -4
  84. package/dist/core/components/viewers/Data/DataMenu.js.map +1 -1
  85. package/dist/core/components/viewers/Data/HeaderButtons.d.ts +3 -1
  86. package/dist/core/components/viewers/Data/HeaderButtons.d.ts.map +1 -1
  87. package/dist/core/components/viewers/Data/HeaderButtons.js +11 -14
  88. package/dist/core/components/viewers/Data/HeaderButtons.js.map +1 -1
  89. package/dist/core/components/viewers/Data/MoreOptions.d.ts.map +1 -1
  90. package/dist/core/components/viewers/Data/MoreOptions.js +14 -27
  91. package/dist/core/components/viewers/Data/MoreOptions.js.map +1 -1
  92. package/dist/core/components/viewers/Data/buildingDetails/AddBuilding.d.ts +3 -1
  93. package/dist/core/components/viewers/Data/buildingDetails/AddBuilding.d.ts.map +1 -1
  94. package/dist/core/components/viewers/Data/buildingDetails/AddBuilding.js +4 -2
  95. package/dist/core/components/viewers/Data/buildingDetails/AddBuilding.js.map +1 -1
  96. package/dist/core/components/viewers/Data/buildingDetails/FieldRenderer.d.ts.map +1 -1
  97. package/dist/core/components/viewers/Data/buildingDetails/FieldRenderer.js +13 -18
  98. package/dist/core/components/viewers/Data/buildingDetails/FieldRenderer.js.map +1 -1
  99. package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.d.ts +3 -1
  100. package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.d.ts.map +1 -1
  101. package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js +3 -1
  102. package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js.map +1 -1
  103. package/dist/core/components/viewers/Data/details/DetailHeader.d.ts +2 -1
  104. package/dist/core/components/viewers/Data/details/DetailHeader.d.ts.map +1 -1
  105. package/dist/core/components/viewers/Data/details/DetailHeader.js +3 -5
  106. package/dist/core/components/viewers/Data/details/DetailHeader.js.map +1 -1
  107. package/dist/core/components/viewers/Data/details/FieldValue.d.ts.map +1 -1
  108. package/dist/core/components/viewers/Data/details/FieldValue.js +13 -3
  109. package/dist/core/components/viewers/Data/details/FieldValue.js.map +1 -1
  110. package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.d.ts +2 -0
  111. package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.d.ts.map +1 -1
  112. package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.js +84 -3
  113. package/dist/core/components/viewers/Data/siteDetails/AssociatedBuildings.js.map +1 -1
  114. package/dist/core/components/viewers/Data/siteDetails/SiteDetails.d.ts.map +1 -1
  115. package/dist/core/components/viewers/Data/siteDetails/SiteDetails.js +23 -2
  116. package/dist/core/components/viewers/Data/siteDetails/SiteDetails.js.map +1 -1
  117. package/dist/core/components/viewers/Viewer.d.ts +7 -1
  118. package/dist/core/components/viewers/Viewer.d.ts.map +1 -1
  119. package/dist/core/components/viewers/Viewer.js +6 -6
  120. package/dist/core/components/viewers/Viewer.js.map +1 -1
  121. package/dist/core/components/viewers/bim/BimToolbar.d.ts +3 -1
  122. package/dist/core/components/viewers/bim/BimToolbar.d.ts.map +1 -1
  123. package/dist/core/components/viewers/bim/BimToolbar.js +2 -2
  124. package/dist/core/components/viewers/bim/BimToolbar.js.map +1 -1
  125. package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.d.ts +3 -1
  126. package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.d.ts.map +1 -1
  127. package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.js +2 -2
  128. package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.js.map +1 -1
  129. package/dist/core/components/viewers/bim/src/BimSidebar/src/index.d.ts +5 -1
  130. package/dist/core/components/viewers/bim/src/BimSidebar/src/index.d.ts.map +1 -1
  131. package/dist/core/components/viewers/bim/src/BimSidebar/src/index.js +3 -2
  132. package/dist/core/components/viewers/bim/src/BimSidebar/src/index.js.map +1 -1
  133. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts +3 -1
  134. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts.map +1 -1
  135. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js +2 -2
  136. package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js.map +1 -1
  137. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.d.ts +1 -1
  138. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.d.ts.map +1 -1
  139. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.js +3 -5
  140. package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.js.map +1 -1
  141. package/dist/core/components/viewers/bim/src/tools/bimToolbar.d.ts +3 -1
  142. package/dist/core/components/viewers/bim/src/tools/bimToolbar.d.ts.map +1 -1
  143. package/dist/core/components/viewers/bim/src/tools/bimToolbar.js +4 -2
  144. package/dist/core/components/viewers/bim/src/tools/bimToolbar.js.map +1 -1
  145. package/dist/core/components/viewers/map/MapViewer.d.ts +3 -1
  146. package/dist/core/components/viewers/map/MapViewer.d.ts.map +1 -1
  147. package/dist/core/components/viewers/map/MapViewer.js +2 -2
  148. package/dist/core/components/viewers/map/MapViewer.js.map +1 -1
  149. package/dist/core/components/viewers/map/datasets/RowActions.d.ts +2 -1
  150. package/dist/core/components/viewers/map/datasets/RowActions.d.ts.map +1 -1
  151. package/dist/core/components/viewers/map/datasets/RowActions.js +5 -6
  152. package/dist/core/components/viewers/map/datasets/RowActions.js.map +1 -1
  153. package/dist/core/components/viewers/map/datasets/index.d.ts +5 -1
  154. package/dist/core/components/viewers/map/datasets/index.d.ts.map +1 -1
  155. package/dist/core/components/viewers/map/datasets/index.js +15 -16
  156. package/dist/core/components/viewers/map/datasets/index.js.map +1 -1
  157. package/dist/core/components/viewers/map/src/Geocoder.d.ts +3 -1
  158. package/dist/core/components/viewers/map/src/Geocoder.d.ts.map +1 -1
  159. package/dist/core/components/viewers/map/src/Geocoder.js +5 -1
  160. package/dist/core/components/viewers/map/src/Geocoder.js.map +1 -1
  161. package/dist/core/components/viewers/map/src/MapLayers/index.d.ts +6 -1
  162. package/dist/core/components/viewers/map/src/MapLayers/index.d.ts.map +1 -1
  163. package/dist/core/components/viewers/map/src/MapLayers/index.js +5 -3
  164. package/dist/core/components/viewers/map/src/MapLayers/index.js.map +1 -1
  165. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.d.ts +5 -1
  166. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.d.ts.map +1 -1
  167. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js +6 -10
  168. package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js.map +1 -1
  169. package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.d.ts +3 -1
  170. package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.d.ts.map +1 -1
  171. package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.js +4 -6
  172. package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.js.map +1 -1
  173. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteContextMenu.d.ts +19 -0
  174. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteContextMenu.d.ts.map +1 -0
  175. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteContextMenu.js +163 -0
  176. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteContextMenu.js.map +1 -0
  177. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteLayer.d.ts +3 -0
  178. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteLayer.d.ts.map +1 -0
  179. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteLayer.js +310 -0
  180. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/SiteLayer.js.map +1 -0
  181. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/siteGeometry.d.ts +30 -0
  182. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/siteGeometry.d.ts.map +1 -0
  183. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/siteGeometry.js +122 -0
  184. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/siteGeometry.js.map +1 -0
  185. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/useShowSitesOnMap.d.ts +13 -0
  186. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/useShowSitesOnMap.d.ts.map +1 -0
  187. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/useShowSitesOnMap.js +58 -0
  188. package/dist/core/components/viewers/map/src/MapLayers/src/SiteLayer/useShowSitesOnMap.js.map +1 -0
  189. package/dist/core/components/viewers/map/src/MapSidebar/index.d.ts +6 -1
  190. package/dist/core/components/viewers/map/src/MapSidebar/index.d.ts.map +1 -1
  191. package/dist/core/components/viewers/map/src/MapSidebar/index.js +5 -4
  192. package/dist/core/components/viewers/map/src/MapSidebar/index.js.map +1 -1
  193. package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.d.ts +5 -1
  194. package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.d.ts.map +1 -1
  195. package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.js +5 -8
  196. package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.js.map +1 -1
  197. package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.d.ts +3 -1
  198. package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.d.ts.map +1 -1
  199. package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.js +2 -2
  200. package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.js.map +1 -1
  201. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/index.d.ts +3 -1
  202. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/index.d.ts.map +1 -1
  203. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/index.js +2 -2
  204. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/index.js.map +1 -1
  205. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/LocationSettings.d.ts +3 -1
  206. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/LocationSettings.d.ts.map +1 -1
  207. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/LocationSettings.js +4 -7
  208. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/LocationSettings.js.map +1 -1
  209. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.d.ts.map +1 -1
  210. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js +8 -8
  211. package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js.map +1 -1
  212. package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/AssociateBuildingsDialog.d.ts +18 -0
  213. package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/AssociateBuildingsDialog.d.ts.map +1 -0
  214. package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/AssociateBuildingsDialog.js +102 -0
  215. package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/AssociateBuildingsDialog.js.map +1 -0
  216. package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/SiteAdder.d.ts.map +1 -1
  217. package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/SiteAdder.js +243 -176
  218. package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/SiteAdder.js.map +1 -1
  219. package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/persistSite.d.ts +24 -0
  220. package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/persistSite.d.ts.map +1 -0
  221. package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/persistSite.js +46 -0
  222. package/dist/core/components/viewers/map/src/tools/AddTools/AddSite/persistSite.js.map +1 -0
  223. package/dist/core/components/viewers/map/src/tools/AddTools/AddToMap.d.ts +8 -1
  224. package/dist/core/components/viewers/map/src/tools/AddTools/AddToMap.d.ts.map +1 -1
  225. package/dist/core/components/viewers/map/src/tools/AddTools/AddToMap.js +8 -3
  226. package/dist/core/components/viewers/map/src/tools/AddTools/AddToMap.js.map +1 -1
  227. package/dist/core/components/viewers/map/src/tools/DatasetMapTool.d.ts +11 -1
  228. package/dist/core/components/viewers/map/src/tools/DatasetMapTool.d.ts.map +1 -1
  229. package/dist/core/components/viewers/map/src/tools/DatasetMapTool.js +5 -3
  230. package/dist/core/components/viewers/map/src/tools/DatasetMapTool.js.map +1 -1
  231. package/dist/core/components/viewers/map/src/tools/mapTools.d.ts +10 -1
  232. package/dist/core/components/viewers/map/src/tools/mapTools.d.ts.map +1 -1
  233. package/dist/core/components/viewers/map/src/tools/mapTools.js +5 -3
  234. package/dist/core/components/viewers/map/src/tools/mapTools.js.map +1 -1
  235. package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.d.ts +1 -0
  236. package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.d.ts.map +1 -1
  237. package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.js +1 -0
  238. package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.js.map +1 -1
  239. package/dist/core/components/viewers/map/utils/geocoding/config.d.ts +14 -5
  240. package/dist/core/components/viewers/map/utils/geocoding/config.d.ts.map +1 -1
  241. package/dist/core/components/viewers/map/utils/geocoding/config.js +22 -11
  242. package/dist/core/components/viewers/map/utils/geocoding/config.js.map +1 -1
  243. package/dist/core/components/viewers/map/utils/geocoding/index.d.ts.map +1 -1
  244. package/dist/core/components/viewers/map/utils/geocoding/index.js +2 -2
  245. package/dist/core/components/viewers/map/utils/geocoding/index.js.map +1 -1
  246. package/dist/core/components/viewers/map/utils/geocoding/osm.d.ts.map +1 -1
  247. package/dist/core/components/viewers/map/utils/geocoding/osm.js +5 -4
  248. package/dist/core/components/viewers/map/utils/geocoding/osm.js.map +1 -1
  249. package/dist/core/components/viewers/map/utils/geocoding/pelias.d.ts.map +1 -1
  250. package/dist/core/components/viewers/map/utils/geocoding/pelias.js +7 -5
  251. package/dist/core/components/viewers/map/utils/geocoding/pelias.js.map +1 -1
  252. package/dist/core/components/viewers/pointcloud/PointCloudViewer.d.ts +3 -1
  253. package/dist/core/components/viewers/pointcloud/PointCloudViewer.d.ts.map +1 -1
  254. package/dist/core/components/viewers/pointcloud/PointCloudViewer.js +11 -14
  255. package/dist/core/components/viewers/pointcloud/PointCloudViewer.js.map +1 -1
  256. package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.d.ts +3 -1
  257. package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.d.ts.map +1 -1
  258. package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.js +37 -52
  259. package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.js.map +1 -1
  260. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.d.ts +3 -1
  261. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.d.ts.map +1 -1
  262. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.js +5 -3
  263. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.js.map +1 -1
  264. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.d.ts +2 -1
  265. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.d.ts.map +1 -1
  266. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.js +5 -6
  267. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.js.map +1 -1
  268. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.d.ts +2 -1
  269. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.d.ts.map +1 -1
  270. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.js +15 -9
  271. package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.js.map +1 -1
  272. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/index.d.ts +5 -1
  273. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/index.d.ts.map +1 -1
  274. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/index.js +3 -2
  275. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/index.js.map +1 -1
  276. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.d.ts +3 -1
  277. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.d.ts.map +1 -1
  278. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js +2 -2
  279. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js.map +1 -1
  280. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.d.ts +2 -1
  281. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.d.ts.map +1 -1
  282. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.js +12 -23
  283. package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.js.map +1 -1
  284. package/dist/core/hooks/sites/createSiteHooks.d.ts.map +1 -1
  285. package/dist/core/hooks/sites/createSiteHooks.js +0 -1
  286. package/dist/core/hooks/sites/createSiteHooks.js.map +1 -1
  287. package/dist/core/hooks/useCaptureScreenshot.d.ts +2 -0
  288. package/dist/core/hooks/useCaptureScreenshot.d.ts.map +1 -0
  289. package/dist/core/hooks/useCaptureScreenshot.js +110 -0
  290. package/dist/core/hooks/useCaptureScreenshot.js.map +1 -0
  291. package/dist/core/hooks/useGeocodingRuntimeConfig.d.ts +3 -0
  292. package/dist/core/hooks/useGeocodingRuntimeConfig.d.ts.map +1 -0
  293. package/dist/core/hooks/useGeocodingRuntimeConfig.js +17 -0
  294. package/dist/core/hooks/useGeocodingRuntimeConfig.js.map +1 -0
  295. package/dist/core/store/AppConfig/context.d.ts +5 -0
  296. package/dist/core/store/AppConfig/context.d.ts.map +1 -1
  297. package/dist/core/store/AppConfig/context.js.map +1 -1
  298. package/dist/core/store/CombineProviders.d.ts +6 -1
  299. package/dist/core/store/CombineProviders.d.ts.map +1 -1
  300. package/dist/core/store/CombineProviders.js +6 -3
  301. package/dist/core/store/CombineProviders.js.map +1 -1
  302. package/dist/core/store/MapSites/context.d.ts +16 -0
  303. package/dist/core/store/MapSites/context.d.ts.map +1 -0
  304. package/dist/core/store/MapSites/context.js +29 -0
  305. package/dist/core/store/MapSites/context.js.map +1 -0
  306. package/dist/core/store/MapSites/reducer.d.ts +52 -0
  307. package/dist/core/store/MapSites/reducer.d.ts.map +1 -0
  308. package/dist/core/store/MapSites/reducer.js +70 -0
  309. package/dist/core/store/MapSites/reducer.js.map +1 -0
  310. package/dist/core/store/index.d.ts +1 -0
  311. package/dist/core/store/index.d.ts.map +1 -1
  312. package/dist/core/store/index.js +1 -0
  313. package/dist/core/store/index.js.map +1 -1
  314. package/dist/core/types/tools.d.ts +2 -1
  315. package/dist/core/types/tools.d.ts.map +1 -1
  316. package/dist/core/utils/imageUtils.d.ts.map +1 -1
  317. package/dist/core/utils/imageUtils.js +2 -1
  318. package/dist/core/utils/imageUtils.js.map +1 -1
  319. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/core/components/support/SupportMenu.tsx"],"sourcesContent":["import * as LR from \"lucide-react\";\r\nimport * as React from \"react\";\r\nimport { useTranslations } from \"next-intl\";\r\n\r\nimport {\r\n DropdownMenu,\r\n DropdownMenuTrigger,\r\n DropdownMenuContent,\r\n DropdownMenuItem,\r\n} from \"../ui/DropdownMenu\";\r\n\r\nimport { SidebarMenuButton } from \"../ui/Sidebar\";\r\n\r\ntype Props = {\r\n item: any;\r\n isCollapsed: boolean;\r\n onOpenBug: () => void;\r\n onOpenFeature: () => void;\r\n};\r\n\r\nexport function SupportMenu({\r\n item,\r\n isCollapsed,\r\n onOpenBug,\r\n onOpenFeature,\r\n}: Props) {\r\n const t = useTranslations(\"supportMenu\");\r\n const [menuOpen, setMenuOpen] = React.useState(false);\r\n\r\n const openDialogAfterMenuCloses = (callback: () => void) => {\r\n setMenuOpen(false);\r\n\r\n requestAnimationFrame(() => {\r\n callback();\r\n });\r\n };\r\n\r\n return (\r\n <DropdownMenu open={menuOpen} onOpenChange={setMenuOpen}>\r\n <DropdownMenuTrigger asChild>\r\n <SidebarMenuButton\r\n title={item.tooltip}\r\n className={`text-xs flex items-center gap-2 w-full ${\r\n isCollapsed ? \"justify-center p-2\" : \"justify-start p-2\"\r\n }`}\r\n >\r\n <LR.LifeBuoy className=\"h-4 w-4\" />\r\n {!isCollapsed && <span>{item.title}</span>}\r\n </SidebarMenuButton>\r\n </DropdownMenuTrigger>\r\n\r\n <DropdownMenuContent align=\"start\">\r\n <DropdownMenuItem\r\n onSelect={() =>\r\n window.open(\r\n \"mailto:support@collabdt.org?subject=Support Request\",\r\n \"_self\"\r\n )\r\n }\r\n >\r\n <LR.Send className=\"mr-2 h-4 w-4\" />\r\n {t(\"contactTeam\")}\r\n </DropdownMenuItem>\r\n\r\n <DropdownMenuItem\r\n onSelect={() =>\r\n openDialogAfterMenuCloses(onOpenFeature)\r\n }\r\n >\r\n <LR.SquarePlus className=\"mr-2 h-4 w-4\" />\r\n {t(\"suggestFeature\")}\r\n </DropdownMenuItem>\r\n\r\n <DropdownMenuItem\r\n onSelect={() =>\r\n openDialogAfterMenuCloses(onOpenBug)\r\n }\r\n >\r\n <LR.Bug className=\"mr-2 h-4 w-4\" />\r\n {t(\"reportBug\")}\r\n </DropdownMenuItem>\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n );\r\n}\r\n\r\n"],"mappings":"AAwCQ,SAME,KANF;AAxCR,YAAY,QAAQ;AACpB,YAAY,WAAW;AACvB,SAAS,uBAAuB;AAEhC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,yBAAyB;AAS3B,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAU;AACR,QAAM,IAAI,gBAAgB,aAAa;AACvC,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAS,KAAK;AAEpD,QAAM,4BAA4B,CAAC,aAAyB;AAC1D,gBAAY,KAAK;AAEjB,0BAAsB,MAAM;AAC1B,eAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,SACE,qBAAC,gBAAa,MAAM,UAAU,cAAc,aAC1C;AAAA,wBAAC,uBAAoB,SAAO,MAC1B;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,KAAK;AAAA,QACZ,WAAW,0CACT,cAAc,uBAAuB,mBACvC;AAAA,QAEA;AAAA,8BAAC,GAAG,UAAH,EAAY,WAAU,WAAU;AAAA,UAChC,CAAC,eAAe,oBAAC,UAAM,eAAK,OAAM;AAAA;AAAA;AAAA,IACrC,GACF;AAAA,IAEA,qBAAC,uBAAoB,OAAM,SACzB;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,UAAU,MACR,OAAO;AAAA,YACL;AAAA,YACA;AAAA,UACF;AAAA,UAGF;AAAA,gCAAC,GAAG,MAAH,EAAQ,WAAU,gBAAe;AAAA,YACjC,EAAE,aAAa;AAAA;AAAA;AAAA,MAClB;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,UAAU,MACR,0BAA0B,aAAa;AAAA,UAGzC;AAAA,gCAAC,GAAG,YAAH,EAAc,WAAU,gBAAe;AAAA,YACvC,EAAE,gBAAgB;AAAA;AAAA;AAAA,MACrB;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,UAAU,MACR,0BAA0B,SAAS;AAAA,UAGrC;AAAA,gCAAC,GAAG,KAAH,EAAO,WAAU,gBAAe;AAAA,YAChC,EAAE,WAAW;AAAA;AAAA;AAAA,MAChB;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../../src/core/components/support/SupportMenu.tsx"],"sourcesContent":["import * as LR from \"lucide-react\";\r\nimport * as React from \"react\";\r\nimport { useTranslations } from \"next-intl\";\r\n\r\nimport {\r\n DropdownMenu,\r\n DropdownMenuTrigger,\r\n DropdownMenuContent,\r\n DropdownMenuItem,\r\n} from \"../ui/DropdownMenu\";\r\n\r\nimport { SidebarMenuButton } from \"../ui/Sidebar\";\r\n\r\ntype Props = {\r\n item: any;\r\n isCollapsed: boolean;\r\n onOpenBug: () => void;\r\n onOpenFeature: () => void;\r\n};\r\n\r\nexport function SupportMenu({\r\n item,\r\n isCollapsed,\r\n onOpenBug,\r\n onOpenFeature,\r\n}: Props) {\r\n const t = useTranslations(\"supportMenu\");\r\n const [menuOpen, setMenuOpen] = React.useState(false);\r\n\r\n const openDialogAfterMenuCloses = (callback: () => void) => {\r\n setMenuOpen(false);\r\n\r\n requestAnimationFrame(() => {\r\n callback();\r\n });\r\n };\r\n\r\n return (\r\n <DropdownMenu open={menuOpen} onOpenChange={setMenuOpen}>\r\n <DropdownMenuTrigger asChild>\r\n <SidebarMenuButton\r\n title={item.tooltip}\r\n className={`text-xs flex items-center gap-2 w-full ${isCollapsed ? \"justify-center p-2\" : \"justify-start p-2\"\r\n }`}\r\n >\r\n <LR.LifeBuoy className=\"h-4 w-4\" />\r\n {!isCollapsed && <span>{item.title}</span>}\r\n </SidebarMenuButton>\r\n </DropdownMenuTrigger>\r\n\r\n <DropdownMenuContent align=\"start\">\r\n <DropdownMenuItem\r\n onSelect={() =>\r\n window.open(\"https://collabdt.org/En/contact\", \"_blank\")\r\n }\r\n >\r\n <LR.Send className=\"mr-2 h-4 w-4\" />\r\n {t(\"contactTeam\")}\r\n </DropdownMenuItem>\r\n\r\n <DropdownMenuItem\r\n onSelect={() =>\r\n openDialogAfterMenuCloses(onOpenFeature)\r\n }\r\n >\r\n <LR.SquarePlus className=\"mr-2 h-4 w-4\" />\r\n {t(\"suggestFeature\")}\r\n </DropdownMenuItem>\r\n\r\n <DropdownMenuItem\r\n onSelect={() =>\r\n openDialogAfterMenuCloses(onOpenBug)\r\n }\r\n >\r\n <LR.Bug className=\"mr-2 h-4 w-4\" />\r\n {t(\"reportBug\")}\r\n </DropdownMenuItem>\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n );\r\n}\r\n\r\n"],"mappings":"AAwCQ,SAKE,KALF;AAxCR,YAAY,QAAQ;AACpB,YAAY,WAAW;AACvB,SAAS,uBAAuB;AAEhC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAEP,SAAS,yBAAyB;AAS3B,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAU;AACR,QAAM,IAAI,gBAAgB,aAAa;AACvC,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAS,KAAK;AAEpD,QAAM,4BAA4B,CAAC,aAAyB;AAC1D,gBAAY,KAAK;AAEjB,0BAAsB,MAAM;AAC1B,eAAS;AAAA,IACX,CAAC;AAAA,EACH;AAEA,SACE,qBAAC,gBAAa,MAAM,UAAU,cAAc,aAC1C;AAAA,wBAAC,uBAAoB,SAAO,MAC1B;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,KAAK;AAAA,QACZ,WAAW,0CAA0C,cAAc,uBAAuB,mBACxF;AAAA,QAEF;AAAA,8BAAC,GAAG,UAAH,EAAY,WAAU,WAAU;AAAA,UAChC,CAAC,eAAe,oBAAC,UAAM,eAAK,OAAM;AAAA;AAAA;AAAA,IACrC,GACF;AAAA,IAEA,qBAAC,uBAAoB,OAAM,SACzB;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,UAAU,MACR,OAAO,KAAK,mCAAmC,QAAQ;AAAA,UAGzD;AAAA,gCAAC,GAAG,MAAH,EAAQ,WAAU,gBAAe;AAAA,YACjC,EAAE,aAAa;AAAA;AAAA;AAAA,MAClB;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,UAAU,MACR,0BAA0B,aAAa;AAAA,UAGzC;AAAA,gCAAC,GAAG,YAAH,EAAc,WAAU,gBAAe;AAAA,YACvC,EAAE,gBAAgB;AAAA;AAAA;AAAA,MACrB;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,UAAU,MACR,0BAA0B,SAAS;AAAA,UAGrC;AAAA,gCAAC,GAAG,KAAH,EAAO,WAAU,gBAAe;AAAA,YAChC,EAAE,WAAW;AAAA;AAAA;AAAA,MAChB;AAAA,OACF;AAAA,KACF;AAEJ;","names":[]}
@@ -1,6 +1,7 @@
1
1
  interface Props {
2
2
  theme?: 'light' | 'dark';
3
+ assetsUrl?: string;
3
4
  }
4
- export default function AnimatedBackground({ theme }?: Props): import("react").JSX.Element;
5
+ export default function AnimatedBackground({ theme, assetsUrl }?: Props): import("react").JSX.Element;
5
6
  export {};
6
7
  //# sourceMappingURL=AnimatedBackground.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AnimatedBackground.d.ts","sourceRoot":"","sources":["../../../../src/core/components/ui/AnimatedBackground.tsx"],"names":[],"mappings":"AASA,UAAU,KAAK;IACb,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;CACzB;AAED,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EAAE,KAAK,EAAE,GAAE,KAAU,+BA8O/D"}
1
+ {"version":3,"file":"AnimatedBackground.d.ts","sourceRoot":"","sources":["../../../../src/core/components/ui/AnimatedBackground.tsx"],"names":[],"mappings":"AAQA,UAAU,KAAK;IACb,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IACxB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,GAAE,KAAU,+BA2O1E"}
@@ -2,8 +2,7 @@
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useRef, useState } from "react";
4
4
  import { useMotionValue, useSpring } from "framer-motion";
5
- import { useAppConfigContext } from "../../store/AppConfig/context";
6
- function AnimatedBackground({ theme } = {}) {
5
+ function AnimatedBackground({ theme, assetsUrl } = {}) {
7
6
  const canvasRef = useRef(null);
8
7
  const mouseX = useMotionValue(0);
9
8
  const mouseY = useMotionValue(0);
@@ -157,13 +156,11 @@ function AnimatedBackground({ theme } = {}) {
157
156
  window.removeEventListener("resize", resize);
158
157
  };
159
158
  }, [smoothMouseX, smoothMouseY, isDark]);
160
- const { state: { runtimeConfig: { minioUrl } } } = useAppConfigContext();
161
- const assetsUrl = minioUrl || "";
162
159
  return /* @__PURE__ */ jsxs(Fragment, { children: [
163
160
  /* @__PURE__ */ jsx("div", { className: "absolute top-0 right-0 inset-0 z-10 w-screen", children: /* @__PURE__ */ jsx(
164
161
  "img",
165
162
  {
166
- src: `${assetsUrl}/cdt-homepage/home-bg.png`,
163
+ src: `${assetsUrl != null ? assetsUrl : ""}/cdt-homepage/home-bg.png`,
167
164
  alt: "Background",
168
165
  className: "object-cover opacity-10 w-screen",
169
166
  style: { filter: isDark ? "invert(0)" : "invert(1)" }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/core/components/ui/AnimatedBackground.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport { useEffect, useRef, useState } from 'react'\r\nimport { useMotionValue, useSpring } from 'framer-motion'\r\nimport { useAppConfigContext } from '../../store/AppConfig/context'\r\n\r\ninterface Props {\r\n theme?: 'light' | 'dark'\r\n}\r\n\r\nexport default function AnimatedBackground({ theme }: Props = {}) {\r\n const canvasRef = useRef<HTMLCanvasElement>(null)\r\n const mouseX = useMotionValue(0)\r\n const mouseY = useMotionValue(0)\r\n const smoothMouseX = useSpring(mouseX, { stiffness: 50, damping: 20 })\r\n const smoothMouseY = useSpring(mouseY, { stiffness: 50, damping: 20 })\r\n const [isDark, setIsDark] = useState(theme !== undefined ? theme === 'dark' : true)\r\n\r\n useEffect(() => {\r\n // If theme is controlled externally, just sync and skip the observer\r\n if (theme !== undefined) {\r\n setIsDark(theme === 'dark')\r\n return\r\n }\r\n\r\n // Auto-detect from document for standalone usage (hero section)\r\n setIsDark(document.documentElement.classList.contains('dark'))\r\n const observer = new MutationObserver(() => {\r\n setIsDark(document.documentElement.classList.contains('dark'))\r\n })\r\n observer.observe(document.documentElement, {\r\n attributes: true,\r\n attributeFilter: ['class']\r\n })\r\n return () => observer.disconnect()\r\n }, [theme])\r\n\r\n useEffect(() => {\r\n const handleMouseMove = (e: MouseEvent) => {\r\n mouseX.set(e.clientX)\r\n mouseY.set(e.clientY)\r\n }\r\n\r\n window.addEventListener('mousemove', handleMouseMove)\r\n return () => window.removeEventListener('mousemove', handleMouseMove)\r\n }, [mouseX, mouseY])\r\n\r\n useEffect(() => {\r\n const canvas = canvasRef.current\r\n if (!canvas) return\r\n\r\n const ctx = canvas.getContext('2d')\r\n if (!ctx) return\r\n\r\n const resize = () => {\r\n canvas.width = window.innerWidth\r\n canvas.height = window.innerHeight\r\n }\r\n resize()\r\n window.addEventListener('resize', resize)\r\n\r\n let animationFrameId: number\r\n let time = 0\r\n let offsetX = 0\r\n\r\n interface DataNode {\r\n x: number\r\n y: number\r\n baseX: number\r\n baseY: number\r\n connections: number[]\r\n pulse: number\r\n }\r\n\r\n const dataNodes: DataNode[] = []\r\n const gridSize = 100\r\n const nodeSpacing = 150\r\n // Render extra columns for seamless wrap\r\n const nodeCols = Math.ceil(canvas.width / nodeSpacing) + 2\r\n const nodeRows = Math.ceil(canvas.height / nodeSpacing)\r\n\r\n for (let row = 0; row < nodeRows; row++) {\r\n for (let col = 0; col < nodeCols; col++) {\r\n const index = row * nodeCols + col\r\n const baseX = col * nodeSpacing + nodeSpacing / 2\r\n const baseY = row * nodeSpacing + nodeSpacing / 2\r\n dataNodes.push({\r\n x: baseX,\r\n y: baseY,\r\n baseX,\r\n baseY,\r\n connections: [],\r\n pulse: (row + col) * 0.5\r\n })\r\n }\r\n }\r\n\r\n dataNodes.forEach((node, i) => {\r\n const col = i % nodeCols\r\n const row = Math.floor(i / nodeCols)\r\n if (col < nodeCols - 1) {\r\n node.connections.push(i + 1)\r\n }\r\n if (row < nodeRows - 1) {\r\n node.connections.push(i + nodeCols)\r\n }\r\n })\r\n\r\n const draw = () => {\r\n time += 0.008\r\n // Move left slowly\r\n offsetX += 0.1 // Lower for slower movement\r\n // Loop offsetX to avoid overflow and create infinite effect\r\n if (offsetX > nodeSpacing) offsetX -= nodeSpacing\r\n\r\n ctx.clearRect(0, 0, canvas.width, canvas.height)\r\n\r\n // Theme-aware colors\r\n const bgGradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height)\r\n if (isDark) {\r\n bgGradient.addColorStop(0, 'rgba(239, 145, 97, 0.025)')\r\n bgGradient.addColorStop(1, 'rgba(180, 90, 40, 0.02)')\r\n } else {\r\n bgGradient.addColorStop(0, 'rgba(239, 146, 98, 0.08)')\r\n bgGradient.addColorStop(1, 'rgba(239, 146, 98, 0.06)')\r\n }\r\n ctx.fillStyle = bgGradient\r\n ctx.fillRect(0, 0, canvas.width, canvas.height)\r\n\r\n // Animate node positions with floating effect\r\n dataNodes.forEach((node, i) => {\r\n const floatX = Math.sin(time * 0.3 + node.pulse) * 2\r\n const floatY = Math.cos(time * 0.2 + node.pulse) * 2\r\n // Shift node baseX by offsetX for infinite left movement\r\n let x = node.baseX - offsetX + floatX\r\n // Wrap node.x to the right if it goes off the left edge\r\n x = ((x + nodeCols * nodeSpacing) % (nodeCols * nodeSpacing))\r\n node.x = x\r\n node.y = node.baseY + floatY\r\n })\r\n\r\n // Theme-aware grid lines\r\n ctx.strokeStyle = isDark ? 'rgba(239, 145, 97, 0.08)' : 'rgba(239, 146, 98, 0.3)'\r\n ctx.lineWidth = 0.5\r\n \r\n for (let y = canvas.height; y > canvas.height * 0.3; y -= gridSize) {\r\n ctx.beginPath()\r\n ctx.moveTo(0, y)\r\n ctx.lineTo(canvas.width, y)\r\n ctx.stroke()\r\n }\r\n \r\n const verticalSpacing = gridSize * 1.5\r\n // Render extra vertical grid lines for seamless wrap\r\n const gridCols = Math.ceil(canvas.width / verticalSpacing) + 2\r\n for (let i = 0; i < gridCols; i++) {\r\n // Shift grid lines by offsetX for infinite left movement\r\n let x = i * verticalSpacing - offsetX % verticalSpacing - verticalSpacing\r\n // Wrap x for seamless effect\r\n x = ((x + gridCols * verticalSpacing) % (gridCols * verticalSpacing))\r\n ctx.beginPath()\r\n ctx.moveTo(x, canvas.height)\r\n ctx.lineTo(x + (x - canvas.width / 2) * 0.3, canvas.height * 0.3)\r\n ctx.stroke()\r\n }\r\n\r\n // Theme-aware connections with data flow\r\n ctx.lineWidth = 0.8\r\n dataNodes.forEach((node, i) => {\r\n node.connections.forEach(targetIndex => {\r\n const target = dataNodes[targetIndex]\r\n const pulse = (Math.sin(time + node.pulse) + 1) / 2\r\n \r\n ctx.beginPath()\r\n ctx.moveTo(node.x, node.y)\r\n ctx.lineTo(target.x, target.y)\r\n ctx.strokeStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.1 + pulse * 0.08})`\r\n : `rgba(239, 146, 98, ${0.35 + pulse * 0.2})`\r\n ctx.stroke()\r\n\r\n // Animated data particles flowing along connections\r\n const flowProgress = (time * 0.3 + node.pulse) % 1\r\n const particleX = node.x + (target.x - node.x) * flowProgress\r\n const particleY = node.y + (target.y - node.y) * flowProgress\r\n\r\n ctx.beginPath()\r\n ctx.arc(particleX, particleY, 1.5, 0, Math.PI * 2)\r\n ctx.fillStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.5 + pulse * 0.3})`\r\n : `rgba(239, 146, 98, ${0.7 + pulse * 0.3})`\r\n ctx.fill()\r\n })\r\n })\r\n\r\n // Theme-aware nodes\r\n dataNodes.forEach(node => {\r\n const pulse = (Math.sin(time + node.pulse) + 1) / 2\r\n const size = 2.5 + pulse * 1\r\n \r\n ctx.beginPath()\r\n ctx.arc(node.x, node.y, size * 2, 0, Math.PI * 2)\r\n ctx.fillStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.12 + pulse * 0.1})`\r\n : `rgba(239, 146, 98, ${0.3 + pulse * 0.15})`\r\n ctx.fill()\r\n\r\n ctx.beginPath()\r\n ctx.arc(node.x, node.y, size, 0, Math.PI * 2)\r\n ctx.fillStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.55 + pulse * 0.25})`\r\n : `rgba(239, 146, 98, ${0.75 + pulse * 0.2})`\r\n ctx.fill()\r\n })\r\n\r\n animationFrameId = requestAnimationFrame(draw)\r\n }\r\n\r\n draw()\r\n\r\n return () => {\r\n cancelAnimationFrame(animationFrameId)\r\n window.removeEventListener('resize', resize)\r\n }\r\n }, [smoothMouseX, smoothMouseY, isDark])\r\n\r\n const { state: { runtimeConfig: { minioUrl } } } = useAppConfigContext()\r\n const assetsUrl = minioUrl || ''\r\n\r\n return (\r\n <>\r\n <div className=\"absolute top-0 right-0 inset-0 z-10 w-screen\">\r\n <img\r\n src={`${assetsUrl}/cdt-homepage/home-bg.png`}\r\n alt=\"Background\"\r\n className=\"object-cover opacity-10 w-screen\"\r\n style={{ filter: isDark ? 'invert(0)' : 'invert(1)' }}\r\n />\r\n </div>\r\n <div className=\"absolute w-screen inset-0 bg-gradient-to-br from-background/10 via-background/5 to-primary/5\" />\r\n <canvas\r\n ref={canvasRef}\r\n className=\"absolute inset-0 w-full h-full opacity-30\"\r\n style={{ mixBlendMode: isDark ? 'screen' : 'multiply' }}\r\n />\r\n <div className=\"absolute inset-0 bg-gradient-to-t from-background/30 via-background/10 to-transparent\" />\r\n </>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/core/components/ui/AnimatedBackground.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport { useEffect, useRef, useState } from 'react'\r\nimport { useMotionValue, useSpring } from 'framer-motion'\r\n\r\ninterface Props {\r\n theme?: 'light' | 'dark'\r\n assetsUrl?: string\r\n}\r\n\r\nexport default function AnimatedBackground({ theme, assetsUrl }: Props = {}) {\r\n const canvasRef = useRef<HTMLCanvasElement>(null)\r\n const mouseX = useMotionValue(0)\r\n const mouseY = useMotionValue(0)\r\n const smoothMouseX = useSpring(mouseX, { stiffness: 50, damping: 20 })\r\n const smoothMouseY = useSpring(mouseY, { stiffness: 50, damping: 20 })\r\n const [isDark, setIsDark] = useState(theme !== undefined ? theme === 'dark' : true)\r\n\r\n useEffect(() => {\r\n // If theme is controlled externally, just sync and skip the observer\r\n if (theme !== undefined) {\r\n setIsDark(theme === 'dark')\r\n return\r\n }\r\n\r\n // Auto-detect from document for standalone usage (hero section)\r\n setIsDark(document.documentElement.classList.contains('dark'))\r\n const observer = new MutationObserver(() => {\r\n setIsDark(document.documentElement.classList.contains('dark'))\r\n })\r\n observer.observe(document.documentElement, {\r\n attributes: true,\r\n attributeFilter: ['class']\r\n })\r\n return () => observer.disconnect()\r\n }, [theme])\r\n\r\n useEffect(() => {\r\n const handleMouseMove = (e: MouseEvent) => {\r\n mouseX.set(e.clientX)\r\n mouseY.set(e.clientY)\r\n }\r\n\r\n window.addEventListener('mousemove', handleMouseMove)\r\n return () => window.removeEventListener('mousemove', handleMouseMove)\r\n }, [mouseX, mouseY])\r\n\r\n useEffect(() => {\r\n const canvas = canvasRef.current\r\n if (!canvas) return\r\n\r\n const ctx = canvas.getContext('2d')\r\n if (!ctx) return\r\n\r\n const resize = () => {\r\n canvas.width = window.innerWidth\r\n canvas.height = window.innerHeight\r\n }\r\n resize()\r\n window.addEventListener('resize', resize)\r\n\r\n let animationFrameId: number\r\n let time = 0\r\n let offsetX = 0\r\n\r\n interface DataNode {\r\n x: number\r\n y: number\r\n baseX: number\r\n baseY: number\r\n connections: number[]\r\n pulse: number\r\n }\r\n\r\n const dataNodes: DataNode[] = []\r\n const gridSize = 100\r\n const nodeSpacing = 150\r\n // Render extra columns for seamless wrap\r\n const nodeCols = Math.ceil(canvas.width / nodeSpacing) + 2\r\n const nodeRows = Math.ceil(canvas.height / nodeSpacing)\r\n\r\n for (let row = 0; row < nodeRows; row++) {\r\n for (let col = 0; col < nodeCols; col++) {\r\n const index = row * nodeCols + col\r\n const baseX = col * nodeSpacing + nodeSpacing / 2\r\n const baseY = row * nodeSpacing + nodeSpacing / 2\r\n dataNodes.push({\r\n x: baseX,\r\n y: baseY,\r\n baseX,\r\n baseY,\r\n connections: [],\r\n pulse: (row + col) * 0.5\r\n })\r\n }\r\n }\r\n\r\n dataNodes.forEach((node, i) => {\r\n const col = i % nodeCols\r\n const row = Math.floor(i / nodeCols)\r\n if (col < nodeCols - 1) {\r\n node.connections.push(i + 1)\r\n }\r\n if (row < nodeRows - 1) {\r\n node.connections.push(i + nodeCols)\r\n }\r\n })\r\n\r\n const draw = () => {\r\n time += 0.008\r\n // Move left slowly\r\n offsetX += 0.1 // Lower for slower movement\r\n // Loop offsetX to avoid overflow and create infinite effect\r\n if (offsetX > nodeSpacing) offsetX -= nodeSpacing\r\n\r\n ctx.clearRect(0, 0, canvas.width, canvas.height)\r\n\r\n // Theme-aware colors\r\n const bgGradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height)\r\n if (isDark) {\r\n bgGradient.addColorStop(0, 'rgba(239, 145, 97, 0.025)')\r\n bgGradient.addColorStop(1, 'rgba(180, 90, 40, 0.02)')\r\n } else {\r\n bgGradient.addColorStop(0, 'rgba(239, 146, 98, 0.08)')\r\n bgGradient.addColorStop(1, 'rgba(239, 146, 98, 0.06)')\r\n }\r\n ctx.fillStyle = bgGradient\r\n ctx.fillRect(0, 0, canvas.width, canvas.height)\r\n\r\n // Animate node positions with floating effect\r\n dataNodes.forEach((node, i) => {\r\n const floatX = Math.sin(time * 0.3 + node.pulse) * 2\r\n const floatY = Math.cos(time * 0.2 + node.pulse) * 2\r\n // Shift node baseX by offsetX for infinite left movement\r\n let x = node.baseX - offsetX + floatX\r\n // Wrap node.x to the right if it goes off the left edge\r\n x = ((x + nodeCols * nodeSpacing) % (nodeCols * nodeSpacing))\r\n node.x = x\r\n node.y = node.baseY + floatY\r\n })\r\n\r\n // Theme-aware grid lines\r\n ctx.strokeStyle = isDark ? 'rgba(239, 145, 97, 0.08)' : 'rgba(239, 146, 98, 0.3)'\r\n ctx.lineWidth = 0.5\r\n \r\n for (let y = canvas.height; y > canvas.height * 0.3; y -= gridSize) {\r\n ctx.beginPath()\r\n ctx.moveTo(0, y)\r\n ctx.lineTo(canvas.width, y)\r\n ctx.stroke()\r\n }\r\n \r\n const verticalSpacing = gridSize * 1.5\r\n // Render extra vertical grid lines for seamless wrap\r\n const gridCols = Math.ceil(canvas.width / verticalSpacing) + 2\r\n for (let i = 0; i < gridCols; i++) {\r\n // Shift grid lines by offsetX for infinite left movement\r\n let x = i * verticalSpacing - offsetX % verticalSpacing - verticalSpacing\r\n // Wrap x for seamless effect\r\n x = ((x + gridCols * verticalSpacing) % (gridCols * verticalSpacing))\r\n ctx.beginPath()\r\n ctx.moveTo(x, canvas.height)\r\n ctx.lineTo(x + (x - canvas.width / 2) * 0.3, canvas.height * 0.3)\r\n ctx.stroke()\r\n }\r\n\r\n // Theme-aware connections with data flow\r\n ctx.lineWidth = 0.8\r\n dataNodes.forEach((node, i) => {\r\n node.connections.forEach(targetIndex => {\r\n const target = dataNodes[targetIndex]\r\n const pulse = (Math.sin(time + node.pulse) + 1) / 2\r\n \r\n ctx.beginPath()\r\n ctx.moveTo(node.x, node.y)\r\n ctx.lineTo(target.x, target.y)\r\n ctx.strokeStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.1 + pulse * 0.08})`\r\n : `rgba(239, 146, 98, ${0.35 + pulse * 0.2})`\r\n ctx.stroke()\r\n\r\n // Animated data particles flowing along connections\r\n const flowProgress = (time * 0.3 + node.pulse) % 1\r\n const particleX = node.x + (target.x - node.x) * flowProgress\r\n const particleY = node.y + (target.y - node.y) * flowProgress\r\n\r\n ctx.beginPath()\r\n ctx.arc(particleX, particleY, 1.5, 0, Math.PI * 2)\r\n ctx.fillStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.5 + pulse * 0.3})`\r\n : `rgba(239, 146, 98, ${0.7 + pulse * 0.3})`\r\n ctx.fill()\r\n })\r\n })\r\n\r\n // Theme-aware nodes\r\n dataNodes.forEach(node => {\r\n const pulse = (Math.sin(time + node.pulse) + 1) / 2\r\n const size = 2.5 + pulse * 1\r\n \r\n ctx.beginPath()\r\n ctx.arc(node.x, node.y, size * 2, 0, Math.PI * 2)\r\n ctx.fillStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.12 + pulse * 0.1})`\r\n : `rgba(239, 146, 98, ${0.3 + pulse * 0.15})`\r\n ctx.fill()\r\n\r\n ctx.beginPath()\r\n ctx.arc(node.x, node.y, size, 0, Math.PI * 2)\r\n ctx.fillStyle = isDark\r\n ? `rgba(239, 145, 97, ${0.55 + pulse * 0.25})`\r\n : `rgba(239, 146, 98, ${0.75 + pulse * 0.2})`\r\n ctx.fill()\r\n })\r\n\r\n animationFrameId = requestAnimationFrame(draw)\r\n }\r\n\r\n draw()\r\n\r\n return () => {\r\n cancelAnimationFrame(animationFrameId)\r\n window.removeEventListener('resize', resize)\r\n }\r\n }, [smoothMouseX, smoothMouseY, isDark])\r\n\r\n return (\r\n <>\r\n <div className=\"absolute top-0 right-0 inset-0 z-10 w-screen\">\r\n <img\r\n src={`${assetsUrl ?? ''}/cdt-homepage/home-bg.png`}\r\n alt=\"Background\"\r\n className=\"object-cover opacity-10 w-screen\"\r\n style={{ filter: isDark ? 'invert(0)' : 'invert(1)' }}\r\n />\r\n </div>\r\n <div className=\"absolute w-screen inset-0 bg-gradient-to-br from-background/10 via-background/5 to-primary/5\" />\r\n <canvas\r\n ref={canvasRef}\r\n className=\"absolute inset-0 w-full h-full opacity-30\"\r\n style={{ mixBlendMode: isDark ? 'screen' : 'multiply' }}\r\n />\r\n <div className=\"absolute inset-0 bg-gradient-to-t from-background/30 via-background/10 to-transparent\" />\r\n </>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
@@ -1,8 +1,10 @@
1
1
  import * as React from 'react';
2
+ import type { Organization } from '../../../types/dbTypes';
2
3
  interface InfoSidebarProps {
3
4
  children?: React.ReactNode;
4
5
  tabSelector?: React.ReactNode;
6
+ organization?: Organization;
5
7
  }
6
- export declare function InfoSidebarContainer({ children, tabSelector, }: InfoSidebarProps): React.JSX.Element;
8
+ export declare function InfoSidebarContainer({ children, tabSelector, organization, }: InfoSidebarProps): React.JSX.Element;
7
9
  export {};
8
10
  //# sourceMappingURL=Container.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Container.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/ui/InfoSidebar/Container.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B,UAAU,gBAAgB;IACxB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC9B;AAED,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,WAAW,GACZ,EAAE,gBAAgB,qBAqBlB"}
1
+ {"version":3,"file":"Container.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/ui/InfoSidebar/Container.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAO9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAE1D,UAAU,gBAAgB;IACxB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,WAAW,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC7B,YAAY,CAAC,EAAE,YAAY,CAAA;CAC5B;AAED,wBAAgB,oBAAoB,CAAC,EACnC,QAAQ,EACR,WAAW,EACX,YAAY,GACb,EAAE,gBAAgB,qBAsBlB"}
@@ -5,7 +5,8 @@ import { BuildingsContext } from "../../../store";
5
5
  import { Header } from "./Header";
6
6
  function InfoSidebarContainer({
7
7
  children,
8
- tabSelector
8
+ tabSelector,
9
+ organization
9
10
  }) {
10
11
  const { state: buildingState } = React.useContext(BuildingsContext);
11
12
  const { building: currentBuilding } = buildingState.buildings;
@@ -15,7 +16,8 @@ function InfoSidebarContainer({
15
16
  Header,
16
17
  {
17
18
  currentBuilding,
18
- loadingBuildingInfo
19
+ loadingBuildingInfo,
20
+ organization
19
21
  }
20
22
  ),
21
23
  tabSelector,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/core/components/ui/InfoSidebar/Container.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\n\r\n// Icons\r\nimport { BuildingsContext } from '../../../store'\r\n\r\n// New structured components\r\nimport { Header } from './Header'\r\n\r\ninterface InfoSidebarProps {\r\n children?: React.ReactNode\r\n tabSelector?: React.ReactNode\r\n}\r\n\r\nexport function InfoSidebarContainer({\r\n children,\r\n tabSelector,\r\n}: InfoSidebarProps) {\r\n const { state: buildingState } = React.useContext(BuildingsContext);\r\n const { building: currentBuilding } = buildingState.buildings;\r\n\r\n // State\r\n const [loadingBuildingInfo] = React.useState(false)\r\n\r\n return (\r\n <div className=\"w-[410px] flex flex-col h-screen bg-background border-r border-border \">\r\n <Header\r\n currentBuilding={currentBuilding}\r\n loadingBuildingInfo={loadingBuildingInfo}\r\n />\r\n\r\n {/* Tab Selector */}\r\n {tabSelector}\r\n\r\n {/* Tab Content */}\r\n {children}\r\n </div>\r\n )\r\n}\r\n"],"mappings":";AA6BI,SACE,KADF;AAxBJ,YAAY,WAAW;AAGvB,SAAS,wBAAwB;AAGjC,SAAS,cAAc;AAOhB,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,EAAE,OAAO,cAAc,IAAI,MAAM,WAAW,gBAAgB;AAClE,QAAM,EAAE,UAAU,gBAAgB,IAAI,cAAc;AAGpD,QAAM,CAAC,mBAAmB,IAAI,MAAM,SAAS,KAAK;AAElD,SACE,qBAAC,SAAI,WAAU,0EACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA;AAAA,IACF;AAAA,IAGC;AAAA,IAGE;AAAA,KACL;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../../../src/core/components/ui/InfoSidebar/Container.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\n\r\n// Icons\r\nimport { BuildingsContext } from '../../../store'\r\n\r\n// New structured components\r\nimport { Header } from './Header'\r\nimport type { Organization } from '../../../types/dbTypes'\r\n\r\ninterface InfoSidebarProps {\r\n children?: React.ReactNode\r\n tabSelector?: React.ReactNode\r\n organization?: Organization\r\n}\r\n\r\nexport function InfoSidebarContainer({\r\n children,\r\n tabSelector,\r\n organization,\r\n}: InfoSidebarProps) {\r\n const { state: buildingState } = React.useContext(BuildingsContext);\r\n const { building: currentBuilding } = buildingState.buildings;\r\n\r\n // State\r\n const [loadingBuildingInfo] = React.useState(false)\r\n\r\n return (\r\n <div className=\"w-[410px] flex flex-col h-screen bg-background border-r border-border \">\r\n <Header\r\n currentBuilding={currentBuilding}\r\n loadingBuildingInfo={loadingBuildingInfo}\r\n organization={organization}\r\n />\r\n\r\n {/* Tab Selector */}\r\n {tabSelector}\r\n\r\n {/* Tab Content */}\r\n {children}\r\n </div>\r\n )\r\n}\r\n"],"mappings":";AAgCI,SACE,KADF;AA3BJ,YAAY,WAAW;AAGvB,SAAS,wBAAwB;AAGjC,SAAS,cAAc;AAShB,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,EAAE,OAAO,cAAc,IAAI,MAAM,WAAW,gBAAgB;AAClE,QAAM,EAAE,UAAU,gBAAgB,IAAI,cAAc;AAGpD,QAAM,CAAC,mBAAmB,IAAI,MAAM,SAAS,KAAK;AAElD,SACE,qBAAC,SAAI,WAAU,0EACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA,QACA;AAAA;AAAA,IACF;AAAA,IAGC;AAAA,IAGE;AAAA,KACL;AAEJ;","names":[]}
@@ -1,9 +1,10 @@
1
1
  import * as React from 'react';
2
- import type { Building } from '../../../types/dbTypes';
2
+ import type { Building, Organization } from '../../../types/dbTypes';
3
3
  interface HeaderProps {
4
4
  currentBuilding: Building | null;
5
5
  loadingBuildingInfo: boolean;
6
+ organization?: Organization;
6
7
  }
7
- export declare function Header({ currentBuilding, loadingBuildingInfo, }: HeaderProps): React.JSX.Element;
8
+ export declare function Header({ currentBuilding, loadingBuildingInfo, organization, }: HeaderProps): React.JSX.Element;
8
9
  export {};
9
10
  //# sourceMappingURL=Header.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/ui/InfoSidebar/Header.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAA;AAStD,UAAU,WAAW;IACnB,eAAe,EAAE,QAAQ,GAAG,IAAI,CAAA;IAChC,mBAAmB,EAAE,OAAO,CAAA;CAC7B;AAED,wBAAgB,MAAM,CAAC,EACrB,eAAe,EACf,mBAAmB,GAEpB,EAAE,WAAW,qBA2Db"}
1
+ {"version":3,"file":"Header.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/ui/InfoSidebar/Header.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAQpE,UAAU,WAAW;IACnB,eAAe,EAAE,QAAQ,GAAG,IAAI,CAAA;IAChC,mBAAmB,EAAE,OAAO,CAAA;IAC5B,YAAY,CAAC,EAAE,YAAY,CAAA;CAC5B;AAED,wBAAgB,MAAM,CAAC,EACrB,eAAe,EACf,mBAAmB,EACnB,YAAY,GACb,EAAE,WAAW,qBA0Db"}
@@ -5,20 +5,19 @@ import { useTranslations } from "next-intl";
5
5
  import { LoadingSpinner } from "../LoadingSpinner";
6
6
  import { useSidebar } from "../Sidebar";
7
7
  import { MapContext } from "../../../store";
8
- import { useAppConfigContext } from "../../../store/AppConfig/context";
9
8
  import { Button } from "../Button";
10
9
  import * as LR from "lucide-react";
11
10
  function Header({
12
11
  currentBuilding,
13
- loadingBuildingInfo
12
+ loadingBuildingInfo,
13
+ organization
14
14
  }) {
15
- var _a, _b;
15
+ var _a;
16
16
  const t = useTranslations("SidebarHeader");
17
17
  const { setOpenInfo } = useSidebar();
18
18
  const { state: mapState } = React.useContext(MapContext);
19
- const { state: appConfigState } = useAppConfigContext();
20
- const countryCode = (_a = appConfigState.appConfig.organization) == null ? void 0 : _a.country;
21
- const countryName = countryCode ? (_b = new Intl.DisplayNames(["en"], { type: "region" }).of(countryCode.toUpperCase())) != null ? _b : countryCode : "";
19
+ const countryCode = organization == null ? void 0 : organization.country;
20
+ const countryName = countryCode ? (_a = new Intl.DisplayNames(["en"], { type: "region" }).of(countryCode.toUpperCase())) != null ? _a : countryCode : "";
22
21
  const formatSubdivision = (code) => {
23
22
  if (!code) return "";
24
23
  const normalized = code.replace("_", "-");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/core/components/ui/InfoSidebar/Header.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\nimport type { Building } from '../../../types/dbTypes'\r\nimport { useTranslations } from 'next-intl'\r\nimport { LoadingSpinner } from '../LoadingSpinner'\r\nimport { useSidebar } from '../Sidebar'\r\nimport { MapContext } from '../../../store'\r\nimport { useAppConfigContext } from '../../../store/AppConfig/context'\r\nimport { Button } from '../Button'\r\nimport * as LR from 'lucide-react'\r\n\r\ninterface HeaderProps {\r\n currentBuilding: Building | null\r\n loadingBuildingInfo: boolean\r\n}\r\n\r\nexport function Header({\r\n currentBuilding,\r\n loadingBuildingInfo,\r\n\r\n}: HeaderProps) {\r\n // Translation\r\n const t = useTranslations('SidebarHeader')\r\n const { setOpenInfo } = useSidebar()\r\n const { state: mapState } = React.useContext(MapContext)\r\n const { state: appConfigState } = useAppConfigContext()\r\n const countryCode = appConfigState.appConfig.organization?.country\r\n const countryName = countryCode\r\n ? (new Intl.DisplayNames(['en'], { type: 'region' }).of(countryCode.toUpperCase()) ?? countryCode)\r\n : ''\r\n\r\n // Strip country prefix from ISO 3166-2 codes: \"CA-ON\" → \"ON\", \"CA_ON\" → \"ON\", \"CAON\" → \"ON\"\r\n const formatSubdivision = (code: string | null | undefined): string => {\r\n if (!code) return ''\r\n const normalized = code.replace('_', '-')\r\n const withDash = normalized.includes('-') ? normalized : `${normalized.slice(0, 2)}-${normalized.slice(2)}`\r\n return withDash.split('-').slice(1).join('-')\r\n }\r\n const { currentLocation } = mapState.map\r\n\r\n return (\r\n <div className=\"p-4\">\r\n <div className=\"flex items-center\">\r\n <div className=\"flex items-center gap-2 w-full justify-between\">\r\n <div className=\"space-y-1 flex justify-center\">\r\n {loadingBuildingInfo\r\n ? (\r\n <div className=\"flex items-center gap-2\">\r\n <LoadingSpinner />\r\n <span className=\"text-sm font-medium text-muted-foreground\">{t('loadingText')}</span>\r\n </div>\r\n )\r\n : (\r\n <h2 className=\"text-sm font-semibold text-foreground\">\r\n {currentBuilding?.buildingName ||\r\n (\r\n currentLocation?.municipality\r\n ? (currentLocation?.countrySubdivision\r\n ? `${currentLocation.municipality}, ${formatSubdivision(currentLocation.countrySubdivision)}`\r\n : currentLocation.municipality)\r\n : (formatSubdivision(currentLocation?.countrySubdivision) || countryName)\r\n )\r\n }\r\n </h2>\r\n )}\r\n </div>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"group/sidebar-trigger opacity-70 hover:opacity-100 transition-opacity duration-200 hover:bg-transparent\"\r\n onClick={() => setOpenInfo(false)}\r\n title={t('closeInfoToggle')}\r\n >\r\n <LR.PanelLeftClose className=\"h-4 w-4\" />\r\n </Button>\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n}"],"mappings":";AAmDgB,SACE,KADF;AA9ChB,YAAY,WAAW;AAEvB,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAC3B,SAAS,kBAAkB;AAC3B,SAAS,2BAA2B;AACpC,SAAS,cAAc;AACvB,YAAY,QAAQ;AAOb,SAAS,OAAO;AAAA,EACrB;AAAA,EACA;AAEF,GAAgB;AAxBhB;AA0BE,QAAM,IAAI,gBAAgB,eAAe;AACzC,QAAM,EAAE,YAAY,IAAI,WAAW;AACnC,QAAM,EAAE,OAAO,SAAS,IAAI,MAAM,WAAW,UAAU;AACvD,QAAM,EAAE,OAAO,eAAe,IAAI,oBAAoB;AACtD,QAAM,eAAc,oBAAe,UAAU,iBAAzB,mBAAuC;AAC3D,QAAM,cAAc,eACf,SAAI,KAAK,aAAa,CAAC,IAAI,GAAG,EAAE,MAAM,SAAS,CAAC,EAAE,GAAG,YAAY,YAAY,CAAC,MAA9E,YAAmF,cACpF;AAGJ,QAAM,oBAAoB,CAAC,SAA4C;AACrE,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,aAAa,KAAK,QAAQ,KAAK,GAAG;AACxC,UAAM,WAAW,WAAW,SAAS,GAAG,IAAI,aAAa,GAAG,WAAW,MAAM,GAAG,CAAC,CAAC,IAAI,WAAW,MAAM,CAAC,CAAC;AACzG,WAAO,SAAS,MAAM,GAAG,EAAE,MAAM,CAAC,EAAE,KAAK,GAAG;AAAA,EAC9C;AACA,QAAM,EAAE,gBAAgB,IAAI,SAAS;AAErC,SACE,oBAAC,SAAI,WAAU,OACb,8BAAC,SAAI,WAAU,qBACb,+BAAC,SAAI,WAAU,kDACb;AAAA,wBAAC,SAAI,WAAU,iCACZ,gCAEG,qBAAC,SAAI,WAAU,2BACb;AAAA,0BAAC,kBAAe;AAAA,MAChB,oBAAC,UAAK,WAAU,6CAA6C,YAAE,aAAa,GAAE;AAAA,OAChF,IAGA,oBAAC,QAAG,WAAU,yCACX,8DAAiB,mBAEd,mDAAiB,iBACZ,mDAAiB,sBACd,GAAG,gBAAgB,YAAY,KAAK,kBAAkB,gBAAgB,kBAAkB,CAAC,KACzF,gBAAgB,eACnB,kBAAkB,mDAAiB,kBAAkB,KAAK,cAGrE,GAEN;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,MAAM,YAAY,KAAK;AAAA,QAChC,OAAO,EAAE,iBAAiB;AAAA,QAE1B,8BAAC,GAAG,gBAAH,EAAkB,WAAU,WAAU;AAAA;AAAA,IACzC;AAAA,KACF,GACF,GACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../../../src/core/components/ui/InfoSidebar/Header.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\nimport type { Building, Organization } from '../../../types/dbTypes'\r\nimport { useTranslations } from 'next-intl'\r\nimport { LoadingSpinner } from '../LoadingSpinner'\r\nimport { useSidebar } from '../Sidebar'\r\nimport { MapContext } from '../../../store'\r\nimport { Button } from '../Button'\r\nimport * as LR from 'lucide-react'\r\n\r\ninterface HeaderProps {\r\n currentBuilding: Building | null\r\n loadingBuildingInfo: boolean\r\n organization?: Organization\r\n}\r\n\r\nexport function Header({\r\n currentBuilding,\r\n loadingBuildingInfo,\r\n organization,\r\n}: HeaderProps) {\r\n // Translation\r\n const t = useTranslations('SidebarHeader')\r\n const { setOpenInfo } = useSidebar()\r\n const { state: mapState } = React.useContext(MapContext)\r\n const countryCode = organization?.country\r\n const countryName = countryCode\r\n ? (new Intl.DisplayNames(['en'], { type: 'region' }).of(countryCode.toUpperCase()) ?? countryCode)\r\n : ''\r\n\r\n // Strip country prefix from ISO 3166-2 codes: \"CA-ON\" → \"ON\", \"CA_ON\" → \"ON\", \"CAON\" → \"ON\"\r\n const formatSubdivision = (code: string | null | undefined): string => {\r\n if (!code) return ''\r\n const normalized = code.replace('_', '-')\r\n const withDash = normalized.includes('-') ? normalized : `${normalized.slice(0, 2)}-${normalized.slice(2)}`\r\n return withDash.split('-').slice(1).join('-')\r\n }\r\n const { currentLocation } = mapState.map\r\n\r\n return (\r\n <div className=\"p-4\">\r\n <div className=\"flex items-center\">\r\n <div className=\"flex items-center gap-2 w-full justify-between\">\r\n <div className=\"space-y-1 flex justify-center\">\r\n {loadingBuildingInfo\r\n ? (\r\n <div className=\"flex items-center gap-2\">\r\n <LoadingSpinner />\r\n <span className=\"text-sm font-medium text-muted-foreground\">{t('loadingText')}</span>\r\n </div>\r\n )\r\n : (\r\n <h2 className=\"text-sm font-semibold text-foreground\">\r\n {currentBuilding?.buildingName ||\r\n (\r\n currentLocation?.municipality\r\n ? (currentLocation?.countrySubdivision\r\n ? `${currentLocation.municipality}, ${formatSubdivision(currentLocation.countrySubdivision)}`\r\n : currentLocation.municipality)\r\n : (formatSubdivision(currentLocation?.countrySubdivision) || countryName)\r\n )\r\n }\r\n </h2>\r\n )}\r\n </div>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"group/sidebar-trigger opacity-70 hover:opacity-100 transition-opacity duration-200 hover:bg-transparent\"\r\n onClick={() => setOpenInfo(false)}\r\n title={t('closeInfoToggle')}\r\n >\r\n <LR.PanelLeftClose className=\"h-4 w-4\" />\r\n </Button>\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n}"],"mappings":";AAkDgB,SACE,KADF;AA7ChB,YAAY,WAAW;AAEvB,SAAS,uBAAuB;AAChC,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAC3B,SAAS,kBAAkB;AAC3B,SAAS,cAAc;AACvB,YAAY,QAAQ;AAQb,SAAS,OAAO;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AACF,GAAgB;AAxBhB;AA0BE,QAAM,IAAI,gBAAgB,eAAe;AACzC,QAAM,EAAE,YAAY,IAAI,WAAW;AACnC,QAAM,EAAE,OAAO,SAAS,IAAI,MAAM,WAAW,UAAU;AACvD,QAAM,cAAc,6CAAc;AAClC,QAAM,cAAc,eACf,SAAI,KAAK,aAAa,CAAC,IAAI,GAAG,EAAE,MAAM,SAAS,CAAC,EAAE,GAAG,YAAY,YAAY,CAAC,MAA9E,YAAmF,cACpF;AAGJ,QAAM,oBAAoB,CAAC,SAA4C;AACrE,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,aAAa,KAAK,QAAQ,KAAK,GAAG;AACxC,UAAM,WAAW,WAAW,SAAS,GAAG,IAAI,aAAa,GAAG,WAAW,MAAM,GAAG,CAAC,CAAC,IAAI,WAAW,MAAM,CAAC,CAAC;AACzG,WAAO,SAAS,MAAM,GAAG,EAAE,MAAM,CAAC,EAAE,KAAK,GAAG;AAAA,EAC9C;AACA,QAAM,EAAE,gBAAgB,IAAI,SAAS;AAErC,SACE,oBAAC,SAAI,WAAU,OACb,8BAAC,SAAI,WAAU,qBACb,+BAAC,SAAI,WAAU,kDACb;AAAA,wBAAC,SAAI,WAAU,iCACZ,gCAEG,qBAAC,SAAI,WAAU,2BACb;AAAA,0BAAC,kBAAe;AAAA,MAChB,oBAAC,UAAK,WAAU,6CAA6C,YAAE,aAAa,GAAE;AAAA,OAChF,IAGA,oBAAC,QAAG,WAAU,yCACX,8DAAiB,mBAEd,mDAAiB,iBACZ,mDAAiB,sBACd,GAAG,gBAAgB,YAAY,KAAK,kBAAkB,gBAAgB,kBAAkB,CAAC,KACzF,gBAAgB,eACnB,kBAAkB,mDAAiB,kBAAkB,KAAK,cAGrE,GAEN;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS,MAAM,YAAY,KAAK;AAAA,QAChC,OAAO,EAAE,iBAAiB;AAAA,QAE1B,8BAAC,GAAG,gBAAH,EAAkB,WAAU,WAAU;AAAA;AAAA,IACzC;AAAA,KACF,GACF,GACF;AAEJ;","names":[]}
@@ -1,3 +1,9 @@
1
1
  import * as React from 'react';
2
- export declare function InfoSidebar(): React.JSX.Element;
2
+ import { Organization } from '../../../types/dbTypes';
3
+ export declare function InfoSidebar({ minioBaseUrl, martinBaseUrl, organization, pointcloudApiUrl }: {
4
+ minioBaseUrl?: string;
5
+ martinBaseUrl?: string;
6
+ organization?: Organization;
7
+ pointcloudApiUrl?: string;
8
+ }): React.JSX.Element;
3
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/ui/InfoSidebar/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAgB9B,wBAAgB,WAAW,sBAW1B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/ui/InfoSidebar/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAWrD,wBAAgB,WAAW,CAAC,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,gBAAgB,EAAE,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,qBAWrM"}
@@ -12,13 +12,13 @@ const PointCloudSidebar = dynamic(
12
12
  () => import("../../viewers/pointcloud/src/PointCloudSidebar").then((m) => ({ default: m.PointCloudSidebar })),
13
13
  { ssr: false }
14
14
  );
15
- function InfoSidebar() {
15
+ function InfoSidebar({ minioBaseUrl, martinBaseUrl, organization, pointcloudApiUrl }) {
16
16
  const { state: menusState } = React.useContext(MenusContext);
17
17
  const { currentViewer } = menusState.menus;
18
18
  return /* @__PURE__ */ jsxs(Fragment, { children: [
19
- currentViewer === "map" && /* @__PURE__ */ jsx(MapSidebar, {}),
20
- currentViewer === "bim" && /* @__PURE__ */ jsx(BimSidebar, {}),
21
- currentViewer === "pointcloud" && /* @__PURE__ */ jsx(PointCloudSidebar, {})
19
+ currentViewer === "map" && /* @__PURE__ */ jsx(MapSidebar, { minioBaseUrl, martinBaseUrl, organization }),
20
+ currentViewer === "bim" && /* @__PURE__ */ jsx(BimSidebar, { minioBaseUrl, organization }),
21
+ currentViewer === "pointcloud" && /* @__PURE__ */ jsx(PointCloudSidebar, { pointcloudApiUrl, organization })
22
22
  ] });
23
23
  }
24
24
  export {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/core/components/ui/InfoSidebar/index.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\nimport dynamic from 'next/dynamic'\r\n\r\n// Icons\r\nimport { MenusContext } from '../../../store'\r\nimport { MapSidebar } from '../../viewers/map/src/MapSidebar'\r\n\r\nconst BimSidebar = dynamic(\r\n () => import('../../viewers/bim/src/BimSidebar/src').then(m => ({ default: m.BimSidebar })),\r\n { ssr: false },\r\n)\r\nconst PointCloudSidebar = dynamic(\r\n () => import('../../viewers/pointcloud/src/PointCloudSidebar').then(m => ({ default: m.PointCloudSidebar })),\r\n { ssr: false },\r\n)\r\n\r\nexport function InfoSidebar() {\r\n const { state: menusState } = React.useContext(MenusContext)\r\n const { currentViewer } = menusState.menus\r\n\r\n return (\r\n <>\r\n {currentViewer === 'map' && <MapSidebar />}\r\n {currentViewer === 'bim' && <BimSidebar />}\r\n {currentViewer === 'pointcloud' && <PointCloudSidebar />}\r\n </>\r\n )\r\n}"],"mappings":";AA0BI,mBAC8B,KAD9B;AArBJ,YAAY,WAAW;AACvB,OAAO,aAAa;AAGpB,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAE3B,MAAM,aAAa;AAAA,EACjB,MAAM,OAAO,sCAAsC,EAAE,KAAK,QAAM,EAAE,SAAS,EAAE,WAAW,EAAE;AAAA,EAC1F,EAAE,KAAK,MAAM;AACf;AACA,MAAM,oBAAoB;AAAA,EACxB,MAAM,OAAO,gDAAgD,EAAE,KAAK,QAAM,EAAE,SAAS,EAAE,kBAAkB,EAAE;AAAA,EAC3G,EAAE,KAAK,MAAM;AACf;AAEO,SAAS,cAAc;AAC5B,QAAM,EAAE,OAAO,WAAW,IAAI,MAAM,WAAW,YAAY;AAC3D,QAAM,EAAE,cAAc,IAAI,WAAW;AAErC,SACE,iCACG;AAAA,sBAAkB,SAAS,oBAAC,cAAW;AAAA,IACvC,kBAAkB,SAAS,oBAAC,cAAW;AAAA,IACvC,kBAAkB,gBAAgB,oBAAC,qBAAkB;AAAA,KACxD;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../../../src/core/components/ui/InfoSidebar/index.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\nimport dynamic from 'next/dynamic'\r\n\r\n// Icons\r\nimport { MenusContext } from '../../../store'\r\nimport { MapSidebar } from '../../viewers/map/src/MapSidebar'\r\nimport { Organization } from '../../../types/dbTypes'\r\n\r\nconst BimSidebar = dynamic(\r\n () => import('../../viewers/bim/src/BimSidebar/src').then(m => ({ default: m.BimSidebar })),\r\n { ssr: false },\r\n)\r\nconst PointCloudSidebar = dynamic(\r\n () => import('../../viewers/pointcloud/src/PointCloudSidebar').then(m => ({ default: m.PointCloudSidebar })),\r\n { ssr: false },\r\n)\r\n\r\nexport function InfoSidebar({ minioBaseUrl, martinBaseUrl, organization, pointcloudApiUrl }: { minioBaseUrl?: string; martinBaseUrl?: string; organization?: Organization; pointcloudApiUrl?: string }) {\r\n const { state: menusState } = React.useContext(MenusContext)\r\n const { currentViewer } = menusState.menus\r\n\r\n return (\r\n <>\r\n {currentViewer === 'map' && <MapSidebar minioBaseUrl={minioBaseUrl} martinBaseUrl={martinBaseUrl} organization={organization} />}\r\n {currentViewer === 'bim' && <BimSidebar minioBaseUrl={minioBaseUrl} organization={organization} />}\r\n {currentViewer === 'pointcloud' && <PointCloudSidebar pointcloudApiUrl={pointcloudApiUrl} organization={organization} />}\r\n </>\r\n )\r\n}"],"mappings":";AA2BI,mBAC8B,KAD9B;AAtBJ,YAAY,WAAW;AACvB,OAAO,aAAa;AAGpB,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAG3B,MAAM,aAAa;AAAA,EACjB,MAAM,OAAO,sCAAsC,EAAE,KAAK,QAAM,EAAE,SAAS,EAAE,WAAW,EAAE;AAAA,EAC1F,EAAE,KAAK,MAAM;AACf;AACA,MAAM,oBAAoB;AAAA,EACxB,MAAM,OAAO,gDAAgD,EAAE,KAAK,QAAM,EAAE,SAAS,EAAE,kBAAkB,EAAE;AAAA,EAC3G,EAAE,KAAK,MAAM;AACf;AAEO,SAAS,YAAY,EAAE,cAAc,eAAe,cAAc,iBAAiB,GAA8G;AACtM,QAAM,EAAE,OAAO,WAAW,IAAI,MAAM,WAAW,YAAY;AAC3D,QAAM,EAAE,cAAc,IAAI,WAAW;AAErC,SACE,iCACG;AAAA,sBAAkB,SAAS,oBAAC,cAAW,cAA4B,eAA8B,cAA4B;AAAA,IAC7H,kBAAkB,SAAS,oBAAC,cAAW,cAA4B,cAA4B;AAAA,IAC/F,kBAAkB,gBAAgB,oBAAC,qBAAkB,kBAAoC,cAA4B;AAAA,KACxH;AAEJ;","names":[]}
@@ -9,7 +9,8 @@ interface CollapsibleSensorItemProps {
9
9
  isVisible?: boolean;
10
10
  onMouseEnter?: () => void;
11
11
  onMouseLeave?: () => void;
12
+ minioBaseUrl?: string;
12
13
  }
13
- export declare function CollapsibleSensorItem({ sensor, sensorType, onAction, depth, isVisible, onMouseEnter, onMouseLeave }: CollapsibleSensorItemProps): React.JSX.Element;
14
+ export declare function CollapsibleSensorItem({ sensor, sensorType, onAction, depth, isVisible, onMouseEnter, onMouseLeave, minioBaseUrl }: CollapsibleSensorItemProps): React.JSX.Element;
14
15
  export {};
15
16
  //# sourceMappingURL=CollapsibleSensorItem.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CollapsibleSensorItem.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/ui/Sensors/CollapsibleSensorItem.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAS9B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAS3D,KAAK,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;AAExD,UAAU,0BAA0B;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,UAAU,CAAA;IACtB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACrD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,UAAU,EACV,QAAQ,EACR,KAAS,EACT,SAAgB,EAChB,YAAY,EACZ,YAAY,EACb,EAAE,0BAA0B,qBAqO5B"}
1
+ {"version":3,"file":"CollapsibleSensorItem.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/ui/Sensors/CollapsibleSensorItem.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAS9B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAO3D,KAAK,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;AAExD,UAAU,0BAA0B;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,UAAU,CAAA;IACtB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IACrD,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB;AAED,wBAAgB,qBAAqB,CAAC,EACpC,MAAM,EACN,UAAU,EACV,QAAQ,EACR,KAAS,EACT,SAAgB,EAChB,YAAY,EACZ,YAAY,EACZ,YAAY,EACb,EAAE,0BAA0B,qBAyO5B"}
@@ -14,7 +14,6 @@ import { useCoreHooks } from "../../../hooks/provider";
14
14
  import { useSession } from "next-auth/react";
15
15
  import { SensorChart } from "./SensorChart";
16
16
  import { SensorTagsSection } from "./SensorTagsSection";
17
- import { useAppConfigContext } from "../../../store/AppConfig/context";
18
17
  function CollapsibleSensorItem({
19
18
  sensor,
20
19
  sensorType,
@@ -22,7 +21,8 @@ function CollapsibleSensorItem({
22
21
  depth = 0,
23
22
  isVisible = true,
24
23
  onMouseEnter,
25
- onMouseLeave
24
+ onMouseLeave,
25
+ minioBaseUrl
26
26
  }) {
27
27
  var _a, _b, _c, _d;
28
28
  const t = useTranslations("SensorsSection");
@@ -30,8 +30,7 @@ function CollapsibleSensorItem({
30
30
  const [sensorData, setSensorData] = React.useState([]);
31
31
  const [isLoadingData, setIsLoadingData] = React.useState(false);
32
32
  const prevVisibleRef = React.useRef(isVisible);
33
- const { state: { runtimeConfig: { minioUrl } } } = useAppConfigContext();
34
- const dataPath = `${minioUrl != null ? minioUrl : ""}/sensors/${sensor.url}`;
33
+ const dataPath = minioBaseUrl ? `${minioBaseUrl}/sensors/${sensor.url}` : "";
35
34
  const typeIcon = (sensorType == null ? void 0 : sensorType.icon) || "Radio";
36
35
  const typeName = (_a = sensorType == null ? void 0 : sensorType.name.replace(/_/g, " ")) != null ? _a : "Unknown";
37
36
  const SensorIcon = LR[typeIcon] || LR.Radio;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/core/components/ui/Sensors/CollapsibleSensorItem.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\nimport { Button } from '../Button'\r\nimport { Badge } from '../Badge'\r\nimport { Avatar, AvatarFallback } from '../Avatar'\r\nimport { UserAvatar } from '../UserAvatar'\r\nimport * as LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport { format } from 'date-fns'\r\nimport { cn } from '../../../utils/utils'\r\nimport { Sensor, SensorType } from '../../../types/dbTypes'\r\nimport { useUser } from '../../../hooks/users/users'\r\nimport { useCoreHooks } from '../../../hooks/provider'\r\nimport { useSession } from 'next-auth/react'\r\nimport { SensorChart } from './SensorChart'\r\nimport { SensorTagsSection } from './SensorTagsSection'\r\nimport type { ChartConfig } from '../chart'\r\nimport { useAppConfigContext } from '../../../store/AppConfig/context'\r\n\r\ntype SensorAction = 'view' | 'edit' | 'delete' | 'reply'\r\n\r\ninterface CollapsibleSensorItemProps {\r\n sensor: Sensor\r\n sensorType: SensorType\r\n onAction?: (action: SensorAction, id: number) => void\r\n depth?: number\r\n isVisible?: boolean\r\n onMouseEnter?: () => void\r\n onMouseLeave?: () => void\r\n}\r\n\r\nexport function CollapsibleSensorItem({\r\n sensor,\r\n sensorType,\r\n onAction,\r\n depth = 0,\r\n isVisible = true,\r\n onMouseEnter,\r\n onMouseLeave\r\n}: CollapsibleSensorItemProps) {\r\n const t = useTranslations('SensorsSection')\r\n const [isExpanded, setIsExpanded] = React.useState(false)\r\n const [sensorData, setSensorData] = React.useState<{ time: string; value: number }[]>([])\r\n const [isLoadingData, setIsLoadingData] = React.useState(false)\r\n const prevVisibleRef = React.useRef(isVisible)\r\n\r\n const { state: { runtimeConfig: { minioUrl } } } = useAppConfigContext()\r\n const dataPath = `${minioUrl ?? ''}/sensors/${sensor.url}`\r\n const typeIcon = sensorType?.icon || 'Radio'\r\n const typeName = sensorType?.name.replace(/_/g, ' ') ?? 'Unknown' \r\n\r\n const SensorIcon = LR[typeIcon] || LR.Radio\r\n\r\n // Auto-collapse when visibility turns off\r\n React.useEffect(() => {\r\n const prevVisible = prevVisibleRef.current\r\n \r\n if (prevVisible && !isVisible) {\r\n // Just turned invisible - collapse\r\n setIsExpanded(false)\r\n }\r\n \r\n prevVisibleRef.current = isVisible\r\n }, [isVisible])\r\n\r\n // Fetch and parse CSV data\r\n React.useEffect(() => {\r\n const fetchCSVData = async () => {\r\n setIsLoadingData(true)\r\n try {\r\n const response = await fetch(dataPath)\r\n const csvText = await response.text()\r\n \r\n // Parse CSV: format is \"time,value\" (e.g., \"0:00:00,7.4\")\r\n const lines = csvText.trim().split('\\n')\r\n const parsed = lines.map(line => {\r\n const [time, valueStr] = line.split(',')\r\n return {\r\n time: time.trim(),\r\n value: parseFloat(valueStr.trim())\r\n }\r\n }).filter(item => !isNaN(item.value)) // Filter out any invalid entries\r\n \r\n setSensorData(parsed)\r\n } catch (error) {\r\n console.error('Error fetching sensor data:', error)\r\n // Fallback to empty array on error\r\n setSensorData([])\r\n } finally {\r\n setIsLoadingData(false)\r\n }\r\n }\r\n\r\n if (isExpanded) {\r\n fetchCSVData()\r\n }\r\n }, [dataPath, isExpanded])\r\n\r\n const chartConfig = {\r\n value: {\r\n label: typeName,\r\n color: \"hsl(var(--chart-1))\",\r\n },\r\n } satisfies ChartConfig\r\n\r\n const user = useSession().data?.user\r\n\r\n const indentClass = depth > 0 ? `ml-${Math.min(depth * 4, 12)}` : ''\r\n\r\n const { user: author } = useUser(String(sensor.authorId))\r\n let authorName: string | undefined = author?.name ?? 'Unknown User'\r\n\r\n const { sensor: sensorHooks } = useCoreHooks()\r\n const { updateSensor } = sensorHooks.useSensor(sensor.id)\r\n\r\n const handleAddTag = async (tag: string) => {\r\n const currentTags = sensor.tags ?? []\r\n await updateSensor({ tags: [...currentTags, tag] })\r\n }\r\n\r\n const handleDeleteTag = async (tag: string) => {\r\n const currentTags = sensor.tags ?? []\r\n await updateSensor({ tags: currentTags.filter(t => t !== tag) })\r\n }\r\n\r\n return (\r\n <div \r\n className={cn(\r\n \"border rounded-md overflow-hidden transition-opacity\",\r\n indentClass,\r\n !isVisible && \"opacity-70\"\r\n )}\r\n onMouseEnter={onMouseEnter}\r\n onMouseLeave={onMouseLeave}\r\n >\r\n {/* Sensor Header */}\r\n <div className=\"flex items-start justify-between p-3 hover:bg-accent/50 transition-colors\">\r\n <div className=\"flex items-start gap-3 flex-1 min-w-0\">\r\n <Button\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n className={cn(\"h-6 w-6 p-0 mt-1\", !isVisible && \"opacity-70\")}\r\n onClick={() => setIsExpanded(!isExpanded)}\r\n >\r\n <LR.ChevronRight\r\n className={cn(\r\n \"h-4 w-4 transition-transform\",\r\n isExpanded && \"rotate-90\"\r\n )}\r\n />\r\n </Button>\r\n\r\n <div className={cn(\r\n \"h-8 w-8 mt-1 rounded-full bg-primary flex items-center justify-center flex-shrink-0\",\r\n !isVisible && \"opacity-70 grayscale\"\r\n )}>\r\n <SensorIcon className={cn(\"h-4 w-4 text-primary-foreground\", !isVisible && \"opacity-70\")} />\r\n </div>\r\n\r\n <div className=\"flex-1 min-w-0\">\r\n <div className=\"flex items-center gap-2\">\r\n <span className={cn(\"text-sm font-medium\", isVisible ? \"text-foreground\" : \"text-muted-foreground\")}>\r\n {sensor.name}\r\n </span>\r\n {sensor.updatedAt !== sensor.createdAt && (\r\n <Badge variant=\"outline\" className=\"text-xs\">\r\n {t('edited')}\r\n </Badge>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Action Buttons */}\r\n {onAction && (\r\n <div className={cn(\"flex items-center gap-0 flex-shrink-0\", !isVisible && \"opacity-70\")}>\r\n {user?.id === String(sensor.authorId) && (\r\n <>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"h-8 w-8 p-0\"\r\n onClick={() => onAction('edit', sensor.id)}\r\n title={t('editSensor')}\r\n >\r\n <LR.Pencil className=\"h-4 w-4\" />\r\n </Button>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"h-8 w-8 p-0\"\r\n onClick={() => onAction('delete', sensor.id)}\r\n title={t('deleteSensor')}\r\n >\r\n <LR.Trash2 className=\"h-4 w-4\" />\r\n </Button>\r\n </>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Expanded Content */ }\r\n {\r\n isExpanded && (\r\n <div className=\"border-t bg-muted/30\">\r\n <div className=\"p-4 space-y-4\">\r\n {/* Sensor Information */}\r\n <div className=\"space-y-2\">\r\n <div className=\"flex items-center justify-between\">\r\n <span className=\"text-xs text-muted-foreground\">\r\n {format(new Date(sensor.createdAt), 'PPp')}\r\n </span>\r\n <Badge variant=\"secondary\" className=\"text-xs\">\r\n {typeName}\r\n </Badge>\r\n </div>\r\n \r\n <div className=\"grid grid-cols-2 gap-2 text-sm\">\r\n <div>\r\n <span className=\"text-muted-foreground\">Name:</span>\r\n <span className=\"ml-2 font-medium\">{sensor.name}</span>\r\n </div>\r\n <div>\r\n <span className=\"text-muted-foreground\">Format:</span>\r\n <span className=\"ml-2 font-medium\">{sensor.dataFormat}</span>\r\n </div>\r\n </div>\r\n\r\n {/* Author Information */}\r\n <div className=\"flex items-center gap-2 pt-2\">\r\n <span className=\"text-muted-foreground text-sm\">Author:</span>\r\n <Avatar className=\"h-5 w-5 rounded-full overflow-hidden\">\r\n <UserAvatar imageFileId={author?.imageFileId} name={authorName} />\r\n </Avatar>\r\n <span className=\"text-sm font-medium\">{authorName}</span>\r\n </div>\r\n </div>\r\n\r\n {/* Sensor Data Chart */}\r\n <SensorChart\r\n sensorData={sensorData}\r\n isLoadingData={isLoadingData}\r\n sensorName={sensor.name}\r\n sensorType={sensorType}\r\n updateFrequency={sensor.updateFrequency}\r\n chartConfig={chartConfig}\r\n />\r\n </div>\r\n <div>\r\n <SensorTagsSection\r\n tags={sensor.tags ?? []}\r\n onAdd={handleAddTag}\r\n onDelete={handleDeleteTag}\r\n translations={{\r\n addTag: t('addTag'),\r\n removeTag: t('removeTag'),\r\n cancel: t('cancel'),\r\n newTagPlaceholder: t('newTagPlaceholder'),\r\n }}\r\n />\r\n </div>\r\n\r\n </div>\r\n )\r\n }\r\n </div >\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","t"]}
1
+ {"version":3,"sources":["../../../../../src/core/components/ui/Sensors/CollapsibleSensorItem.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\nimport { Button } from '../Button'\r\nimport { Badge } from '../Badge'\r\nimport { Avatar, AvatarFallback } from '../Avatar'\r\nimport { UserAvatar } from '../UserAvatar'\r\nimport * as LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport { format } from 'date-fns'\r\nimport { cn } from '../../../utils/utils'\r\nimport { Sensor, SensorType } from '../../../types/dbTypes'\r\nimport { useUser } from '../../../hooks/users/users'\r\nimport { useCoreHooks } from '../../../hooks/provider'\r\nimport { useSession } from 'next-auth/react'\r\nimport { SensorChart } from './SensorChart'\r\nimport { SensorTagsSection } from './SensorTagsSection'\r\nimport type { ChartConfig } from '../chart'\r\ntype SensorAction = 'view' | 'edit' | 'delete' | 'reply'\r\n\r\ninterface CollapsibleSensorItemProps {\r\n sensor: Sensor\r\n sensorType: SensorType\r\n onAction?: (action: SensorAction, id: number) => void\r\n depth?: number\r\n isVisible?: boolean\r\n onMouseEnter?: () => void\r\n onMouseLeave?: () => void\r\n minioBaseUrl?: string\r\n}\r\n\r\nexport function CollapsibleSensorItem({\r\n sensor,\r\n sensorType,\r\n onAction,\r\n depth = 0,\r\n isVisible = true,\r\n onMouseEnter,\r\n onMouseLeave,\r\n minioBaseUrl\r\n}: CollapsibleSensorItemProps) {\r\n const t = useTranslations('SensorsSection')\r\n const [isExpanded, setIsExpanded] = React.useState(false)\r\n const [sensorData, setSensorData] = React.useState<{ time: string; value: number }[]>([])\r\n const [isLoadingData, setIsLoadingData] = React.useState(false)\r\n const prevVisibleRef = React.useRef(isVisible)\r\n\r\n //const { state: { runtimeConfig: { minioUrl } } } = useAppConfigContext()\r\n\r\n //const dataPath = `${minioUrl ?? ''}/sensors/${sensor.url}`\r\n const dataPath = minioBaseUrl\r\n ? `${minioBaseUrl}/sensors/${sensor.url}`\r\n : ''\r\n const typeIcon = sensorType?.icon || 'Radio'\r\n const typeName = sensorType?.name.replace(/_/g, ' ') ?? 'Unknown' \r\n\r\n const SensorIcon = LR[typeIcon] || LR.Radio\r\n\r\n // Auto-collapse when visibility turns off\r\n React.useEffect(() => {\r\n const prevVisible = prevVisibleRef.current\r\n \r\n if (prevVisible && !isVisible) {\r\n // Just turned invisible - collapse\r\n setIsExpanded(false)\r\n }\r\n \r\n prevVisibleRef.current = isVisible\r\n }, [isVisible])\r\n\r\n // Fetch and parse CSV data\r\n React.useEffect(() => {\r\n const fetchCSVData = async () => {\r\n setIsLoadingData(true)\r\n try {\r\n const response = await fetch(dataPath)\r\n const csvText = await response.text()\r\n \r\n // Parse CSV: format is \"time,value\" (e.g., \"0:00:00,7.4\")\r\n const lines = csvText.trim().split('\\n')\r\n const parsed = lines.map(line => {\r\n const [time, valueStr] = line.split(',')\r\n return {\r\n time: time.trim(),\r\n value: parseFloat(valueStr.trim())\r\n }\r\n }).filter(item => !isNaN(item.value)) // Filter out any invalid entries\r\n \r\n setSensorData(parsed)\r\n } catch (error) {\r\n console.error('Error fetching sensor data:', error)\r\n // Fallback to empty array on error\r\n setSensorData([])\r\n } finally {\r\n setIsLoadingData(false)\r\n }\r\n }\r\n\r\n if (isExpanded) {\r\n fetchCSVData()\r\n }\r\n }, [dataPath, isExpanded])\r\n\r\n const chartConfig = {\r\n value: {\r\n label: typeName,\r\n color: \"hsl(var(--chart-1))\",\r\n },\r\n } satisfies ChartConfig\r\n\r\n const user = useSession().data?.user\r\n\r\n const indentClass = depth > 0 ? `ml-${Math.min(depth * 4, 12)}` : ''\r\n\r\n const { user: author } = useUser(String(sensor.authorId))\r\n let authorName: string | undefined = author?.name ?? 'Unknown User'\r\n\r\n const { sensor: sensorHooks } = useCoreHooks()\r\n const { updateSensor } = sensorHooks.useSensor(sensor.id)\r\n\r\n const handleAddTag = async (tag: string) => {\r\n const currentTags = sensor.tags ?? []\r\n await updateSensor({ tags: [...currentTags, tag] })\r\n }\r\n\r\n const handleDeleteTag = async (tag: string) => {\r\n const currentTags = sensor.tags ?? []\r\n await updateSensor({ tags: currentTags.filter(t => t !== tag) })\r\n }\r\n\r\n return (\r\n <div \r\n className={cn(\r\n \"border rounded-md overflow-hidden transition-opacity\",\r\n indentClass,\r\n !isVisible && \"opacity-70\"\r\n )}\r\n onMouseEnter={onMouseEnter}\r\n onMouseLeave={onMouseLeave}\r\n >\r\n {/* Sensor Header */}\r\n <div className=\"flex items-start justify-between p-3 hover:bg-accent/50 transition-colors\">\r\n <div className=\"flex items-start gap-3 flex-1 min-w-0\">\r\n <Button\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n className={cn(\"h-6 w-6 p-0 mt-1\", !isVisible && \"opacity-70\")}\r\n onClick={() => setIsExpanded(!isExpanded)}\r\n >\r\n <LR.ChevronRight\r\n className={cn(\r\n \"h-4 w-4 transition-transform\",\r\n isExpanded && \"rotate-90\"\r\n )}\r\n />\r\n </Button>\r\n\r\n <div className={cn(\r\n \"h-8 w-8 mt-1 rounded-full bg-primary flex items-center justify-center flex-shrink-0\",\r\n !isVisible && \"opacity-70 grayscale\"\r\n )}>\r\n <SensorIcon className={cn(\"h-4 w-4 text-primary-foreground\", !isVisible && \"opacity-70\")} />\r\n </div>\r\n\r\n <div className=\"flex-1 min-w-0\">\r\n <div className=\"flex items-center gap-2\">\r\n <span className={cn(\"text-sm font-medium\", isVisible ? \"text-foreground\" : \"text-muted-foreground\")}>\r\n {sensor.name}\r\n </span>\r\n {sensor.updatedAt !== sensor.createdAt && (\r\n <Badge variant=\"outline\" className=\"text-xs\">\r\n {t('edited')}\r\n </Badge>\r\n )}\r\n </div>\r\n </div>\r\n </div>\r\n\r\n {/* Action Buttons */}\r\n {onAction && (\r\n <div className={cn(\"flex items-center gap-0 flex-shrink-0\", !isVisible && \"opacity-70\")}>\r\n {user?.id === String(sensor.authorId) && (\r\n <>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"h-8 w-8 p-0\"\r\n onClick={() => onAction('edit', sensor.id)}\r\n title={t('editSensor')}\r\n >\r\n <LR.Pencil className=\"h-4 w-4\" />\r\n </Button>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"h-8 w-8 p-0\"\r\n onClick={() => onAction('delete', sensor.id)}\r\n title={t('deleteSensor')}\r\n >\r\n <LR.Trash2 className=\"h-4 w-4\" />\r\n </Button>\r\n </>\r\n )}\r\n </div>\r\n )}\r\n </div>\r\n\r\n {/* Expanded Content */ }\r\n {\r\n isExpanded && (\r\n <div className=\"border-t bg-muted/30\">\r\n <div className=\"p-4 space-y-4\">\r\n {/* Sensor Information */}\r\n <div className=\"space-y-2\">\r\n <div className=\"flex items-center justify-between\">\r\n <span className=\"text-xs text-muted-foreground\">\r\n {format(new Date(sensor.createdAt), 'PPp')}\r\n </span>\r\n <Badge variant=\"secondary\" className=\"text-xs\">\r\n {typeName}\r\n </Badge>\r\n </div>\r\n \r\n <div className=\"grid grid-cols-2 gap-2 text-sm\">\r\n <div>\r\n <span className=\"text-muted-foreground\">Name:</span>\r\n <span className=\"ml-2 font-medium\">{sensor.name}</span>\r\n </div>\r\n <div>\r\n <span className=\"text-muted-foreground\">Format:</span>\r\n <span className=\"ml-2 font-medium\">{sensor.dataFormat}</span>\r\n </div>\r\n </div>\r\n\r\n {/* Author Information */}\r\n <div className=\"flex items-center gap-2 pt-2\">\r\n <span className=\"text-muted-foreground text-sm\">Author:</span>\r\n <Avatar className=\"h-5 w-5 rounded-full overflow-hidden\">\r\n <UserAvatar imageFileId={author?.imageFileId} name={authorName} />\r\n </Avatar>\r\n <span className=\"text-sm font-medium\">{authorName}</span>\r\n </div>\r\n </div>\r\n\r\n {/* Sensor Data Chart */}\r\n <SensorChart\r\n sensorData={sensorData}\r\n isLoadingData={isLoadingData}\r\n sensorName={sensor.name}\r\n sensorType={sensorType}\r\n updateFrequency={sensor.updateFrequency}\r\n chartConfig={chartConfig}\r\n />\r\n </div>\r\n <div>\r\n <SensorTagsSection\r\n tags={sensor.tags ?? []}\r\n onAdd={handleAddTag}\r\n onDelete={handleDeleteTag}\r\n translations={{\r\n addTag: t('addTag'),\r\n removeTag: t('removeTag'),\r\n cancel: t('cancel'),\r\n newTagPlaceholder: t('newTagPlaceholder'),\r\n }}\r\n />\r\n </div>\r\n\r\n </div>\r\n )\r\n }\r\n </div >\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","t"]}
@@ -1,5 +1,7 @@
1
1
  import * as React from 'react';
2
2
  /** Stable key used in state for sensors with no tags — locale-independent */
3
3
  export declare const UNTAGGED_TAG = "__untagged__";
4
- export declare function SensorsSection(): React.JSX.Element;
4
+ export declare function SensorsSection({ minioBaseUrl }: {
5
+ minioBaseUrl?: string;
6
+ }): React.JSX.Element;
5
7
  //# sourceMappingURL=SensorsSection.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SensorsSection.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/ui/Sensors/SensorsSection.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA0B9B,6EAA6E;AAC7E,eAAO,MAAM,YAAY,iBAAiB,CAAA;AAE1C,wBAAgB,cAAc,sBAgR7B"}
1
+ {"version":3,"file":"SensorsSection.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/ui/Sensors/SensorsSection.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA0B9B,6EAA6E;AAC7E,eAAO,MAAM,YAAY,iBAAiB,CAAA;AAE1C,wBAAgB,cAAc,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,qBAkRzE"}
@@ -23,7 +23,7 @@ import { useSensorTypes } from "../../../hooks/sensorTypes/sensorTypes";
23
23
  import * as LR from "lucide-react";
24
24
  import { stringToColour } from "../../viewers/map/utils/stringToColour";
25
25
  const UNTAGGED_TAG = "__untagged__";
26
- function SensorsSection() {
26
+ function SensorsSection({ minioBaseUrl }) {
27
27
  var _a, _b;
28
28
  const t = useTranslations("SensorsSection");
29
29
  const { dispatch: toolsDispatch } = React.useContext(ToolsContext);
@@ -209,6 +209,7 @@ function SensorsSection() {
209
209
  sensorType: type,
210
210
  onAction: handleSensorAction,
211
211
  isVisible: isTypeVisible,
212
+ minioBaseUrl,
212
213
  onMouseEnter: () => menusDispatch({ type: "SET_CURRENT_SENSOR_ID", payload: { currentSensorId: sensor.id } }),
213
214
  onMouseLeave: () => menusDispatch({ type: "SET_CURRENT_SENSOR_ID", payload: { currentSensorId: null } })
214
215
  },
@@ -242,6 +243,7 @@ function SensorsSection() {
242
243
  sensorType: type,
243
244
  onAction: handleSensorAction,
244
245
  isVisible: isTagVisible,
246
+ minioBaseUrl,
245
247
  onMouseEnter: () => menusDispatch({ type: "SET_CURRENT_SENSOR_ID", payload: { currentSensorId: sensor.id } }),
246
248
  onMouseLeave: () => menusDispatch({ type: "SET_CURRENT_SENSOR_ID", payload: { currentSensorId: null } })
247
249
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/core/components/ui/Sensors/SensorsSection.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\nimport { BuildingsContext, MenusContext, ToolsContext } from '../../../store'\r\nimport { Button } from '../Button'\r\nimport { CollapsibleSection } from '../CollapsibleSection'\r\nimport { SearchInput } from '../SearchInput'\r\nimport { DropdownMenu } from '../DropdownMenu'\r\nimport {\r\n DropdownMenuTrigger,\r\n DropdownMenuContent,\r\n DropdownMenuLabel,\r\n DropdownMenuSeparator,\r\n DropdownMenuRadioGroup,\r\n DropdownMenuRadioItem,\r\n} from '../DropdownMenu'\r\nimport { useTranslations } from 'next-intl'\r\nimport { CollapsibleSensorItem } from './CollapsibleSensorItem'\r\nimport { SensorsSectionSkeleton } from './SensorsSectionSkeleton'\r\nimport { useSensor, useSensors } from '../../../hooks/sensors/sensors'\r\nimport { toast } from 'sonner'\r\nimport type { Sensor } from '../../../types/dbTypes';\r\nimport { useSensorTypes } from '../../../hooks/sensorTypes/sensorTypes'\r\nimport * as LR from 'lucide-react'\r\nimport { stringToColour } from '../../viewers/map/utils/stringToColour'\r\n\r\ntype SensorAction = 'view' | 'edit' | 'delete'\r\n\r\n/** Stable key used in state for sensors with no tags — locale-independent */\r\nexport const UNTAGGED_TAG = '__untagged__'\r\n\r\nexport function SensorsSection() {\r\n // Translation\r\n const t = useTranslations('SensorsSection')\r\n\r\n const { dispatch: toolsDispatch } = React.useContext(ToolsContext)\r\n const { state: menusState, dispatch: menusDispatch } = React.useContext(MenusContext)\r\n const { currentViewer, visibleSensorTypes, visibleSensorTags } = menusState.menus\r\n\r\n const { sensors: allSensors }: { sensors: Sensor[] } = useSensors()\r\n const { sensorTypes, isLoading } = useSensorTypes()\r\n\r\n const {state: buildingsState} = React.useContext(BuildingsContext)\r\n const buildingId = buildingsState?.buildings?.building?.id || -1\r\n \r\n const [sensorToDelete, setSensorToDelete] = React.useState<number | null>(null)\r\n const [searchQuery, setSearchQuery] = React.useState('')\r\n const [groupBy, setGroupBy] = React.useState<'type' | 'tag'>('type')\r\n const { deleteSensor } = useSensor(sensorToDelete)\r\n\r\n const handleAddSensor = React.useCallback((currentSensorTypeId?: number) => {\r\n if (!currentViewer) return\r\n toolsDispatch({\r\n type: 'SET-TOOL',\r\n payload: {\r\n currentToolId:\r\n currentViewer === 'bim'\r\n ? 'bim-add-sensor'\r\n : currentViewer === 'map'\r\n ? 'map-add-sensor'\r\n : undefined,\r\n },\r\n })\r\n if (currentSensorTypeId) {\r\n menusDispatch({\r\n type: 'SET_CURRENT_SENSOR_TYPE_ID',\r\n payload: { currentSensorTypeId },\r\n })\r\n }\r\n }, [toolsDispatch, currentViewer])\r\n \r\n const handleSensorAction = React.useCallback((action: SensorAction, id: number) => {\r\n switch (action) {\r\n case 'view':\r\n console.log(`View sensor ${id}`)\r\n break\r\n case 'edit':\r\n console.log(`Edit sensor ${id}`)\r\n break\r\n case 'delete':\r\n toast.success(t('sensorDeleted'))\r\n setSensorToDelete(id)\r\n break\r\n default:\r\n break\r\n }\r\n }, [t])\r\n\r\n // Trigger deletion when sensorToDelete changes\r\n React.useEffect(() => {\r\n if (sensorToDelete !== null) {\r\n deleteSensor()\r\n setSensorToDelete(null)\r\n }\r\n }, [sensorToDelete, deleteSensor])\r\n\r\n const currentSensors: Sensor[] = allSensors.filter((sensor) => currentViewer === sensor.viewer && (!sensor.buildingId || sensor.buildingId === buildingId))\r\n \r\n // Filter sensors based on search query\r\n const filteredSensors = React.useMemo(() => {\r\n if (!searchQuery.trim()) return currentSensors\r\n\r\n const query = searchQuery.toLowerCase()\r\n return currentSensors.filter((sensor) => {\r\n const sensorTypeName =\r\n sensorTypes.find(type => type.id === sensor.typeId)?.name ?? ''\r\n return (\r\n sensor.name?.toLowerCase().includes(query) ||\r\n sensorTypeName.toLowerCase().includes(query)\r\n )\r\n })\r\n }, [currentSensors, searchQuery])\r\n \r\n const toggleSensorTypeVisibility = React.useCallback((sensorTypeId: number) => {\r\n menusDispatch({\r\n type: 'TOGGLE_SENSOR_TYPE_VISIBILITY',\r\n payload: {\r\n viewer: currentViewer,\r\n sensorTypeId: sensorTypeId,\r\n },\r\n })\r\n }, [currentViewer, menusDispatch])\r\n\r\n const handleGroupByChange = React.useCallback((newGroupBy: 'type' | 'tag') => {\r\n setGroupBy(newGroupBy)\r\n // Clear the opposing visibility state so markers from the old filter don't bleed through\r\n if (newGroupBy === 'tag') {\r\n menusDispatch({ type: 'HIDE_ALL_SENSORS_IN_VIEWER', payload: { viewer: currentViewer } })\r\n } else {\r\n menusDispatch({ type: 'HIDE_ALL_SENSOR_TAGS_IN_VIEWER', payload: { viewer: currentViewer } })\r\n }\r\n }, [currentViewer, menusDispatch])\r\n\r\n const toggleSensorTagVisibility = React.useCallback((tag: string) => {\r\n menusDispatch({\r\n type: 'TOGGLE_SENSOR_TAG_VISIBILITY',\r\n payload: {\r\n viewer: currentViewer,\r\n sensorTag: tag,\r\n },\r\n })\r\n }, [currentViewer, menusDispatch])\r\n\r\n // Group sensors by type, using sensorTypes as the source of truth for types\r\n const sensorsByType = React.useMemo(() => {\r\n const grouped: Record<string, Sensor[]> = {}\r\n sensorTypes.forEach(type => {\r\n grouped[type.name] = []\r\n })\r\n filteredSensors.forEach(sensor => {\r\n const type = sensorTypes.find(t => t.id === sensor.typeId)\r\n const typeName = type?.name ?? 'Other'\r\n if (!grouped[typeName]) {\r\n grouped[typeName] = []\r\n }\r\n grouped[typeName].push(sensor)\r\n })\r\n // Remove empty groups\r\n Object.keys(grouped).forEach(key => {\r\n if (grouped[key].length === 0) {\r\n delete grouped[key]\r\n }\r\n })\r\n return grouped\r\n }, [filteredSensors, sensorTypes])\r\n\r\n // Group sensors by tag\r\n const sensorsByTag = React.useMemo(() => {\r\n const grouped: Record<string, Sensor[]> = {}\r\n filteredSensors.forEach(sensor => {\r\n const tags = sensor.tags && sensor.tags.length > 0 ? sensor.tags : [UNTAGGED_TAG]\r\n tags.forEach(tag => {\r\n if (!grouped[tag]) grouped[tag] = []\r\n grouped[tag].push(sensor)\r\n })\r\n })\r\n return grouped\r\n }, [filteredSensors])\r\n\r\n return (\r\n <div className=\"flex-1 flex flex-col space-y-4 overflow-hidden\">\r\n <div className=\"px-4 flex items-center gap-2\">\r\n <SearchInput\r\n placeholder={t('searchSensors')}\r\n value={searchQuery}\r\n onChange={e => setSearchQuery(e.target.value)}\r\n />\r\n <DropdownMenu>\r\n <DropdownMenuTrigger asChild>\r\n <Button variant=\"outline\" size=\"icon\" title={t('filters')} className=\"flex-shrink-0\">\r\n <LR.Funnel size={16} />\r\n </Button>\r\n </DropdownMenuTrigger>\r\n <DropdownMenuContent align=\"end\">\r\n <DropdownMenuLabel>{t('groupBy')}</DropdownMenuLabel>\r\n <DropdownMenuSeparator />\r\n <DropdownMenuRadioGroup value={groupBy} onValueChange={v => handleGroupByChange(v as 'type' | 'tag')}>\r\n <DropdownMenuRadioItem value=\"type\">\r\n <LR.Layers className=\"mr-2 h-4 w-4\" />\r\n {t('groupByType')}\r\n </DropdownMenuRadioItem>\r\n <DropdownMenuRadioItem value=\"tag\">\r\n <LR.Tag className=\"mr-2 h-4 w-4\" />\r\n {t('groupByTag')}\r\n </DropdownMenuRadioItem>\r\n </DropdownMenuRadioGroup>\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n </div>\r\n {isLoading ? (\r\n <SensorsSectionSkeleton />\r\n ) : \r\n filteredSensors.length === 0 ? (\r\n <div className=\"p-4 text-muted-foreground text-sm flex flex-col items-center\">\r\n <div>{t('noSensorsFound')}</div>\r\n <Button\r\n className=\"mt-2 px-4 \"\r\n variant='outline'\r\n onClick={() => handleAddSensor()}\r\n >\r\n {t('addSensorTitle')}\r\n </Button>\r\n </div>\r\n ) : groupBy === 'type' ? (\r\n Object.entries(sensorsByType).map(([typeName, sensorsOfType]) => {\r\n const type = sensorTypes.find(t => t.name === typeName)\r\n const typeId = type?.id ?? -1\r\n\r\n const viewerTypes = visibleSensorTypes?.[currentViewer]\r\n const isTypeVisible = viewerTypes?.length > 0 && viewerTypes.includes(typeId)\r\n\r\n const sensorIcon = LR[type?.icon] || LR.Radio\r\n\r\n return (\r\n <CollapsibleSection\r\n key={typeName}\r\n title={typeName.replace(/_/g, ' ')}\r\n icon={sensorIcon}\r\n className=\"overflow-y-auto\"\r\n itemCount={sensorsOfType.length}\r\n onAddItem={() => handleAddSensor(typeId)}\r\n addItemTitle={t('addSensorTitle')}\r\n defaultOpen={false}\r\n switchVariant={{\r\n checked: isTypeVisible,\r\n onCheckedChange: () => toggleSensorTypeVisibility(typeId),\r\n }}\r\n >\r\n <div className=\"space-y-2 mx-2 pr-2\">\r\n {sensorsOfType.map((sensor) => (\r\n <CollapsibleSensorItem\r\n key={sensor.id}\r\n sensor={sensor}\r\n sensorType={type}\r\n onAction={handleSensorAction}\r\n isVisible={isTypeVisible}\r\n onMouseEnter={() => menusDispatch({ type: 'SET_CURRENT_SENSOR_ID', payload: { currentSensorId: sensor.id } })}\r\n onMouseLeave={() => menusDispatch({ type: 'SET_CURRENT_SENSOR_ID', payload: { currentSensorId: null } })}\r\n />\r\n ))}\r\n </div>\r\n </CollapsibleSection>\r\n )\r\n })\r\n ) : (\r\n Object.entries(sensorsByTag).map(([tag, sensorsOfTag]) => {\r\n const isTagVisible = visibleSensorTags?.[currentViewer]?.includes(tag) ?? false\r\n return (\r\n <CollapsibleSection\r\n key={tag}\r\n title={tag === UNTAGGED_TAG ? t('untagged') : tag}\r\n icon={LR.Tag}\r\n colour={stringToColour(tag, 'max')}\r\n className=\"overflow-y-auto\"\r\n itemCount={sensorsOfTag.length}\r\n defaultOpen={false}\r\n switchVariant={{\r\n checked: isTagVisible,\r\n onCheckedChange: () => toggleSensorTagVisibility(tag),\r\n }}\r\n >\r\n <div className=\"space-y-2 mx-2 pr-2\">\r\n {sensorsOfTag.map((sensor) => {\r\n const type = sensorTypes.find(tp => tp.id === sensor.typeId)\r\n return (\r\n <CollapsibleSensorItem\r\n key={sensor.id}\r\n sensor={sensor}\r\n sensorType={type}\r\n onAction={handleSensorAction}\r\n isVisible={isTagVisible}\r\n onMouseEnter={() => menusDispatch({ type: 'SET_CURRENT_SENSOR_ID', payload: { currentSensorId: sensor.id } })}\r\n onMouseLeave={() => menusDispatch({ type: 'SET_CURRENT_SENSOR_ID', payload: { currentSensorId: null } })}\r\n />\r\n )\r\n })}\r\n </div>\r\n </CollapsibleSection>\r\n )\r\n })\r\n )}\r\n </div>\r\n )\r\n}\r\n"],"mappings":";AAyLQ,cAeM,YAfN;AApLR,YAAY,WAAW;AACvB,SAAS,kBAAkB,cAAc,oBAAoB;AAC7D,SAAS,cAAc;AACvB,SAAS,0BAA0B;AACnC,SAAS,mBAAmB;AAC5B,SAAS,oBAAoB;AAC7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,uBAAuB;AAChC,SAAS,6BAA6B;AACtC,SAAS,8BAA8B;AACvC,SAAS,WAAW,kBAAkB;AACtC,SAAS,aAAa;AAEtB,SAAS,sBAAsB;AAC/B,YAAY,QAAQ;AACpB,SAAS,sBAAsB;AAKxB,MAAM,eAAe;AAErB,SAAS,iBAAiB;AAlCjC;AAoCE,QAAM,IAAI,gBAAgB,gBAAgB;AAE1C,QAAM,EAAE,UAAU,cAAc,IAAI,MAAM,WAAW,YAAY;AACjE,QAAM,EAAE,OAAO,YAAY,UAAU,cAAc,IAAI,MAAM,WAAW,YAAY;AACpF,QAAM,EAAE,eAAe,oBAAoB,kBAAkB,IAAI,WAAW;AAE5E,QAAM,EAAE,SAAS,WAAW,IAA2B,WAAW;AAClE,QAAM,EAAE,aAAa,UAAU,IAAI,eAAe;AAElD,QAAM,EAAC,OAAO,eAAc,IAAI,MAAM,WAAW,gBAAgB;AACjE,QAAM,eAAa,4DAAgB,cAAhB,mBAA2B,aAA3B,mBAAqC,OAAM;AAE9D,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,MAAM,SAAwB,IAAI;AAC9E,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAS,EAAE;AACvD,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAyB,MAAM;AACnE,QAAM,EAAE,aAAa,IAAI,UAAU,cAAc;AAEjD,QAAM,kBAAkB,MAAM,YAAY,CAAC,wBAAiC;AAC1E,QAAI,CAAC,cAAe;AAClB,kBAAc;AAAA,MACZ,MAAM;AAAA,MACN,SAAS;AAAA,QACP,eACE,kBAAkB,QACd,mBACA,kBAAkB,QAChB,mBACA;AAAA,MACV;AAAA,IACF,CAAC;AACD,QAAI,qBAAqB;AACvB,oBAAc;AAAA,QACZ,MAAM;AAAA,QACN,SAAS,EAAE,oBAAoB;AAAA,MACjC,CAAC;AAAA,IACH;AAAA,EACJ,GAAG,CAAC,eAAe,aAAa,CAAC;AAEjC,QAAM,qBAAqB,MAAM,YAAY,CAAC,QAAsB,OAAe;AACjF,YAAQ,QAAQ;AAAA,MACd,KAAK;AACH,gBAAQ,IAAI,eAAe,EAAE,EAAE;AAC/B;AAAA,MACF,KAAK;AACH,gBAAQ,IAAI,eAAe,EAAE,EAAE;AAC/B;AAAA,MACF,KAAK;AACC,cAAM,QAAQ,EAAE,eAAe,CAAC;AAChC,0BAAkB,EAAE;AACxB;AAAA,MACF;AACE;AAAA,IACJ;AAAA,EACF,GAAG,CAAC,CAAC,CAAC;AAGN,QAAM,UAAU,MAAM;AACpB,QAAI,mBAAmB,MAAM;AAC3B,mBAAa;AACb,wBAAkB,IAAI;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,gBAAgB,YAAY,CAAC;AAEjC,QAAM,iBAA2B,WAAW,OAAO,CAAC,WAAW,kBAAkB,OAAO,WAAW,CAAC,OAAO,cAAc,OAAO,eAAe,WAAW;AAG1J,QAAM,kBAAkB,MAAM,QAAQ,MAAM;AAC1C,QAAI,CAAC,YAAY,KAAK,EAAG,QAAO;AAEhC,UAAM,QAAQ,YAAY,YAAY;AACtC,WAAO,eAAe,OAAO,CAAC,WAAW;AA1G7C,UAAAA,KAAAC,KAAA;AA2GM,YAAM,kBACNA,OAAAD,MAAA,YAAY,KAAK,UAAQ,KAAK,OAAO,OAAO,MAAM,MAAlD,gBAAAA,IAAqD,SAArD,OAAAC,MAA6D;AAC7D,eACA,YAAO,SAAP,mBAAa,cAAc,SAAS,WACpC,eAAe,YAAY,EAAE,SAAS,KAAK;AAAA,IAE7C,CAAC;AAAA,EACH,GAAG,CAAC,gBAAgB,WAAW,CAAC;AAEhC,QAAM,6BAA6B,MAAM,YAAY,CAAC,iBAAyB;AAC7E,kBAAc;AAAA,MACZ,MAAM;AAAA,MACN,SAAS;AAAA,QACP,QAAQ;AAAA,QACR;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,eAAe,aAAa,CAAC;AAEjC,QAAM,sBAAsB,MAAM,YAAY,CAAC,eAA+B;AAC5E,eAAW,UAAU;AAErB,QAAI,eAAe,OAAO;AACxB,oBAAc,EAAE,MAAM,8BAA8B,SAAS,EAAE,QAAQ,cAAc,EAAE,CAAC;AAAA,IAC1F,OAAO;AACL,oBAAc,EAAE,MAAM,kCAAkC,SAAS,EAAE,QAAQ,cAAc,EAAE,CAAC;AAAA,IAC9F;AAAA,EACF,GAAG,CAAC,eAAe,aAAa,CAAC;AAEjC,QAAM,4BAA4B,MAAM,YAAY,CAAC,QAAgB;AACnE,kBAAc;AAAA,MACZ,MAAM;AAAA,MACN,SAAS;AAAA,QACP,QAAQ;AAAA,QACR,WAAW;AAAA,MACb;AAAA,IACF,CAAC;AAAA,EACH,GAAG,CAAC,eAAe,aAAa,CAAC;AAGjC,QAAM,gBAAgB,MAAM,QAAQ,MAAM;AACxC,UAAM,UAAoC,CAAC;AAC3C,gBAAY,QAAQ,UAAQ;AAC1B,cAAQ,KAAK,IAAI,IAAI,CAAC;AAAA,IACxB,CAAC;AACD,oBAAgB,QAAQ,YAAU;AAxJtC,UAAAD;AAyJM,YAAM,OAAO,YAAY,KAAK,CAAAE,OAAKA,GAAE,OAAO,OAAO,MAAM;AACzD,YAAM,YAAWF,MAAA,6BAAM,SAAN,OAAAA,MAAc;AAC/B,UAAI,CAAC,QAAQ,QAAQ,GAAG;AACtB,gBAAQ,QAAQ,IAAI,CAAC;AAAA,MACvB;AACA,cAAQ,QAAQ,EAAE,KAAK,MAAM;AAAA,IAC/B,CAAC;AAED,WAAO,KAAK,OAAO,EAAE,QAAQ,SAAO;AAClC,UAAI,QAAQ,GAAG,EAAE,WAAW,GAAG;AAC7B,eAAO,QAAQ,GAAG;AAAA,MACpB;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT,GAAG,CAAC,iBAAiB,WAAW,CAAC;AAGjC,QAAM,eAAe,MAAM,QAAQ,MAAM;AACvC,UAAM,UAAoC,CAAC;AAC3C,oBAAgB,QAAQ,YAAU;AAChC,YAAM,OAAO,OAAO,QAAQ,OAAO,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,YAAY;AAChF,WAAK,QAAQ,SAAO;AAClB,YAAI,CAAC,QAAQ,GAAG,EAAG,SAAQ,GAAG,IAAI,CAAC;AACnC,gBAAQ,GAAG,EAAE,KAAK,MAAM;AAAA,MAC1B,CAAC;AAAA,IACH,CAAC;AACD,WAAO;AAAA,EACT,GAAG,CAAC,eAAe,CAAC;AAEpB,SACE,qBAAC,SAAI,WAAU,kDACb;AAAA,yBAAC,SAAI,WAAU,gCACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,aAAa,EAAE,eAAe;AAAA,UAC9B,OAAO;AAAA,UACP,UAAU,OAAK,eAAe,EAAE,OAAO,KAAK;AAAA;AAAA,MAC9C;AAAA,MACA,qBAAC,gBACC;AAAA,4BAAC,uBAAoB,SAAO,MAC1B,8BAAC,UAAO,SAAQ,WAAU,MAAK,QAAO,OAAO,EAAE,SAAS,GAAG,WAAU,iBACnE,8BAAC,GAAG,QAAH,EAAU,MAAM,IAAI,GACvB,GACF;AAAA,QACA,qBAAC,uBAAoB,OAAM,OACzB;AAAA,8BAAC,qBAAmB,YAAE,SAAS,GAAE;AAAA,UACjC,oBAAC,yBAAsB;AAAA,UACrB,qBAAC,0BAAuB,OAAO,SAAS,eAAe,OAAK,oBAAoB,CAAmB,GACnG;AAAA,iCAAC,yBAAsB,OAAM,QAC3B;AAAA,kCAAC,GAAG,QAAH,EAAU,WAAU,gBAAe;AAAA,cACnC,EAAE,aAAa;AAAA,eAClB;AAAA,YACA,qBAAC,yBAAsB,OAAM,OAC3B;AAAA,kCAAC,GAAG,KAAH,EAAO,WAAU,gBAAe;AAAA,cAChC,EAAE,YAAY;AAAA,eACjB;AAAA,aACF;AAAA,WACF;AAAA,SACF;AAAA,OACF;AAAA,IACC,YACC,oBAAC,0BAAuB,IAE1B,gBAAgB,WAAW,IACzB,qBAAC,SAAI,WAAU,gEACb;AAAA,0BAAC,SAAK,YAAE,gBAAgB,GAAE;AAAA,MAC1B;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,SAAQ;AAAA,UACR,SAAS,MAAM,gBAAgB;AAAA,UAE9B,YAAE,gBAAgB;AAAA;AAAA,MACrB;AAAA,OACF,IACE,YAAY,SACd,OAAO,QAAQ,aAAa,EAAE,IAAI,CAAC,CAAC,UAAU,aAAa,MAAM;AAnOzE,UAAAA;AAoOU,YAAM,OAAO,YAAY,KAAK,CAAAE,OAAKA,GAAE,SAAS,QAAQ;AACtD,YAAM,UAASF,MAAA,6BAAM,OAAN,OAAAA,MAAY;AAE3B,YAAM,cAAc,yDAAqB;AACzC,YAAM,iBAAgB,2CAAa,UAAS,KAAK,YAAY,SAAS,MAAM;AAE5E,YAAM,aAAa,GAAG,6BAAM,IAAI,KAAK,GAAG;AAExC,aACE;AAAA,QAAC;AAAA;AAAA,UAEC,OAAO,SAAS,QAAQ,MAAM,GAAG;AAAA,UACjC,MAAM;AAAA,UACN,WAAU;AAAA,UACV,WAAW,cAAc;AAAA,UACzB,WAAW,MAAM,gBAAgB,MAAM;AAAA,UACvC,cAAc,EAAE,gBAAgB;AAAA,UAChC,aAAa;AAAA,UACb,eAAe;AAAA,YACb,SAAS;AAAA,YACT,iBAAiB,MAAM,2BAA2B,MAAM;AAAA,UAC1D;AAAA,UAEA,8BAAC,SAAI,WAAU,uBACZ,wBAAc,IAAI,CAAC,WAClB;AAAA,YAAC;AAAA;AAAA,cAEC;AAAA,cACA,YAAY;AAAA,cACZ,UAAU;AAAA,cACV,WAAW;AAAA,cACX,cAAc,MAAM,cAAc,EAAE,MAAM,yBAAyB,SAAS,EAAE,iBAAiB,OAAO,GAAG,EAAE,CAAC;AAAA,cAC5G,cAAc,MAAM,cAAc,EAAE,MAAM,yBAAyB,SAAS,EAAE,iBAAiB,KAAK,EAAE,CAAC;AAAA;AAAA,YANlG,OAAO;AAAA,UAOd,CACD,GACH;AAAA;AAAA,QAzBK;AAAA,MA0BP;AAAA,IAEJ,CAAC,IAED,OAAO,QAAQ,YAAY,EAAE,IAAI,CAAC,CAAC,KAAK,YAAY,MAAM;AA5QlE,UAAAA,KAAAC;AA6QU,YAAM,gBAAeA,OAAAD,MAAA,uDAAoB,mBAApB,gBAAAA,IAAoC,SAAS,SAA7C,OAAAC,MAAqD;AAC1E,aACA;AAAA,QAAC;AAAA;AAAA,UAEC,OAAO,QAAQ,eAAe,EAAE,UAAU,IAAI;AAAA,UAC9C,MAAM,GAAG;AAAA,UACT,QAAQ,eAAe,KAAK,KAAK;AAAA,UACjC,WAAU;AAAA,UACV,WAAW,aAAa;AAAA,UACxB,aAAa;AAAA,UACb,eAAe;AAAA,YACb,SAAS;AAAA,YACT,iBAAiB,MAAM,0BAA0B,GAAG;AAAA,UACtD;AAAA,UAEA,8BAAC,SAAI,WAAU,uBACZ,uBAAa,IAAI,CAAC,WAAW;AAC5B,kBAAM,OAAO,YAAY,KAAK,QAAM,GAAG,OAAO,OAAO,MAAM;AAC3D,mBACE;AAAA,cAAC;AAAA;AAAA,gBAEC;AAAA,gBACA,YAAY;AAAA,gBACZ,UAAU;AAAA,gBACV,WAAW;AAAA,gBACX,cAAc,MAAM,cAAc,EAAE,MAAM,yBAAyB,SAAS,EAAE,iBAAiB,OAAO,GAAG,EAAE,CAAC;AAAA,gBAC5G,cAAc,MAAM,cAAc,EAAE,MAAM,yBAAyB,SAAS,EAAE,iBAAiB,KAAK,EAAE,CAAC;AAAA;AAAA,cANlG,OAAO;AAAA,YAOd;AAAA,UAEJ,CAAC,GACH;AAAA;AAAA,QA3BK;AAAA,MA4BP;AAAA,IAEF,CAAC;AAAA,KAEL;AAEJ;","names":["_a","_b","t"]}
1
+ {"version":3,"sources":["../../../../../src/core/components/ui/Sensors/SensorsSection.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\nimport { BuildingsContext, MenusContext, ToolsContext } from '../../../store'\r\nimport { Button } from '../Button'\r\nimport { CollapsibleSection } from '../CollapsibleSection'\r\nimport { SearchInput } from '../SearchInput'\r\nimport { DropdownMenu } from '../DropdownMenu'\r\nimport {\r\n DropdownMenuTrigger,\r\n DropdownMenuContent,\r\n DropdownMenuLabel,\r\n DropdownMenuSeparator,\r\n DropdownMenuRadioGroup,\r\n DropdownMenuRadioItem,\r\n} from '../DropdownMenu'\r\nimport { useTranslations } from 'next-intl'\r\nimport { CollapsibleSensorItem } from './CollapsibleSensorItem'\r\nimport { SensorsSectionSkeleton } from './SensorsSectionSkeleton'\r\nimport { useSensor, useSensors } from '../../../hooks/sensors/sensors'\r\nimport { toast } from 'sonner'\r\nimport type { Sensor } from '../../../types/dbTypes';\r\nimport { useSensorTypes } from '../../../hooks/sensorTypes/sensorTypes'\r\nimport * as LR from 'lucide-react'\r\nimport { stringToColour } from '../../viewers/map/utils/stringToColour'\r\n\r\ntype SensorAction = 'view' | 'edit' | 'delete'\r\n\r\n/** Stable key used in state for sensors with no tags — locale-independent */\r\nexport const UNTAGGED_TAG = '__untagged__'\r\n\r\nexport function SensorsSection({ minioBaseUrl }: { minioBaseUrl?: string }) {\r\n // Translation\r\n const t = useTranslations('SensorsSection')\r\n\r\n const { dispatch: toolsDispatch } = React.useContext(ToolsContext)\r\n const { state: menusState, dispatch: menusDispatch } = React.useContext(MenusContext)\r\n const { currentViewer, visibleSensorTypes, visibleSensorTags } = menusState.menus\r\n\r\n const { sensors: allSensors }: { sensors: Sensor[] } = useSensors()\r\n const { sensorTypes, isLoading } = useSensorTypes()\r\n\r\n const {state: buildingsState} = React.useContext(BuildingsContext)\r\n const buildingId = buildingsState?.buildings?.building?.id || -1\r\n \r\n const [sensorToDelete, setSensorToDelete] = React.useState<number | null>(null)\r\n const [searchQuery, setSearchQuery] = React.useState('')\r\n const [groupBy, setGroupBy] = React.useState<'type' | 'tag'>('type')\r\n const { deleteSensor } = useSensor(sensorToDelete)\r\n\r\n const handleAddSensor = React.useCallback((currentSensorTypeId?: number) => {\r\n if (!currentViewer) return\r\n toolsDispatch({\r\n type: 'SET-TOOL',\r\n payload: {\r\n currentToolId:\r\n currentViewer === 'bim'\r\n ? 'bim-add-sensor'\r\n : currentViewer === 'map'\r\n ? 'map-add-sensor'\r\n : undefined,\r\n },\r\n })\r\n if (currentSensorTypeId) {\r\n menusDispatch({\r\n type: 'SET_CURRENT_SENSOR_TYPE_ID',\r\n payload: { currentSensorTypeId },\r\n })\r\n }\r\n }, [toolsDispatch, currentViewer])\r\n \r\n const handleSensorAction = React.useCallback((action: SensorAction, id: number) => {\r\n switch (action) {\r\n case 'view':\r\n console.log(`View sensor ${id}`)\r\n break\r\n case 'edit':\r\n console.log(`Edit sensor ${id}`)\r\n break\r\n case 'delete':\r\n toast.success(t('sensorDeleted'))\r\n setSensorToDelete(id)\r\n break\r\n default:\r\n break\r\n }\r\n }, [t])\r\n\r\n // Trigger deletion when sensorToDelete changes\r\n React.useEffect(() => {\r\n if (sensorToDelete !== null) {\r\n deleteSensor()\r\n setSensorToDelete(null)\r\n }\r\n }, [sensorToDelete, deleteSensor])\r\n\r\n const currentSensors: Sensor[] = allSensors.filter((sensor) => currentViewer === sensor.viewer && (!sensor.buildingId || sensor.buildingId === buildingId))\r\n \r\n // Filter sensors based on search query\r\n const filteredSensors = React.useMemo(() => {\r\n if (!searchQuery.trim()) return currentSensors\r\n\r\n const query = searchQuery.toLowerCase()\r\n return currentSensors.filter((sensor) => {\r\n const sensorTypeName =\r\n sensorTypes.find(type => type.id === sensor.typeId)?.name ?? ''\r\n return (\r\n sensor.name?.toLowerCase().includes(query) ||\r\n sensorTypeName.toLowerCase().includes(query)\r\n )\r\n })\r\n }, [currentSensors, searchQuery])\r\n \r\n const toggleSensorTypeVisibility = React.useCallback((sensorTypeId: number) => {\r\n menusDispatch({\r\n type: 'TOGGLE_SENSOR_TYPE_VISIBILITY',\r\n payload: {\r\n viewer: currentViewer,\r\n sensorTypeId: sensorTypeId,\r\n },\r\n })\r\n }, [currentViewer, menusDispatch])\r\n\r\n const handleGroupByChange = React.useCallback((newGroupBy: 'type' | 'tag') => {\r\n setGroupBy(newGroupBy)\r\n // Clear the opposing visibility state so markers from the old filter don't bleed through\r\n if (newGroupBy === 'tag') {\r\n menusDispatch({ type: 'HIDE_ALL_SENSORS_IN_VIEWER', payload: { viewer: currentViewer } })\r\n } else {\r\n menusDispatch({ type: 'HIDE_ALL_SENSOR_TAGS_IN_VIEWER', payload: { viewer: currentViewer } })\r\n }\r\n }, [currentViewer, menusDispatch])\r\n\r\n const toggleSensorTagVisibility = React.useCallback((tag: string) => {\r\n menusDispatch({\r\n type: 'TOGGLE_SENSOR_TAG_VISIBILITY',\r\n payload: {\r\n viewer: currentViewer,\r\n sensorTag: tag,\r\n },\r\n })\r\n }, [currentViewer, menusDispatch])\r\n\r\n // Group sensors by type, using sensorTypes as the source of truth for types\r\n const sensorsByType = React.useMemo(() => {\r\n const grouped: Record<string, Sensor[]> = {}\r\n sensorTypes.forEach(type => {\r\n grouped[type.name] = []\r\n })\r\n filteredSensors.forEach(sensor => {\r\n const type = sensorTypes.find(t => t.id === sensor.typeId)\r\n const typeName = type?.name ?? 'Other'\r\n if (!grouped[typeName]) {\r\n grouped[typeName] = []\r\n }\r\n grouped[typeName].push(sensor)\r\n })\r\n // Remove empty groups\r\n Object.keys(grouped).forEach(key => {\r\n if (grouped[key].length === 0) {\r\n delete grouped[key]\r\n }\r\n })\r\n return grouped\r\n }, [filteredSensors, sensorTypes])\r\n\r\n // Group sensors by tag\r\n const sensorsByTag = React.useMemo(() => {\r\n const grouped: Record<string, Sensor[]> = {}\r\n filteredSensors.forEach(sensor => {\r\n const tags = sensor.tags && sensor.tags.length > 0 ? sensor.tags : [UNTAGGED_TAG]\r\n tags.forEach(tag => {\r\n if (!grouped[tag]) grouped[tag] = []\r\n grouped[tag].push(sensor)\r\n })\r\n })\r\n return grouped\r\n }, [filteredSensors])\r\n\r\n return (\r\n <div className=\"flex-1 flex flex-col space-y-4 overflow-hidden\">\r\n <div className=\"px-4 flex items-center gap-2\">\r\n <SearchInput\r\n placeholder={t('searchSensors')}\r\n value={searchQuery}\r\n onChange={e => setSearchQuery(e.target.value)}\r\n />\r\n <DropdownMenu>\r\n <DropdownMenuTrigger asChild>\r\n <Button variant=\"outline\" size=\"icon\" title={t('filters')} className=\"flex-shrink-0\">\r\n <LR.Funnel size={16} />\r\n </Button>\r\n </DropdownMenuTrigger>\r\n <DropdownMenuContent align=\"end\">\r\n <DropdownMenuLabel>{t('groupBy')}</DropdownMenuLabel>\r\n <DropdownMenuSeparator />\r\n <DropdownMenuRadioGroup value={groupBy} onValueChange={v => handleGroupByChange(v as 'type' | 'tag')}>\r\n <DropdownMenuRadioItem value=\"type\">\r\n <LR.Layers className=\"mr-2 h-4 w-4\" />\r\n {t('groupByType')}\r\n </DropdownMenuRadioItem>\r\n <DropdownMenuRadioItem value=\"tag\">\r\n <LR.Tag className=\"mr-2 h-4 w-4\" />\r\n {t('groupByTag')}\r\n </DropdownMenuRadioItem>\r\n </DropdownMenuRadioGroup>\r\n </DropdownMenuContent>\r\n </DropdownMenu>\r\n </div>\r\n {isLoading ? (\r\n <SensorsSectionSkeleton />\r\n ) : \r\n filteredSensors.length === 0 ? (\r\n <div className=\"p-4 text-muted-foreground text-sm flex flex-col items-center\">\r\n <div>{t('noSensorsFound')}</div>\r\n <Button\r\n className=\"mt-2 px-4 \"\r\n variant='outline'\r\n onClick={() => handleAddSensor()}\r\n >\r\n {t('addSensorTitle')}\r\n </Button>\r\n </div>\r\n ) : groupBy === 'type' ? (\r\n Object.entries(sensorsByType).map(([typeName, sensorsOfType]) => {\r\n const type = sensorTypes.find(t => t.name === typeName)\r\n const typeId = type?.id ?? -1\r\n\r\n const viewerTypes = visibleSensorTypes?.[currentViewer]\r\n const isTypeVisible = viewerTypes?.length > 0 && viewerTypes.includes(typeId)\r\n\r\n const sensorIcon = LR[type?.icon] || LR.Radio\r\n\r\n return (\r\n <CollapsibleSection\r\n key={typeName}\r\n title={typeName.replace(/_/g, ' ')}\r\n icon={sensorIcon}\r\n className=\"overflow-y-auto\"\r\n itemCount={sensorsOfType.length}\r\n onAddItem={() => handleAddSensor(typeId)}\r\n addItemTitle={t('addSensorTitle')}\r\n defaultOpen={false}\r\n switchVariant={{\r\n checked: isTypeVisible,\r\n onCheckedChange: () => toggleSensorTypeVisibility(typeId),\r\n }}\r\n >\r\n <div className=\"space-y-2 mx-2 pr-2\">\r\n {sensorsOfType.map((sensor) => (\r\n <CollapsibleSensorItem\r\n key={sensor.id}\r\n sensor={sensor}\r\n sensorType={type}\r\n onAction={handleSensorAction}\r\n isVisible={isTypeVisible}\r\n minioBaseUrl={minioBaseUrl}\r\n onMouseEnter={() => menusDispatch({ type: 'SET_CURRENT_SENSOR_ID', payload: { currentSensorId: sensor.id } })}\r\n onMouseLeave={() => menusDispatch({ type: 'SET_CURRENT_SENSOR_ID', payload: { currentSensorId: null } })}\r\n />\r\n ))}\r\n </div>\r\n </CollapsibleSection>\r\n )\r\n })\r\n ) : (\r\n Object.entries(sensorsByTag).map(([tag, sensorsOfTag]) => {\r\n const isTagVisible = visibleSensorTags?.[currentViewer]?.includes(tag) ?? false\r\n return (\r\n <CollapsibleSection\r\n key={tag}\r\n title={tag === UNTAGGED_TAG ? t('untagged') : tag}\r\n icon={LR.Tag}\r\n colour={stringToColour(tag, 'max')}\r\n className=\"overflow-y-auto\"\r\n itemCount={sensorsOfTag.length}\r\n defaultOpen={false}\r\n switchVariant={{\r\n checked: isTagVisible,\r\n onCheckedChange: () => toggleSensorTagVisibility(tag),\r\n }}\r\n >\r\n <div className=\"space-y-2 mx-2 pr-2\">\r\n {sensorsOfTag.map((sensor) => {\r\n const type = sensorTypes.find(tp => tp.id === sensor.typeId)\r\n return (\r\n <CollapsibleSensorItem\r\n key={sensor.id}\r\n sensor={sensor}\r\n sensorType={type}\r\n onAction={handleSensorAction}\r\n isVisible={isTagVisible}\r\n minioBaseUrl={minioBaseUrl}\r\n onMouseEnter={() => menusDispatch({ type: 'SET_CURRENT_SENSOR_ID', payload: { currentSensorId: sensor.id } })}\r\n onMouseLeave={() => menusDispatch({ type: 'SET_CURRENT_SENSOR_ID', payload: { currentSensorId: null } })}\r\n />\r\n )\r\n })}\r\n </div>\r\n </CollapsibleSection>\r\n )\r\n })\r\n )}\r\n </div>\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","_b","t"]}