@collabdt/core 0.0.55 → 0.0.57
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.
- package/dist/core/components/AppSidebarContent.d.ts +2 -1
- package/dist/core/components/AppSidebarContent.d.ts.map +1 -1
- package/dist/core/components/AppSidebarContent.js +8 -5
- package/dist/core/components/AppSidebarContent.js.map +1 -1
- package/dist/core/components/Toolbar.d.ts +7 -1
- package/dist/core/components/Toolbar.d.ts.map +1 -1
- package/dist/core/components/Toolbar.js +3 -3
- package/dist/core/components/Toolbar.js.map +1 -1
- package/dist/core/components/TopNavigationBar.d.ts +6 -1
- package/dist/core/components/TopNavigationBar.d.ts.map +1 -1
- package/dist/core/components/TopNavigationBar.js +2 -2
- package/dist/core/components/TopNavigationBar.js.map +1 -1
- package/dist/core/components/authentication/AuthPage.d.ts +2 -1
- package/dist/core/components/authentication/AuthPage.d.ts.map +1 -1
- package/dist/core/components/authentication/AuthPage.js +2 -3
- package/dist/core/components/authentication/AuthPage.js.map +1 -1
- package/dist/core/components/authentication/Signin.d.ts +6 -1
- package/dist/core/components/authentication/Signin.d.ts.map +1 -1
- package/dist/core/components/authentication/Signin.js +17 -6
- package/dist/core/components/authentication/Signin.js.map +1 -1
- package/dist/core/components/organizationConfig/src/organizationConfigContent.d.ts.map +1 -1
- package/dist/core/components/organizationConfig/src/organizationConfigContent.js +109 -36
- package/dist/core/components/organizationConfig/src/organizationConfigContent.js.map +1 -1
- package/dist/core/components/settings/index.d.ts +3 -1
- package/dist/core/components/settings/index.d.ts.map +1 -1
- package/dist/core/components/settings/index.js +2 -2
- package/dist/core/components/settings/index.js.map +1 -1
- package/dist/core/components/settings/src/AccountSettingsPanel.d.ts.map +1 -1
- package/dist/core/components/settings/src/AccountSettingsPanel.js +9 -2
- package/dist/core/components/settings/src/AccountSettingsPanel.js.map +1 -1
- package/dist/core/components/settings/src/OrganizationSettingsPanel.d.ts +5 -1
- package/dist/core/components/settings/src/OrganizationSettingsPanel.d.ts.map +1 -1
- package/dist/core/components/settings/src/OrganizationSettingsPanel.js +7 -3
- package/dist/core/components/settings/src/OrganizationSettingsPanel.js.map +1 -1
- package/dist/core/components/settings/src/SettingsContent.d.ts +2 -1
- package/dist/core/components/settings/src/SettingsContent.d.ts.map +1 -1
- package/dist/core/components/settings/src/SettingsContent.js +2 -2
- package/dist/core/components/settings/src/SettingsContent.js.map +1 -1
- package/dist/core/components/support/BugReportDialog.d.ts +3 -2
- package/dist/core/components/support/BugReportDialog.d.ts.map +1 -1
- package/dist/core/components/support/BugReportDialog.js +71 -25
- package/dist/core/components/support/BugReportDialog.js.map +1 -1
- package/dist/core/components/support/FeatureRequestDialog.d.ts +3 -1
- package/dist/core/components/support/FeatureRequestDialog.d.ts.map +1 -1
- package/dist/core/components/support/FeatureRequestDialog.js +7 -4
- package/dist/core/components/support/FeatureRequestDialog.js.map +1 -1
- package/dist/core/components/support/SupportMenu.d.ts.map +1 -1
- package/dist/core/components/support/SupportMenu.js +1 -4
- package/dist/core/components/support/SupportMenu.js.map +1 -1
- package/dist/core/components/ui/AnimatedBackground.d.ts +2 -1
- package/dist/core/components/ui/AnimatedBackground.d.ts.map +1 -1
- package/dist/core/components/ui/AnimatedBackground.js +2 -3
- package/dist/core/components/ui/AnimatedBackground.js.map +1 -1
- package/dist/core/components/ui/AppSidebar.d.ts.map +1 -1
- package/dist/core/components/ui/AppSidebar.js +11 -11
- package/dist/core/components/ui/AppSidebar.js.map +1 -1
- package/dist/core/components/ui/InfoSidebar/Container.d.ts +3 -1
- package/dist/core/components/ui/InfoSidebar/Container.d.ts.map +1 -1
- package/dist/core/components/ui/InfoSidebar/Container.js +4 -2
- package/dist/core/components/ui/InfoSidebar/Container.js.map +1 -1
- package/dist/core/components/ui/InfoSidebar/Header.d.ts +3 -2
- package/dist/core/components/ui/InfoSidebar/Header.d.ts.map +1 -1
- package/dist/core/components/ui/InfoSidebar/Header.js +5 -6
- package/dist/core/components/ui/InfoSidebar/Header.js.map +1 -1
- package/dist/core/components/ui/InfoSidebar/index.d.ts +7 -1
- package/dist/core/components/ui/InfoSidebar/index.d.ts.map +1 -1
- package/dist/core/components/ui/InfoSidebar/index.js +4 -4
- package/dist/core/components/ui/InfoSidebar/index.js.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts +2 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js +3 -2
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js.map +1 -1
- package/dist/core/components/ui/Sensors/SensorsSection.d.ts +3 -1
- package/dist/core/components/ui/Sensors/SensorsSection.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/SensorsSection.js +3 -1
- package/dist/core/components/ui/Sensors/SensorsSection.js.map +1 -1
- package/dist/core/components/ui/Sidebar.d.ts +8 -0
- package/dist/core/components/ui/Sidebar.d.ts.map +1 -1
- package/dist/core/components/ui/Sidebar.js +21 -7
- package/dist/core/components/ui/Sidebar.js.map +1 -1
- package/dist/core/components/ui/ToolbarButton.js +18 -1
- package/dist/core/components/ui/ToolbarButton.js.map +1 -1
- package/dist/core/components/viewers/Data/DataMenu.d.ts +5 -1
- package/dist/core/components/viewers/Data/DataMenu.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/DataMenu.js +6 -3
- package/dist/core/components/viewers/Data/DataMenu.js.map +1 -1
- package/dist/core/components/viewers/Data/HeaderButtons.d.ts +3 -1
- package/dist/core/components/viewers/Data/HeaderButtons.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/HeaderButtons.js +6 -2
- package/dist/core/components/viewers/Data/HeaderButtons.js.map +1 -1
- package/dist/core/components/viewers/Data/buildingDetails/AddBuilding.d.ts +3 -1
- package/dist/core/components/viewers/Data/buildingDetails/AddBuilding.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/buildingDetails/AddBuilding.js +4 -2
- package/dist/core/components/viewers/Data/buildingDetails/AddBuilding.js.map +1 -1
- package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.d.ts +3 -1
- package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js +3 -1
- package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js.map +1 -1
- package/dist/core/components/viewers/Data/details/DetailHeader.d.ts +2 -1
- package/dist/core/components/viewers/Data/details/DetailHeader.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/details/DetailHeader.js +3 -5
- package/dist/core/components/viewers/Data/details/DetailHeader.js.map +1 -1
- package/dist/core/components/viewers/Viewer.d.ts +7 -1
- package/dist/core/components/viewers/Viewer.d.ts.map +1 -1
- package/dist/core/components/viewers/Viewer.js +6 -6
- package/dist/core/components/viewers/Viewer.js.map +1 -1
- package/dist/core/components/viewers/bim/BimToolbar.d.ts +3 -1
- package/dist/core/components/viewers/bim/BimToolbar.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/BimToolbar.js +2 -2
- package/dist/core/components/viewers/bim/BimToolbar.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.d.ts +3 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.js +2 -2
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/index.d.ts +5 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/index.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/index.js +3 -2
- package/dist/core/components/viewers/bim/src/BimSidebar/src/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts +3 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js +2 -2
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.d.ts +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.js +2 -2
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/bimToolbar.d.ts +3 -1
- package/dist/core/components/viewers/bim/src/tools/bimToolbar.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/bimToolbar.js +4 -2
- package/dist/core/components/viewers/bim/src/tools/bimToolbar.js.map +1 -1
- package/dist/core/components/viewers/map/MapViewer.d.ts +3 -1
- package/dist/core/components/viewers/map/MapViewer.d.ts.map +1 -1
- package/dist/core/components/viewers/map/MapViewer.js +2 -2
- package/dist/core/components/viewers/map/MapViewer.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/RowActions.d.ts +2 -1
- package/dist/core/components/viewers/map/datasets/RowActions.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/RowActions.js +5 -4
- package/dist/core/components/viewers/map/datasets/RowActions.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/index.d.ts +5 -1
- package/dist/core/components/viewers/map/datasets/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/index.js +15 -16
- package/dist/core/components/viewers/map/datasets/index.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/minioDatasets.d.ts +1 -1
- package/dist/core/components/viewers/map/datasets/src/minioDatasets.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/minioDatasets.js +3 -5
- package/dist/core/components/viewers/map/datasets/src/minioDatasets.js.map +1 -1
- package/dist/core/components/viewers/map/src/Geocoder.d.ts +3 -1
- package/dist/core/components/viewers/map/src/Geocoder.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/Geocoder.js +5 -1
- package/dist/core/components/viewers/map/src/Geocoder.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.d.ts +6 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.js +3 -3
- package/dist/core/components/viewers/map/src/MapLayers/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.d.ts +5 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js +6 -10
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.d.ts +3 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.js +2 -2
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/index.d.ts +6 -1
- package/dist/core/components/viewers/map/src/MapSidebar/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/index.js +5 -4
- package/dist/core/components/viewers/map/src/MapSidebar/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.d.ts +5 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.js +5 -8
- package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.d.ts +3 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.js +2 -2
- package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/index.d.ts +3 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/index.js +2 -2
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/LocationSettings.d.ts +3 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/LocationSettings.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/LocationSettings.js +4 -7
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/LocationSettings.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js +8 -8
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js.map +1 -1
- package/dist/core/components/viewers/map/src/tools/AddTools/AddToMap.d.ts +8 -1
- package/dist/core/components/viewers/map/src/tools/AddTools/AddToMap.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/tools/AddTools/AddToMap.js +8 -3
- package/dist/core/components/viewers/map/src/tools/AddTools/AddToMap.js.map +1 -1
- package/dist/core/components/viewers/map/src/tools/DatasetMapTool.d.ts +11 -1
- package/dist/core/components/viewers/map/src/tools/DatasetMapTool.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/tools/DatasetMapTool.js +5 -3
- package/dist/core/components/viewers/map/src/tools/DatasetMapTool.js.map +1 -1
- package/dist/core/components/viewers/map/src/tools/mapTools.d.ts +10 -1
- package/dist/core/components/viewers/map/src/tools/mapTools.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/tools/mapTools.js +5 -3
- package/dist/core/components/viewers/map/src/tools/mapTools.js.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/config.d.ts +14 -5
- package/dist/core/components/viewers/map/utils/geocoding/config.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/config.js +22 -11
- package/dist/core/components/viewers/map/utils/geocoding/config.js.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/index.js +2 -2
- package/dist/core/components/viewers/map/utils/geocoding/index.js.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/osm.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/osm.js +5 -4
- package/dist/core/components/viewers/map/utils/geocoding/osm.js.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/pelias.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/pelias.js +7 -5
- package/dist/core/components/viewers/map/utils/geocoding/pelias.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/PointCloudViewer.d.ts +3 -1
- package/dist/core/components/viewers/pointcloud/PointCloudViewer.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/PointCloudViewer.js +11 -12
- package/dist/core/components/viewers/pointcloud/PointCloudViewer.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.d.ts +3 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.js +37 -50
- package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.d.ts +3 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.js +5 -3
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.d.ts +2 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.js +8 -7
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.d.ts +2 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.js +22 -9
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/index.d.ts +5 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/index.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/index.js +3 -2
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/index.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.d.ts +3 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js +2 -2
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.d.ts +2 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.js +12 -22
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.js.map +1 -1
- package/dist/core/hooks/useCaptureScreenshot.d.ts +2 -0
- package/dist/core/hooks/useCaptureScreenshot.d.ts.map +1 -0
- package/dist/core/hooks/useCaptureScreenshot.js +63 -0
- package/dist/core/hooks/useCaptureScreenshot.js.map +1 -0
- package/dist/core/hooks/useGeocodingRuntimeConfig.d.ts +3 -0
- package/dist/core/hooks/useGeocodingRuntimeConfig.d.ts.map +1 -0
- package/dist/core/hooks/useGeocodingRuntimeConfig.js +17 -0
- package/dist/core/hooks/useGeocodingRuntimeConfig.js.map +1 -0
- package/dist/core/store/AppConfig/context.d.ts +15 -1
- package/dist/core/store/AppConfig/context.d.ts.map +1 -1
- package/dist/core/store/AppConfig/context.js +26 -5
- package/dist/core/store/AppConfig/context.js.map +1 -1
- package/dist/core/store/CombineProviders.d.ts +6 -1
- package/dist/core/store/CombineProviders.d.ts.map +1 -1
- package/dist/core/store/CombineProviders.js +4 -3
- package/dist/core/store/CombineProviders.js.map +1 -1
- package/dist/core/types/tools.d.ts +2 -1
- package/dist/core/types/tools.d.ts.map +1 -1
- package/dist/core/utils/imageUtils.d.ts.map +1 -1
- package/dist/core/utils/imageUtils.js +2 -1
- package/dist/core/utils/imageUtils.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/core/components/viewers/Viewer.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Dependencies\r\nimport * as React from 'react'\r\nimport dynamic from 'next/dynamic'\r\nimport { Loader2 } from 'lucide-react'\r\nimport { useSearchParams, useRouter, usePathname } from 'next/navigation'\r\nimport { ViewerNames } from '../../types'\r\nimport { BuildingsContext, MenusContext } from '../../store'\r\nimport { MapViewer } from './map/MapViewer'\r\n// Deep file import (not the ui barrel): the barrel re-exports heavy modules\r\n// (InfoSidebar, useFileUploadHandler, …) that would land in the eager map-route bundle.\r\nimport { SidebarTrigger } from '../ui/Sidebar'\r\nimport { UserSettings } from '../settings'\r\nimport { Toolbar } from '../Toolbar'\r\nimport { switchLanguage } from '../../utils/utils'\r\nimport { Organization } from '../../types/dbTypes'\r\n\r\n// Code-split the heavy viewers: BimViewer pulls in ~456 KB gzipped of\r\n// @thatopen/*, PointCloudViewer the Potree loader stack — loaded only when\r\n// selected, so map-only sessions never pay their cost. MapViewer stays static\r\n// because every user lands on it.\r\nconst BimViewer = dynamic(\r\n () => import('./bim/BimViewer').then(m => ({ default: m.BimViewer })),\r\n { ssr: false, loading: () => <ViewerLoadingFallback label=\"Loading BIM viewer…\" /> },\r\n)\r\nconst PointCloudViewer = dynamic(\r\n () => import('./pointcloud/PointCloudViewer').then(m => ({ default: m.PointCloudViewer })),\r\n { ssr: false, loading: () => <ViewerLoadingFallback label=\"Loading point cloud viewer…\" /> },\r\n)\r\n\r\n// DataMenu transitively imports BimViewer (via FilePreview), so keep it lazy\r\n// too — a static import would pull @thatopen + three/webgpu back into the eager\r\n// bundle. Only rendered for the data viewers, so map-only sessions skip it.\r\nconst DataMenu = dynamic(\r\n () => import('./Data/DataMenu').then(m => ({ default: m.DataMenu })),\r\n { ssr: false, loading: () => <ViewerLoadingFallback label=\"Loading data…\" /> },\r\n)\r\n\r\n// Styled to match the in-viewer loading card (see BimLoadingState): a soft\r\n// backdrop-blurred overlay with a bordered card, spinner + label. Uses only\r\n// Tailwind tokens + one lucide icon, so it adds no meaningful weight to the\r\n// eager map-route bundle (Viewer.tsx is statically imported).\r\nfunction ViewerLoadingFallback({ label }: { label: string }) {\r\n return (\r\n <div className=\"absolute inset-0 z-10 flex items-center justify-center bg-background/50 backdrop-blur-[1px]\">\r\n <div className=\"flex items-center gap-3 rounded-md border border-border bg-card px-5 py-4 shadow-sm\">\r\n <Loader2 className=\"h-5 w-5 animate-spin text-muted-foreground\" />\r\n <span className=\"text-foreground text-base font-medium font-['Inter'] leading-7\">{label}</span>\r\n </div>\r\n </div>\r\n )\r\n}\r\n\r\ninterface ViewerProps {\r\n organization: Organization\r\n}\r\n\r\nexport function Viewer({ organization }: ViewerProps) {\r\n\r\n const searchParams = useSearchParams()\r\n const viewer = (searchParams.get('viewer') as ViewerNames) || ViewerNames.map\r\n\r\n const { dispatch: menusDispatch, state: menusState } = React.useContext(MenusContext)\r\n const { state: buildingState } = React.useContext(BuildingsContext)\r\n // const { dispatch: appConfigDispatch } = React.useContext(AppConfigContext)\r\n const { building } = buildingState.buildings\r\n const { currentViewer } = menusState.menus\r\n const router = useRouter()\r\n const pathname = usePathname()\r\n const [isMounted, setIsMounted] = React.useState(false)\r\n\r\n // Use a ref to track if we're currently updating -> prevent circular updates\r\n const isUpdatingRef = React.useRef(false)\r\n\r\n const { appContent } = organization\r\n\r\n // Check if viewer is valid based on appContent\r\n const isViewerValid = appContent.length === 0 || appContent.includes(viewer)\r\n \r\n // Use default viewer (map) if current viewer is not valid\r\n const validViewer = isViewerValid ? viewer : ViewerNames.map\r\n\r\n // Update URL if viewer was not available for the organization\r\n React.useEffect(() => {\r\n if (isMounted && !isViewerValid && viewer !== ViewerNames.map) {\r\n const newSearchParams = new URLSearchParams(searchParams.toString())\r\n newSearchParams.delete('viewer')\r\n if (building?.id) {\r\n newSearchParams.set('buildingId', String(building.id))\r\n }\r\n router.replace(`${pathname}?${newSearchParams.toString()}`, { scroll: false })\r\n }\r\n }, [isMounted, isViewerValid, viewer, searchParams, pathname, router, building?.id])\r\n\r\n // On first mount, respond to URL\r\n React.useEffect(() => {\r\n if (!isMounted) {\r\n menusDispatch({\r\n type: 'SET_VIEWER',\r\n payload: { currentViewer: validViewer },\r\n })\r\n setIsMounted(true)\r\n }\r\n }, [isMounted, validViewer, menusDispatch])\r\n\r\n React.useEffect(() => {\r\n if (!organization) return\r\n const defaultLanguage = organization.languages?.[0] || 'En'\r\n if (defaultLanguage) switchLanguage(defaultLanguage)\r\n }, [organization])\r\n\r\n // Handle context changes (from sidebar, HeaderButtons, etc.)\r\n React.useEffect(() => {\r\n if (!isMounted || !currentViewer || currentViewer === validViewer || isUpdatingRef.current) {\r\n return\r\n }\r\n\r\n isUpdatingRef.current = true\r\n\r\n // Create URLSearchParams to preserve existing search params\r\n\r\n const newSearchParams = new URLSearchParams(searchParams.toString())\r\n newSearchParams.set('viewer', currentViewer)\r\n if (building?.id) {\r\n newSearchParams.set('buildingId', String(building.id))\r\n }\r\n\r\n\r\n router.replace(`${pathname}?${newSearchParams.toString()}`, { scroll: false })\r\n\r\n // Reset the flag after a brief delay to allow the navigation to complete\r\n setTimeout(() => {\r\n isUpdatingRef.current = false\r\n }, 100)\r\n }, [currentViewer, isMounted, pathname, router, viewer, searchParams])\r\n\r\n // Handle URL changes (direct navigation)\r\n React.useEffect(() => {\r\n if (isMounted && currentViewer !== validViewer && !isUpdatingRef.current) {\r\n isUpdatingRef.current = true\r\n\r\n menusDispatch({\r\n type: 'SET_VIEWER',\r\n payload: { currentViewer: validViewer },\r\n })\r\n\r\n // Reset the flag after a brief delay\r\n setTimeout(() => {\r\n isUpdatingRef.current = false\r\n }, 100)\r\n }\r\n }, [validViewer, menusDispatch, isMounted, currentViewer])\r\n\r\n const selectedViewer = (\r\n <>\r\n {[ViewerNames.map, ViewerNames.bim, ViewerNames.pointcloud].includes(validViewer) && <SidebarTrigger />}\r\n <div style={{ height: '100%', width: '100%', position: 'relative' }}>\r\n <div style={{ display: validViewer === ViewerNames.map ? 'block' : 'none', width: '100%', height: '100%' }}>\r\n <MapViewer organization={organization} />\r\n </div>\r\n {validViewer === ViewerNames.bim && <BimViewer />}\r\n {validViewer === ViewerNames.pointcloud && <PointCloudViewer />}\r\n {[ViewerNames.buildings, ViewerNames.sites, ViewerNames.files, ViewerNames.land, ViewerNames.infrastructure, ViewerNames.extensions, ViewerNames.users].includes(validViewer) && (\r\n <DataMenu currentViewer={validViewer} />\r\n )}\r\n {[ViewerNames.settings].includes(validViewer) && (\r\n <UserSettings />\r\n )}\r\n </div>\r\n </>\r\n )\r\n\r\n return (\r\n <>\r\n {selectedViewer}\r\n <Toolbar viewer={validViewer} />\r\n </>\r\n )\r\n}"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/core/components/viewers/Viewer.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Dependencies\r\nimport * as React from 'react'\r\nimport dynamic from 'next/dynamic'\r\nimport { Loader2 } from 'lucide-react'\r\nimport { useSearchParams, useRouter, usePathname } from 'next/navigation'\r\nimport { ViewerNames } from '../../types'\r\nimport { BuildingsContext, MenusContext } from '../../store'\r\nimport { MapViewer } from './map/MapViewer'\r\n// Deep file import (not the ui barrel): the barrel re-exports heavy modules\r\n// (InfoSidebar, useFileUploadHandler, …) that would land in the eager map-route bundle.\r\nimport { SidebarTrigger } from '../ui/Sidebar'\r\nimport { UserSettings } from '../settings'\r\nimport { Toolbar } from '../Toolbar'\r\nimport { switchLanguage } from '../../utils/utils'\r\nimport { Organization } from '../../types/dbTypes'\r\n\r\n// Code-split the heavy viewers: BimViewer pulls in ~456 KB gzipped of\r\n// @thatopen/*, PointCloudViewer the Potree loader stack — loaded only when\r\n// selected, so map-only sessions never pay their cost. MapViewer stays static\r\n// because every user lands on it.\r\nconst BimViewer = dynamic(\r\n () => import('./bim/BimViewer').then(m => ({ default: m.BimViewer })),\r\n { ssr: false, loading: () => <ViewerLoadingFallback label=\"Loading BIM viewer…\" /> },\r\n)\r\nconst PointCloudViewer = dynamic(\r\n () => import('./pointcloud/PointCloudViewer').then(m => ({ default: m.PointCloudViewer })),\r\n { ssr: false, loading: () => <ViewerLoadingFallback label=\"Loading point cloud viewer…\" /> },\r\n)\r\n\r\n// DataMenu transitively imports BimViewer (via FilePreview), so keep it lazy\r\n// too — a static import would pull @thatopen + three/webgpu back into the eager\r\n// bundle. Only rendered for the data viewers, so map-only sessions skip it.\r\nconst DataMenu = dynamic(\r\n () => import('./Data/DataMenu').then(m => ({ default: m.DataMenu })),\r\n { ssr: false, loading: () => <ViewerLoadingFallback label=\"Loading data…\" /> },\r\n)\r\n\r\n// Styled to match the in-viewer loading card (see BimLoadingState): a soft\r\n// backdrop-blurred overlay with a bordered card, spinner + label. Uses only\r\n// Tailwind tokens + one lucide icon, so it adds no meaningful weight to the\r\n// eager map-route bundle (Viewer.tsx is statically imported).\r\nfunction ViewerLoadingFallback({ label }: { label: string }) {\r\n return (\r\n <div className=\"absolute inset-0 z-10 flex items-center justify-center bg-background/50 backdrop-blur-[1px]\">\r\n <div className=\"flex items-center gap-3 rounded-md border border-border bg-card px-5 py-4 shadow-sm\">\r\n <Loader2 className=\"h-5 w-5 animate-spin text-muted-foreground\" />\r\n <span className=\"text-foreground text-base font-medium font-['Inter'] leading-7\">{label}</span>\r\n </div>\r\n </div>\r\n )\r\n}\r\n\r\ninterface ViewerProps {\r\n organization: Organization\r\n minioBaseUrl?: string\r\n martinBaseUrl?: string\r\n pointcloudApiUrl?: string\r\n maptilerKey?: string\r\n geocodeEarthApiKey?: string\r\n geocoderUrl?: string\r\n}\r\n\r\nexport function Viewer({ organization, minioBaseUrl, martinBaseUrl, pointcloudApiUrl, maptilerKey, geocodeEarthApiKey, geocoderUrl }: ViewerProps) {\r\n\r\n const searchParams = useSearchParams()\r\n const viewer = (searchParams.get('viewer') as ViewerNames) || ViewerNames.map\r\n\r\n const { dispatch: menusDispatch, state: menusState } = React.useContext(MenusContext)\r\n const { state: buildingState } = React.useContext(BuildingsContext)\r\n // const { dispatch: appConfigDispatch } = React.useContext(AppConfigContext)\r\n const { building } = buildingState.buildings\r\n const { currentViewer } = menusState.menus\r\n const router = useRouter()\r\n const pathname = usePathname()\r\n const [isMounted, setIsMounted] = React.useState(false)\r\n\r\n // Use a ref to track if we're currently updating -> prevent circular updates\r\n const isUpdatingRef = React.useRef(false)\r\n\r\n const { appContent } = organization\r\n\r\n // Check if viewer is valid based on appContent\r\n const isViewerValid = appContent.length === 0 || appContent.includes(viewer)\r\n \r\n // Use default viewer (map) if current viewer is not valid\r\n const validViewer = isViewerValid ? viewer : ViewerNames.map\r\n\r\n // Update URL if viewer was not available for the organization\r\n React.useEffect(() => {\r\n if (isMounted && !isViewerValid && viewer !== ViewerNames.map) {\r\n const newSearchParams = new URLSearchParams(searchParams.toString())\r\n newSearchParams.delete('viewer')\r\n if (building?.id) {\r\n newSearchParams.set('buildingId', String(building.id))\r\n }\r\n router.replace(`${pathname}?${newSearchParams.toString()}`, { scroll: false })\r\n }\r\n }, [isMounted, isViewerValid, viewer, searchParams, pathname, router, building?.id])\r\n\r\n // On first mount, respond to URL\r\n React.useEffect(() => {\r\n if (!isMounted) {\r\n menusDispatch({\r\n type: 'SET_VIEWER',\r\n payload: { currentViewer: validViewer },\r\n })\r\n setIsMounted(true)\r\n }\r\n }, [isMounted, validViewer, menusDispatch])\r\n\r\n React.useEffect(() => {\r\n if (!organization) return\r\n const defaultLanguage = organization.languages?.[0] || 'En'\r\n if (defaultLanguage) switchLanguage(defaultLanguage)\r\n }, [organization])\r\n\r\n // Handle context changes (from sidebar, HeaderButtons, etc.)\r\n React.useEffect(() => {\r\n if (!isMounted || !currentViewer || currentViewer === validViewer || isUpdatingRef.current) {\r\n return\r\n }\r\n\r\n isUpdatingRef.current = true\r\n\r\n // Create URLSearchParams to preserve existing search params\r\n\r\n const newSearchParams = new URLSearchParams(searchParams.toString())\r\n newSearchParams.set('viewer', currentViewer)\r\n if (building?.id) {\r\n newSearchParams.set('buildingId', String(building.id))\r\n }\r\n\r\n\r\n router.replace(`${pathname}?${newSearchParams.toString()}`, { scroll: false })\r\n\r\n // Reset the flag after a brief delay to allow the navigation to complete\r\n setTimeout(() => {\r\n isUpdatingRef.current = false\r\n }, 100)\r\n }, [currentViewer, isMounted, pathname, router, viewer, searchParams])\r\n\r\n // Handle URL changes (direct navigation)\r\n React.useEffect(() => {\r\n if (isMounted && currentViewer !== validViewer && !isUpdatingRef.current) {\r\n isUpdatingRef.current = true\r\n\r\n menusDispatch({\r\n type: 'SET_VIEWER',\r\n payload: { currentViewer: validViewer },\r\n })\r\n\r\n // Reset the flag after a brief delay\r\n setTimeout(() => {\r\n isUpdatingRef.current = false\r\n }, 100)\r\n }\r\n }, [validViewer, menusDispatch, isMounted, currentViewer])\r\n\r\n const selectedViewer = (\r\n <>\r\n {[ViewerNames.map, ViewerNames.bim, ViewerNames.pointcloud].includes(validViewer) && <SidebarTrigger />}\r\n <div style={{ height: '100%', width: '100%', position: 'relative' }}>\r\n <div style={{ display: validViewer === ViewerNames.map ? 'block' : 'none', width: '100%', height: '100%' }}>\r\n <MapViewer organization={organization} minioBaseUrl={minioBaseUrl} maptilerKey={maptilerKey} />\r\n </div>\r\n {validViewer === ViewerNames.bim && <BimViewer />}\r\n {validViewer === ViewerNames.pointcloud && <PointCloudViewer pointcloudApiUrl={pointcloudApiUrl} />}\r\n {[ViewerNames.buildings, ViewerNames.sites, ViewerNames.files, ViewerNames.land, ViewerNames.infrastructure, ViewerNames.extensions, ViewerNames.users].includes(validViewer) && (\r\n <DataMenu currentViewer={validViewer} organization={organization} geocodeEarthApiKey={geocodeEarthApiKey} geocoderUrl={geocoderUrl} />\r\n )}\r\n {[ViewerNames.settings].includes(validViewer) && (\r\n <UserSettings minioBaseUrl={minioBaseUrl} />\r\n )}\r\n </div>\r\n </>\r\n )\r\n\r\n return (\r\n <>\r\n {selectedViewer}\r\n <Toolbar viewer={validViewer} minioBaseUrl={minioBaseUrl} martinBaseUrl={martinBaseUrl} organization={organization} geocodeEarthApiKey={geocodeEarthApiKey} geocoderUrl={geocoderUrl} />\r\n </>\r\n )\r\n}"],"mappings":";AA2B+B,SAyI3B,UAzI2B,KAsBzB,YAtByB;AArB/B,YAAY,WAAW;AACvB,OAAO,aAAa;AACpB,SAAS,eAAe;AACxB,SAAS,iBAAiB,WAAW,mBAAmB;AACxD,SAAS,mBAAmB;AAC5B,SAAS,kBAAkB,oBAAoB;AAC/C,SAAS,iBAAiB;AAG1B,SAAS,sBAAsB;AAC/B,SAAS,oBAAoB;AAC7B,SAAS,eAAe;AACxB,SAAS,sBAAsB;AAO/B,MAAM,YAAY;AAAA,EAChB,MAAM,OAAO,iBAAiB,EAAE,KAAK,QAAM,EAAE,SAAS,EAAE,UAAU,EAAE;AAAA,EACpE,EAAE,KAAK,OAAO,SAAS,MAAM,oBAAC,yBAAsB,OAAM,4BAAsB,EAAG;AACrF;AACA,MAAM,mBAAmB;AAAA,EACvB,MAAM,OAAO,+BAA+B,EAAE,KAAK,QAAM,EAAE,SAAS,EAAE,iBAAiB,EAAE;AAAA,EACzF,EAAE,KAAK,OAAO,SAAS,MAAM,oBAAC,yBAAsB,OAAM,oCAA8B,EAAG;AAC7F;AAKA,MAAM,WAAW;AAAA,EACf,MAAM,OAAO,iBAAiB,EAAE,KAAK,QAAM,EAAE,SAAS,EAAE,SAAS,EAAE;AAAA,EACnE,EAAE,KAAK,OAAO,SAAS,MAAM,oBAAC,yBAAsB,OAAM,sBAAgB,EAAG;AAC/E;AAMA,SAAS,sBAAsB,EAAE,MAAM,GAAsB;AAC3D,SACE,oBAAC,SAAI,WAAU,+FACb,+BAAC,SAAI,WAAU,uFACb;AAAA,wBAAC,WAAQ,WAAU,8CAA6C;AAAA,IAChE,oBAAC,UAAK,WAAU,kEAAkE,iBAAM;AAAA,KAC1F,GACF;AAEJ;AAYO,SAAS,OAAO,EAAE,cAAc,cAAc,eAAe,kBAAkB,aAAa,oBAAoB,YAAY,GAAgB;AAEjJ,QAAM,eAAe,gBAAgB;AACrC,QAAM,SAAU,aAAa,IAAI,QAAQ,KAAqB,YAAY;AAE1E,QAAM,EAAE,UAAU,eAAe,OAAO,WAAW,IAAI,MAAM,WAAW,YAAY;AACpF,QAAM,EAAE,OAAO,cAAc,IAAI,MAAM,WAAW,gBAAgB;AAElE,QAAM,EAAE,SAAS,IAAI,cAAc;AACnC,QAAM,EAAE,cAAc,IAAI,WAAW;AACrC,QAAM,SAAS,UAAU;AACzB,QAAM,WAAW,YAAY;AAC7B,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,KAAK;AAGtD,QAAM,gBAAgB,MAAM,OAAO,KAAK;AAEtC,QAAM,EAAE,WAAW,IAAI;AAGzB,QAAM,gBAAgB,WAAW,WAAW,KAAK,WAAW,SAAS,MAAM;AAG3E,QAAM,cAAc,gBAAgB,SAAS,YAAY;AAGzD,QAAM,UAAU,MAAM;AACpB,QAAI,aAAa,CAAC,iBAAiB,WAAW,YAAY,KAAK;AAC7D,YAAM,kBAAkB,IAAI,gBAAgB,aAAa,SAAS,CAAC;AACnE,sBAAgB,OAAO,QAAQ;AAC/B,UAAI,qCAAU,IAAI;AAChB,wBAAgB,IAAI,cAAc,OAAO,SAAS,EAAE,CAAC;AAAA,MACvD;AACA,aAAO,QAAQ,GAAG,QAAQ,IAAI,gBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,MAAM,CAAC;AAAA,IAC/E;AAAA,EACF,GAAG,CAAC,WAAW,eAAe,QAAQ,cAAc,UAAU,QAAQ,qCAAU,EAAE,CAAC;AAGnF,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,WAAW;AACd,oBAAc;AAAA,QACZ,MAAM;AAAA,QACN,SAAS,EAAE,eAAe,YAAY;AAAA,MACxC,CAAC;AACD,mBAAa,IAAI;AAAA,IACnB;AAAA,EACF,GAAG,CAAC,WAAW,aAAa,aAAa,CAAC;AAE1C,QAAM,UAAU,MAAM;AAnHxB;AAoHI,QAAI,CAAC,aAAc;AACnB,UAAM,oBAAmB,kBAAa,cAAb,mBAAyB,OAAM;AACxD,QAAI,gBAAiB,gBAAe,eAAe;AAAA,EACrD,GAAG,CAAC,YAAY,CAAC;AAGjB,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,aAAa,CAAC,iBAAiB,kBAAkB,eAAe,cAAc,SAAS;AAC1F;AAAA,IACF;AAEA,kBAAc,UAAU;AAIxB,UAAM,kBAAkB,IAAI,gBAAgB,aAAa,SAAS,CAAC;AACnE,oBAAgB,IAAI,UAAU,aAAa;AAC3C,QAAI,qCAAU,IAAI;AAChB,sBAAgB,IAAI,cAAc,OAAO,SAAS,EAAE,CAAC;AAAA,IACvD;AAGA,WAAO,QAAQ,GAAG,QAAQ,IAAI,gBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,MAAM,CAAC;AAG7E,eAAW,MAAM;AACf,oBAAc,UAAU;AAAA,IAC1B,GAAG,GAAG;AAAA,EACR,GAAG,CAAC,eAAe,WAAW,UAAU,QAAQ,QAAQ,YAAY,CAAC;AAGrE,QAAM,UAAU,MAAM;AACpB,QAAI,aAAa,kBAAkB,eAAe,CAAC,cAAc,SAAS;AACxE,oBAAc,UAAU;AAExB,oBAAc;AAAA,QACZ,MAAM;AAAA,QACN,SAAS,EAAE,eAAe,YAAY;AAAA,MACxC,CAAC;AAGD,iBAAW,MAAM;AACf,sBAAc,UAAU;AAAA,MAC1B,GAAG,GAAG;AAAA,IACR;AAAA,EACF,GAAG,CAAC,aAAa,eAAe,WAAW,aAAa,CAAC;AAEzD,QAAM,iBACJ,iCACG;AAAA,KAAC,YAAY,KAAK,YAAY,KAAK,YAAY,UAAU,EAAE,SAAS,WAAW,KAAK,oBAAC,kBAAe;AAAA,IACrG,qBAAC,SAAI,OAAO,EAAE,QAAQ,QAAQ,OAAO,QAAQ,UAAU,WAAW,GAChE;AAAA,0BAAC,SAAI,OAAO,EAAE,SAAS,gBAAgB,YAAY,MAAM,UAAU,QAAQ,OAAO,QAAQ,QAAQ,OAAO,GACvG,8BAAC,aAAU,cAA4B,cAA4B,aAA0B,GAC/F;AAAA,MACC,gBAAgB,YAAY,OAAO,oBAAC,aAAU;AAAA,MAC9C,gBAAgB,YAAY,cAAc,oBAAC,oBAAiB,kBAAoC;AAAA,MAChG,CAAC,YAAY,WAAW,YAAY,OAAO,YAAY,OAAO,YAAY,MAAM,YAAY,gBAAgB,YAAY,YAAY,YAAY,KAAK,EAAE,SAAS,WAAW,KAC1K,oBAAC,YAAS,eAAe,aAAa,cAA4B,oBAAwC,aAA0B;AAAA,MAErI,CAAC,YAAY,QAAQ,EAAE,SAAS,WAAW,KAC1C,oBAAC,gBAAa,cAA4B;AAAA,OAE9C;AAAA,KACF;AAGF,SACE,iCACG;AAAA;AAAA,IACD,oBAAC,WAAQ,QAAQ,aAAa,cAA4B,eAA8B,cAA4B,oBAAwC,aAA0B;AAAA,KACxL;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BimToolbar.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/viewers/bim/BimToolbar.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,wBAAgB,UAAU,
|
|
1
|
+
{"version":3,"file":"BimToolbar.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/viewers/bim/BimToolbar.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,wBAAgB,UAAU,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,qBAErE"}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import { bimToolbarTools } from "./src/tools/bimToolbar";
|
|
4
4
|
import { ToolbarBody } from "../../ToolbarBody";
|
|
5
|
-
function BimToolbar() {
|
|
6
|
-
return /* @__PURE__ */ jsx(ToolbarBody, { viewer: "bim", tools: bimToolbarTools() });
|
|
5
|
+
function BimToolbar({ minioBaseUrl }) {
|
|
6
|
+
return /* @__PURE__ */ jsx(ToolbarBody, { viewer: "bim", tools: bimToolbarTools({ minioBaseUrl }) });
|
|
7
7
|
}
|
|
8
8
|
export {
|
|
9
9
|
BimToolbar
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/core/components/viewers/bim/BimToolbar.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 { bimToolbarTools } from './src/tools/bimToolbar'\r\nimport { ToolbarBody } from '../../ToolbarBody'\r\n\r\nexport function BimToolbar() {\r\n return <ToolbarBody viewer=\"bim\" tools={bimToolbarTools()} />\r\n}\r\n"],"mappings":";AAUS;AAJT,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAErB,SAAS,aAAa;
|
|
1
|
+
{"version":3,"sources":["../../../../../src/core/components/viewers/bim/BimToolbar.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 { bimToolbarTools } from './src/tools/bimToolbar'\r\nimport { ToolbarBody } from '../../ToolbarBody'\r\n\r\nexport function BimToolbar({ minioBaseUrl }: { minioBaseUrl?: string }) {\r\n return <ToolbarBody viewer=\"bim\" tools={bimToolbarTools({ minioBaseUrl })} />\r\n}\r\n"],"mappings":";AAUS;AAJT,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAErB,SAAS,WAAW,EAAE,aAAa,GAA8B;AACtE,SAAO,oBAAC,eAAY,QAAO,OAAM,OAAO,gBAAgB,EAAE,aAAa,CAAC,GAAG;AAC7E;","names":[]}
|
|
@@ -5,5 +5,7 @@ export interface FileItem {
|
|
|
5
5
|
icon: React.ElementType;
|
|
6
6
|
visible: boolean;
|
|
7
7
|
}
|
|
8
|
-
export declare function SensorsTab(
|
|
8
|
+
export declare function SensorsTab({ minioBaseUrl }: {
|
|
9
|
+
minioBaseUrl?: string;
|
|
10
|
+
}): React.JSX.Element;
|
|
9
11
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAA;AAE3D,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,KAAK,CAAC,WAAW,CAAA;IACvB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,UAAU,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAA;AAE3D,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,KAAK,CAAC,WAAW,CAAA;IACvB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,UAAU,CAAC,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,qBAMrE"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import { SensorsSection } from "../../../../../../ui/Sensors/SensorsSection";
|
|
4
|
-
function SensorsTab() {
|
|
5
|
-
return /* @__PURE__ */ jsx("div", { className: "flex-1 flex flex-col space-y-6 py-4 overflow-hidden", children: /* @__PURE__ */ jsx(SensorsSection, {}) });
|
|
4
|
+
function SensorsTab({ minioBaseUrl }) {
|
|
5
|
+
return /* @__PURE__ */ jsx("div", { className: "flex-1 flex flex-col space-y-6 py-4 overflow-hidden", children: /* @__PURE__ */ jsx(SensorsSection, { minioBaseUrl }) });
|
|
6
6
|
}
|
|
7
7
|
export {
|
|
8
8
|
SensorsTab
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/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 { DbFile } from '../../../../../../../types/dbTypes'\r\nimport { SensorsSection } from '../../../../../../ui/Sensors/SensorsSection'\r\nexport interface FileItem {\r\n task: DbFile\r\n icon: React.ElementType\r\n visible: boolean\r\n}\r\n\r\nexport function SensorsTab() {\r\n return (\r\n <div className=\"flex-1 flex flex-col space-y-6 py-4 overflow-hidden\">\r\n <SensorsSection />\r\n </div>\r\n )\r\n}\r\n"],"mappings":";AAiBM;AAVN,SAAS,sBAAsB;AAOxB,SAAS,aAAa;
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/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 { DbFile } from '../../../../../../../types/dbTypes'\r\nimport { SensorsSection } from '../../../../../../ui/Sensors/SensorsSection'\r\nexport interface FileItem {\r\n task: DbFile\r\n icon: React.ElementType\r\n visible: boolean\r\n}\r\n\r\nexport function SensorsTab({ minioBaseUrl }: { minioBaseUrl?: string }) {\r\n return (\r\n <div className=\"flex-1 flex flex-col space-y-6 py-4 overflow-hidden\">\r\n <SensorsSection minioBaseUrl={minioBaseUrl} />\r\n </div>\r\n )\r\n}\r\n"],"mappings":";AAiBM;AAVN,SAAS,sBAAsB;AAOxB,SAAS,WAAW,EAAE,aAAa,GAA8B;AACtE,SACE,oBAAC,SAAI,WAAU,uDACb,8BAAC,kBAAe,cAA4B,GAC9C;AAEJ;","names":[]}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
|
|
2
|
+
import type { Organization } from '../../../../../../types/dbTypes';
|
|
3
|
+
export declare function BimSidebar({ minioBaseUrl, organization }: {
|
|
4
|
+
minioBaseUrl?: string;
|
|
5
|
+
organization?: Organization;
|
|
6
|
+
}): React.JSX.Element;
|
|
3
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAU9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAA;AAEnE,wBAAgB,UAAU,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,YAAY,CAAA;CAAE,qBA2BhH"}
|
|
@@ -9,7 +9,7 @@ import { SettingsTab } from "./SettingsTab";
|
|
|
9
9
|
import { BimContext, MenusContext } from "../../../../../../store";
|
|
10
10
|
import { InfoSidebarContainer } from "../../../../../ui/InfoSidebar/Container";
|
|
11
11
|
import { SensorsTab } from "./SensorsTab";
|
|
12
|
-
function BimSidebar() {
|
|
12
|
+
function BimSidebar({ minioBaseUrl, organization }) {
|
|
13
13
|
const { state: bimState } = React.useContext(BimContext);
|
|
14
14
|
const { modelId } = bimState.bim;
|
|
15
15
|
const { state: menusState, dispatch: menusDispatch } = React.useContext(MenusContext);
|
|
@@ -20,6 +20,7 @@ function BimSidebar() {
|
|
|
20
20
|
return /* @__PURE__ */ jsxs(
|
|
21
21
|
InfoSidebarContainer,
|
|
22
22
|
{
|
|
23
|
+
organization,
|
|
23
24
|
tabSelector: /* @__PURE__ */ jsx(
|
|
24
25
|
TabSelector,
|
|
25
26
|
{
|
|
@@ -31,7 +32,7 @@ function BimSidebar() {
|
|
|
31
32
|
selectedTab === "file" && /* @__PURE__ */ jsx(FileTab, {}),
|
|
32
33
|
selectedTab === "layers" && /* @__PURE__ */ jsx(LayersTab, { modelId }),
|
|
33
34
|
selectedTab === "communication" && /* @__PURE__ */ jsx(CommunicationTab, {}),
|
|
34
|
-
selectedTab === "sensors" && /* @__PURE__ */ jsx(SensorsTab, {}),
|
|
35
|
+
selectedTab === "sensors" && /* @__PURE__ */ jsx(SensorsTab, { minioBaseUrl }),
|
|
35
36
|
selectedTab === "settings" && /* @__PURE__ */ jsx(SettingsTab, {})
|
|
36
37
|
]
|
|
37
38
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/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 { TabSelector } from './TabSelector'\r\nimport { FileTab } from './FileTab'\r\nimport { LayersTab } from './LayersTab'\r\nimport { CommunicationTab } from './CommunicationTab'\r\nimport { SettingsTab } from './SettingsTab'\r\nimport { BimContext, MenusContext } from '../../../../../../store'\r\nimport { SidebarTabType } from '../../../../../../store/Menus/reducer'\r\nimport { InfoSidebarContainer } from '../../../../../ui/InfoSidebar/Container'\r\nimport { SensorsTab } from './SensorsTab'\r\n\r\nexport function BimSidebar() {\r\n const { state: bimState } = React.useContext(BimContext)\r\n const { modelId } = bimState.bim\r\n const { state: menusState, dispatch: menusDispatch } = React.useContext(MenusContext)\r\n const { selectedTab } = menusState.menus\r\n\r\n const handleTabChange = (selectedTab: SidebarTabType) => {\r\n menusDispatch({ type: 'SET_SIDEBAR_SELECTED_TAB', payload: { selectedTab } })\r\n }\r\n\r\n return (\r\n <InfoSidebarContainer\r\n tabSelector={\r\n <TabSelector\r\n activeTab={selectedTab}\r\n onTabChangeAction={handleTabChange}\r\n />\r\n }\r\n >\r\n {selectedTab === 'file' && <FileTab />}\r\n {selectedTab === 'layers' && <LayersTab modelId={modelId} />}\r\n {selectedTab === 'communication' && <CommunicationTab />}\r\n {selectedTab === 'sensors' && <SensorsTab />}\r\n {selectedTab === 'settings' && <SettingsTab />}\r\n </InfoSidebarContainer>\r\n )\r\n}"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../src/core/components/viewers/bim/src/BimSidebar/src/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 { TabSelector } from './TabSelector'\r\nimport { FileTab } from './FileTab'\r\nimport { LayersTab } from './LayersTab'\r\nimport { CommunicationTab } from './CommunicationTab'\r\nimport { SettingsTab } from './SettingsTab'\r\nimport { BimContext, MenusContext } from '../../../../../../store'\r\nimport { SidebarTabType } from '../../../../../../store/Menus/reducer'\r\nimport { InfoSidebarContainer } from '../../../../../ui/InfoSidebar/Container'\r\nimport { SensorsTab } from './SensorsTab'\r\nimport type { Organization } from '../../../../../../types/dbTypes'\r\n\r\nexport function BimSidebar({ minioBaseUrl, organization }: { minioBaseUrl?: string; organization?: Organization }) {\r\n const { state: bimState } = React.useContext(BimContext)\r\n const { modelId } = bimState.bim\r\n const { state: menusState, dispatch: menusDispatch } = React.useContext(MenusContext)\r\n const { selectedTab } = menusState.menus\r\n\r\n const handleTabChange = (selectedTab: SidebarTabType) => {\r\n menusDispatch({ type: 'SET_SIDEBAR_SELECTED_TAB', payload: { selectedTab } })\r\n }\r\n\r\n return (\r\n <InfoSidebarContainer\r\n organization={organization}\r\n tabSelector={\r\n <TabSelector\r\n activeTab={selectedTab}\r\n onTabChangeAction={handleTabChange}\r\n />\r\n }\r\n >\r\n {selectedTab === 'file' && <FileTab />}\r\n {selectedTab === 'layers' && <LayersTab modelId={modelId} />}\r\n {selectedTab === 'communication' && <CommunicationTab />}\r\n {selectedTab === 'sensors' && <SensorsTab minioBaseUrl={minioBaseUrl} />}\r\n {selectedTab === 'settings' && <SettingsTab />}\r\n </InfoSidebarContainer>\r\n )\r\n}"],"mappings":";AA4BI,SAGI,KAHJ;AAvBJ,YAAY,WAAW;AACvB,SAAS,mBAAmB;AAC5B,SAAS,eAAe;AACxB,SAAS,iBAAiB;AAC1B,SAAS,wBAAwB;AACjC,SAAS,mBAAmB;AAC5B,SAAS,YAAY,oBAAoB;AAEzC,SAAS,4BAA4B;AACrC,SAAS,kBAAkB;AAGpB,SAAS,WAAW,EAAE,cAAc,aAAa,GAA2D;AACjH,QAAM,EAAE,OAAO,SAAS,IAAI,MAAM,WAAW,UAAU;AACvD,QAAM,EAAE,QAAQ,IAAI,SAAS;AAC7B,QAAM,EAAE,OAAO,YAAY,UAAU,cAAc,IAAI,MAAM,WAAW,YAAY;AACpF,QAAM,EAAE,YAAY,IAAI,WAAW;AAEnC,QAAM,kBAAkB,CAACA,iBAAgC;AACvD,kBAAc,EAAE,MAAM,4BAA4B,SAAS,EAAE,aAAAA,aAAY,EAAE,CAAC;AAAA,EAC9E;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,aACE;AAAA,QAAC;AAAA;AAAA,UACC,WAAW;AAAA,UACX,mBAAmB;AAAA;AAAA,MACrB;AAAA,MAGD;AAAA,wBAAgB,UAAU,oBAAC,WAAQ;AAAA,QACnC,gBAAgB,YAAY,oBAAC,aAAU,SAAkB;AAAA,QACzD,gBAAgB,mBAAmB,oBAAC,oBAAiB;AAAA,QACrD,gBAAgB,aAAa,oBAAC,cAAW,cAA4B;AAAA,QACrE,gBAAgB,cAAc,oBAAC,eAAY;AAAA;AAAA;AAAA,EAC9C;AAEJ;","names":["selectedTab"]}
|
|
@@ -2,7 +2,9 @@ import * as React from "react";
|
|
|
2
2
|
import type { Tool } from "../../../../../../types/tools";
|
|
3
3
|
interface AddToBimProps {
|
|
4
4
|
tool: Tool;
|
|
5
|
+
minioBaseUrl?: string;
|
|
6
|
+
[key: string]: unknown;
|
|
5
7
|
}
|
|
6
|
-
export default function AddToBim({ tool }: AddToBimProps): React.JSX.Element;
|
|
8
|
+
export default function AddToBim({ tool, minioBaseUrl }: AddToBimProps): React.JSX.Element;
|
|
7
9
|
export {};
|
|
8
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B,OAAO,KAAK,EAAE,IAAI,EAAmB,MAAM,+BAA+B,CAAA;AAmB1E,UAAU,aAAa;IACrB,IAAI,EAAE,IAAI,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B,OAAO,KAAK,EAAE,IAAI,EAAmB,MAAM,+BAA+B,CAAA;AAmB1E,UAAU,aAAa;IACrB,IAAI,EAAE,IAAI,CAAA;IACV,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAkCD,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,aAAa,qBA2PrE"}
|
|
@@ -43,7 +43,7 @@ const FilePreview = ({ file, mousePosition }) => {
|
|
|
43
43
|
}
|
|
44
44
|
);
|
|
45
45
|
};
|
|
46
|
-
function AddToBim({ tool }) {
|
|
46
|
+
function AddToBim({ tool, minioBaseUrl }) {
|
|
47
47
|
var _a, _b;
|
|
48
48
|
const t = useTranslations("AddToBim");
|
|
49
49
|
const { dispatch: toolsDispatch, state: toolsState } = React.useContext(ToolsContext);
|
|
@@ -56,7 +56,7 @@ function AddToBim({ tool }) {
|
|
|
56
56
|
const [addingMode, setAddingMode] = React.useState(null);
|
|
57
57
|
const [contextMenu, setContextMenu] = React.useState(null);
|
|
58
58
|
const { addPendingComment, removePendingComment, commentCount } = useCommentMarkers(world, buildingId);
|
|
59
|
-
const { addPendingSensor, removePendingSensor, sensorCount } = useSensorMarkers(world, buildingId);
|
|
59
|
+
const { addPendingSensor, removePendingSensor, sensorCount } = useSensorMarkers(world, buildingId, minioBaseUrl);
|
|
60
60
|
const { uploadFile } = useUploadFileToBuilding(buildingId);
|
|
61
61
|
const { deleteFile } = useDeleteFile(buildingId);
|
|
62
62
|
const filesData = useFilesByBuildingId(buildingId).files || [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/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 * as LR from \"lucide-react\"\r\nimport Image from \"next/image\"\r\nimport { useTranslations } from 'next-intl'\r\n\r\nimport { BuildingsContext, MenusContext, ToolsContext } from \"../../../../../../store\"\r\nimport { BimContext } from \"../../../../../../store/BIM/context\"\r\nimport { ViewerNames } from \"../../../../../../types/dbTypes\"\r\nimport type { Tool, ToolbarToolType } from \"../../../../../../types/tools\"\r\nimport type { BimToolbarToolsType } from \"../bimToolbar\"\r\nimport { Button, useSidebar } from \"../../../../../ui\"\r\n\r\nimport { initializeCSS2DRenderer } from \"./src/FileMarkerUtils\"\r\nimport { useCommentMarkers } from \"./src/useCommentMarkers\"\r\nimport { useSensorMarkers } from \"./src/useSensorMarkers\"\r\nimport { useFilePlacement } from \"./src/useFilePlacement\"\r\nimport { AddToBimToolbar } from \"./src/AddToBimToolbar\"\r\nimport Position3DCard from \"./src/Position3DCard\"\r\nimport { FileAdderDialog } from \"../../../../map/src/tools/AddTools/AddFile/FileAdder\"\r\nimport { CommentInput } from \"../../../../../ui/Comments/CommentInput\"\r\nimport { SensorInput } from \"../../../../../ui/Sensors/SensorInput\"\r\nimport { useFilesByBuildingId, useUploadFileToBuilding, useDeleteFile } from \"../../../../../../hooks/files/files\"\r\nimport { ViewerContextMenu } from \"../../../../../ui/FilesManager\"\r\nimport type { FileMarkerAction } from \"../../../../../ui/FilesManager/src/FileMarker\"\r\nimport type { DbFile } from \"../../../../../../types/dbTypes\"\r\nimport type { FileAction } from \"../../../../../../types/global\"\r\n\r\ninterface AddToBimProps {\r\n tool: Tool\r\n}\r\n\r\nconst FilePreview: React.FC<{\r\n file: File\r\n mousePosition: { x: number; y: number }\r\n}> = ({ file, mousePosition }) => {\r\n const [imageUrl, setImageUrl] = React.useState<string | null>(null)\r\n const isImage = file.type.startsWith(\"image/\")\r\n\r\n React.useEffect(() => {\r\n if (isImage) {\r\n const url = URL.createObjectURL(file)\r\n setImageUrl(url)\r\n return () => URL.revokeObjectURL(url)\r\n }\r\n }, [file, isImage])\r\n\r\n return (\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n className=\"fixed pointer-events-none z-[9999] bg-white/95 flex items-center gap-2 cursor-crosshair text-xs\"\r\n style={{ left: mousePosition.x + 10, top: mousePosition.y - 10 }}\r\n >\r\n {isImage && imageUrl ? (\r\n <Image src={imageUrl} alt={file.name} width={16} height={16} className=\"object-cover rounded\" />\r\n ) : (\r\n <LR.File size={16} className=\"text-black\" />\r\n )}\r\n <span className=\"overflow-hidden text-ellipsis whitespace-nowrap flex-1\">{file.name}</span>\r\n </Button>\r\n )\r\n}\r\n\r\nexport default function AddToBim({ tool }: AddToBimProps) {\r\n const t = useTranslations('AddToBim')\r\n const { dispatch: toolsDispatch, state: toolsState } = React.useContext(ToolsContext)\r\n const { state: bimState } = React.useContext(BimContext)\r\n const { bimComponents, world, fragments } = bimState.bim\r\n const { state: buildingState } = React.useContext(BuildingsContext)\r\n const buildingId = buildingState?.buildings?.building?.id || -1\r\n const { dispatch: menusDispatch } = React.useContext(MenusContext)\r\n const { setOpenInfo } = useSidebar()\r\n\r\n const [addingMode, setAddingMode] = React.useState<BimToolbarToolsType>(null)\r\n\r\n // Context menu state for right-click on BIM scene objects\r\n const [contextMenu, setContextMenu] = React.useState<{ x: number; y: number; file: DbFile } | null>(null)\r\n\r\n // Extracted hooks\r\n const { addPendingComment, removePendingComment, commentCount } = useCommentMarkers(world, buildingId)\r\n const { addPendingSensor, removePendingSensor, sensorCount } = useSensorMarkers(world, buildingId)\r\n const { uploadFile } = useUploadFileToBuilding(buildingId)\r\n const { deleteFile } = useDeleteFile(buildingId)\r\n\r\n // Visible (added-to-scene) non-BIM files; also used to resolve a marker to its DB record.\r\n const filesData = useFilesByBuildingId(buildingId).files || []\r\n const filesDataRef = React.useRef(filesData)\r\n filesDataRef.current = filesData\r\n const visibleFileCount = filesData.filter(f => {\r\n const ext = f.extension?.toLowerCase()\r\n return ext !== \"ifc\" && ext !== \"frag\" && f.tag !== \"user\" && f.tag !== \"bim-file\" && f.isVisible\r\n }).length\r\n\r\n // Marker actions reach into the placement API after it is created, so route through a ref.\r\n const placementRef = React.useRef<ReturnType<typeof useFilePlacement> | null>(null)\r\n const handleMarkerAction = React.useCallback((id: string, action: FileMarkerAction) => {\r\n const api = placementRef.current\r\n if (!api) return\r\n if (action === \"delete\") {\r\n const placed = api.getPlacedFile(id)\r\n api.removePlacedFile(id)\r\n const dbFile = placed\r\n ? filesDataRef.current.find(f => f.name === placed.name && (f.id ?? 0) > 0)\r\n : undefined\r\n if (dbFile?.id) deleteFile(dbFile.id).catch(() => { })\r\n return\r\n }\r\n api.editPlacedFile(id, action === \"move\" ? \"translate\" : action)\r\n }, [deleteFile])\r\n\r\n const filePlacement = useFilePlacement(\r\n bimComponents, world, fragments, toolsDispatch, buildingId, uploadFile,\r\n handleMarkerAction,\r\n )\r\n placementRef.current = filePlacement\r\n\r\n // Initialize CSS2D renderer\r\n React.useEffect(() => {\r\n if (world) initializeCSS2DRenderer(world)\r\n }, [world])\r\n\r\n // Canvas-level right-click: raycast to detect hit, show context menu\r\n React.useEffect(() => {\r\n if (!world || !fragments) return\r\n const canvas = world.renderer?.three?.domElement\r\n if (!canvas) return\r\n\r\n const handleContextMenu = async (e: MouseEvent) => {\r\n // Prevent the browser default menu immediately, regardless of what we hit\r\n e.preventDefault()\r\n\r\n const mouse = new (await import(\"three\")).Vector2(e.clientX, e.clientY)\r\n const result = await filePlacement.raycast({\r\n camera: world.camera.three,\r\n mouse,\r\n dom: canvas,\r\n })\r\n\r\n // Try to identify which file was hit by matching model names in fragments\r\n const hitModelId = (result as any)?.modelId ?? (result as any)?.fragments?.modelId\r\n const matchedFile = hitModelId\r\n ? filesDataRef.current.find(f => f.name === hitModelId)\r\n : null\r\n\r\n setContextMenu({\r\n x: e.clientX,\r\n y: e.clientY,\r\n file: matchedFile ?? { id: 0, name: t('bimObject'), url: \"\", type: \"bim-file\" } as DbFile,\r\n })\r\n }\r\n\r\n canvas.addEventListener(\"contextmenu\", handleContextMenu)\r\n return () => canvas.removeEventListener(\"contextmenu\", handleContextMenu)\r\n }, [world, fragments, filePlacement.raycast])\r\n\r\n // Allow other UI to trigger AddToBim modes via currentToolId\r\n const { currentToolId } = toolsState.tools\r\n React.useEffect(() => {\r\n const bimAddModes: BimToolbarToolsType[] = [\r\n \"bim-add-file\", \"bim-add-comment\", \"bim-add-ids\",\r\n \"bim-add-ifc\", \"bim-add-bcf\", \"bim-add-cad\", \"bim-add-sensor\",\r\n ]\r\n if (bimAddModes.includes(currentToolId as BimToolbarToolsType)) {\r\n setAddingMode(currentToolId as BimToolbarToolsType)\r\n }\r\n }, [currentToolId])\r\n\r\n const startAdding = React.useCallback((mode: BimToolbarToolsType) => {\r\n setAddingMode(mode)\r\n toolsDispatch({ type: \"SET-TOOL\", payload: { currentToolId: mode } })\r\n // Crosshair is set by useFilePlacement.handleFileSelect after the user picks a file,\r\n // not here — so the cursor stays normal while the file picker is open.\r\n }, [toolsDispatch])\r\n\r\n const cancelAdding = React.useCallback(() => {\r\n setAddingMode(null)\r\n filePlacement.cancelPlacement()\r\n }, [filePlacement])\r\n\r\n // Sidebar navigation callbacks\r\n const openFileTab = React.useCallback(() => {\r\n setOpenInfo(true)\r\n menusDispatch({ type: \"SET_SIDEBAR_SELECTED_TAB\", payload: { selectedTab: \"file\" } })\r\n }, [setOpenInfo, menusDispatch])\r\n\r\n const openCommentsTab = React.useCallback(() => {\r\n setOpenInfo(true)\r\n menusDispatch({ type: \"SET_SIDEBAR_SELECTED_TAB\", payload: { selectedTab: \"communication\" } })\r\n }, [setOpenInfo, menusDispatch])\r\n\r\n const openSensorsTab = React.useCallback(() => {\r\n setOpenInfo(true)\r\n menusDispatch({ type: \"SET_SIDEBAR_SELECTED_TAB\", payload: { selectedTab: \"sensors\" } })\r\n }, [setOpenInfo, menusDispatch])\r\n\r\n const handleContextMenuAction = React.useCallback((_action: FileAction, _file: DbFile) => {\r\n openFileTab()\r\n }, [openFileTab])\r\n\r\n return (\r\n <>\r\n {/* File preview tooltip following cursor during placement */}\r\n {filePlacement.selectedFile && filePlacement.isPlacingFile && (\r\n <FilePreview file={filePlacement.selectedFile} mousePosition={filePlacement.mousePosition} />\r\n )}\r\n\r\n {/* Toolbar submenu */}\r\n <AddToBimToolbar\r\n tool={tool}\r\n onStartFile={() => startAdding(\"bim-add-file\")}\r\n onStartComment={() => startAdding(\"bim-add-comment\")}\r\n onStartCAD={() => startAdding(\"bim-add-cad\")}\r\n onStartSensor={() => startAdding(\"bim-add-sensor\")}\r\n fileCount={visibleFileCount}\r\n commentCount={commentCount}\r\n sensorCount={sensorCount}\r\n onFileBadgeClick={openFileTab}\r\n onCommentBadgeClick={openCommentsTab}\r\n onSensorBadgeClick={openSensorsTab}\r\n />\r\n\r\n {/* 3D position/scale card for DXF/GLB placement */}\r\n {filePlacement.show3DScaleCard && filePlacement.selectedFile && filePlacement.current3DFileType && (\r\n <Position3DCard\r\n fileType={filePlacement.current3DFileType}\r\n fileName={filePlacement.selectedFile.name}\r\n scale={filePlacement.fileScale}\r\n rotation={filePlacement.fileRotation}\r\n onScaleChange={filePlacement.setFileScale}\r\n onRotationChange={filePlacement.setFileRotation}\r\n onConfirm={() => {\r\n filePlacement.confirmPlacement()\r\n setAddingMode(null)\r\n }}\r\n onCancel={cancelAdding}\r\n />\r\n )}\r\n\r\n {/* File input card */}\r\n {addingMode === \"bim-add-file\" && !filePlacement.show3DScaleCard && (\r\n <FileAdderDialog\r\n isOpen={true}\r\n onClose={cancelAdding}\r\n title={t('addFile')}\r\n icon={LR.FilePlus}\r\n accept=\"*/*\"\r\n onFileSelect={(e) => filePlacement.handleFileSelect(e, addingMode)}\r\n onFileDrop={(file) => filePlacement.handleFileDrop(file, addingMode)}\r\n dropZoneTitle={t('dropZoneTitle')}\r\n dropZoneSubtext={t('dropZoneSubtext')}\r\n hide={filePlacement.isPlacingFile && !!filePlacement.selectedFile}\r\n />\r\n )}\r\n\r\n {addingMode === \"bim-add-cad\" && !filePlacement.show3DScaleCard && (\r\n <FileAdderDialog\r\n isOpen={true}\r\n onClose={cancelAdding}\r\n title={t('addCadFile')}\r\n icon={LR.DraftingCompass}\r\n accept=\".dxf,.dwg\"\r\n onFileSelect={(e) => filePlacement.handleFileSelect(e, addingMode)}\r\n onFileDrop={(file) => filePlacement.handleFileDrop(file, addingMode)}\r\n dropZoneTitle={t('dropZoneTitleCad')}\r\n dropZoneSubtext={t('dropZoneSubtextCad')}\r\n hide={filePlacement.isPlacingFile && !!filePlacement.selectedFile}\r\n />\r\n )}\r\n\r\n {/* Comment input */}\r\n <CommentInput\r\n viewer={ViewerNames.bim}\r\n layout=\"dialog\"\r\n isOpen={addingMode === \"bim-add-comment\"}\r\n onCancel={cancelAdding}\r\n bim={{\r\n world,\r\n raycast: filePlacement.raycast,\r\n buildingId,\r\n setCursor: filePlacement.setCursor,\r\n addPendingMarker: addPendingComment,\r\n removePendingMarker: removePendingComment,\r\n }}\r\n />\r\n\r\n {/* Sensor input */}\r\n <SensorInput\r\n viewer={ViewerNames.bim}\r\n layout=\"dialog\"\r\n isOpen={addingMode === \"bim-add-sensor\"}\r\n onCancel={cancelAdding}\r\n bim={{\r\n world,\r\n raycast: filePlacement.raycast,\r\n buildingId,\r\n setCursor: filePlacement.setCursor,\r\n addPendingMarker: addPendingSensor,\r\n removePendingMarker: removePendingSensor,\r\n }}\r\n />\r\n\r\n {/* Right-click context menu on BIM scene objects */}\r\n {contextMenu && (\r\n <ViewerContextMenu\r\n x={contextMenu.x}\r\n y={contextMenu.y}\r\n file={contextMenu.file}\r\n options={['view', 'move', 'delete']}\r\n onAction={handleContextMenuAction}\r\n onClose={() => setContextMenu(null)}\r\n />\r\n )}\r\n </>\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","_b"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/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 * as LR from \"lucide-react\"\r\nimport Image from \"next/image\"\r\nimport { useTranslations } from 'next-intl'\r\n\r\nimport { BuildingsContext, MenusContext, ToolsContext } from \"../../../../../../store\"\r\nimport { BimContext } from \"../../../../../../store/BIM/context\"\r\nimport { ViewerNames } from \"../../../../../../types/dbTypes\"\r\nimport type { Tool, ToolbarToolType } from \"../../../../../../types/tools\"\r\nimport type { BimToolbarToolsType } from \"../bimToolbar\"\r\nimport { Button, useSidebar } from \"../../../../../ui\"\r\n\r\nimport { initializeCSS2DRenderer } from \"./src/FileMarkerUtils\"\r\nimport { useCommentMarkers } from \"./src/useCommentMarkers\"\r\nimport { useSensorMarkers } from \"./src/useSensorMarkers\"\r\nimport { useFilePlacement } from \"./src/useFilePlacement\"\r\nimport { AddToBimToolbar } from \"./src/AddToBimToolbar\"\r\nimport Position3DCard from \"./src/Position3DCard\"\r\nimport { FileAdderDialog } from \"../../../../map/src/tools/AddTools/AddFile/FileAdder\"\r\nimport { CommentInput } from \"../../../../../ui/Comments/CommentInput\"\r\nimport { SensorInput } from \"../../../../../ui/Sensors/SensorInput\"\r\nimport { useFilesByBuildingId, useUploadFileToBuilding, useDeleteFile } from \"../../../../../../hooks/files/files\"\r\nimport { ViewerContextMenu } from \"../../../../../ui/FilesManager\"\r\nimport type { FileMarkerAction } from \"../../../../../ui/FilesManager/src/FileMarker\"\r\nimport type { DbFile } from \"../../../../../../types/dbTypes\"\r\nimport type { FileAction } from \"../../../../../../types/global\"\r\n\r\ninterface AddToBimProps {\r\n tool: Tool\r\n minioBaseUrl?: string\r\n [key: string]: unknown\r\n}\r\n\r\nconst FilePreview: React.FC<{\r\n file: File\r\n mousePosition: { x: number; y: number }\r\n}> = ({ file, mousePosition }) => {\r\n const [imageUrl, setImageUrl] = React.useState<string | null>(null)\r\n const isImage = file.type.startsWith(\"image/\")\r\n\r\n React.useEffect(() => {\r\n if (isImage) {\r\n const url = URL.createObjectURL(file)\r\n setImageUrl(url)\r\n return () => URL.revokeObjectURL(url)\r\n }\r\n }, [file, isImage])\r\n\r\n return (\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n className=\"fixed pointer-events-none z-[9999] bg-white/95 flex items-center gap-2 cursor-crosshair text-xs\"\r\n style={{ left: mousePosition.x + 10, top: mousePosition.y - 10 }}\r\n >\r\n {isImage && imageUrl ? (\r\n <Image src={imageUrl} alt={file.name} width={16} height={16} className=\"object-cover rounded\" />\r\n ) : (\r\n <LR.File size={16} className=\"text-black\" />\r\n )}\r\n <span className=\"overflow-hidden text-ellipsis whitespace-nowrap flex-1\">{file.name}</span>\r\n </Button>\r\n )\r\n}\r\n\r\nexport default function AddToBim({ tool, minioBaseUrl }: AddToBimProps) {\r\n const t = useTranslations('AddToBim')\r\n const { dispatch: toolsDispatch, state: toolsState } = React.useContext(ToolsContext)\r\n const { state: bimState } = React.useContext(BimContext)\r\n const { bimComponents, world, fragments } = bimState.bim\r\n const { state: buildingState } = React.useContext(BuildingsContext)\r\n const buildingId = buildingState?.buildings?.building?.id || -1\r\n const { dispatch: menusDispatch } = React.useContext(MenusContext)\r\n const { setOpenInfo } = useSidebar()\r\n\r\n const [addingMode, setAddingMode] = React.useState<BimToolbarToolsType>(null)\r\n\r\n // Context menu state for right-click on BIM scene objects\r\n const [contextMenu, setContextMenu] = React.useState<{ x: number; y: number; file: DbFile } | null>(null)\r\n\r\n // Extracted hooks\r\n const { addPendingComment, removePendingComment, commentCount } = useCommentMarkers(world, buildingId)\r\n const { addPendingSensor, removePendingSensor, sensorCount } = useSensorMarkers(world, buildingId, minioBaseUrl)\r\n const { uploadFile } = useUploadFileToBuilding(buildingId)\r\n const { deleteFile } = useDeleteFile(buildingId)\r\n\r\n // Visible (added-to-scene) non-BIM files; also used to resolve a marker to its DB record.\r\n const filesData = useFilesByBuildingId(buildingId).files || []\r\n const filesDataRef = React.useRef(filesData)\r\n filesDataRef.current = filesData\r\n const visibleFileCount = filesData.filter(f => {\r\n const ext = f.extension?.toLowerCase()\r\n return ext !== \"ifc\" && ext !== \"frag\" && f.tag !== \"user\" && f.tag !== \"bim-file\" && f.isVisible\r\n }).length\r\n\r\n // Marker actions reach into the placement API after it is created, so route through a ref.\r\n const placementRef = React.useRef<ReturnType<typeof useFilePlacement> | null>(null)\r\n const handleMarkerAction = React.useCallback((id: string, action: FileMarkerAction) => {\r\n const api = placementRef.current\r\n if (!api) return\r\n if (action === \"delete\") {\r\n const placed = api.getPlacedFile(id)\r\n api.removePlacedFile(id)\r\n const dbFile = placed\r\n ? filesDataRef.current.find(f => f.name === placed.name && (f.id ?? 0) > 0)\r\n : undefined\r\n if (dbFile?.id) deleteFile(dbFile.id).catch(() => { })\r\n return\r\n }\r\n api.editPlacedFile(id, action === \"move\" ? \"translate\" : action)\r\n }, [deleteFile])\r\n\r\n const filePlacement = useFilePlacement(\r\n bimComponents, world, fragments, toolsDispatch, buildingId, uploadFile,\r\n handleMarkerAction,\r\n )\r\n placementRef.current = filePlacement\r\n\r\n // Initialize CSS2D renderer\r\n React.useEffect(() => {\r\n if (world) initializeCSS2DRenderer(world)\r\n }, [world])\r\n\r\n // Canvas-level right-click: raycast to detect hit, show context menu\r\n React.useEffect(() => {\r\n if (!world || !fragments) return\r\n const canvas = world.renderer?.three?.domElement\r\n if (!canvas) return\r\n\r\n const handleContextMenu = async (e: MouseEvent) => {\r\n // Prevent the browser default menu immediately, regardless of what we hit\r\n e.preventDefault()\r\n\r\n const mouse = new (await import(\"three\")).Vector2(e.clientX, e.clientY)\r\n const result = await filePlacement.raycast({\r\n camera: world.camera.three,\r\n mouse,\r\n dom: canvas,\r\n })\r\n\r\n // Try to identify which file was hit by matching model names in fragments\r\n const hitModelId = (result as any)?.modelId ?? (result as any)?.fragments?.modelId\r\n const matchedFile = hitModelId\r\n ? filesDataRef.current.find(f => f.name === hitModelId)\r\n : null\r\n\r\n setContextMenu({\r\n x: e.clientX,\r\n y: e.clientY,\r\n file: matchedFile ?? { id: 0, name: t('bimObject'), url: \"\", type: \"bim-file\" } as DbFile,\r\n })\r\n }\r\n\r\n canvas.addEventListener(\"contextmenu\", handleContextMenu)\r\n return () => canvas.removeEventListener(\"contextmenu\", handleContextMenu)\r\n }, [world, fragments, filePlacement.raycast])\r\n\r\n // Allow other UI to trigger AddToBim modes via currentToolId\r\n const { currentToolId } = toolsState.tools\r\n React.useEffect(() => {\r\n const bimAddModes: BimToolbarToolsType[] = [\r\n \"bim-add-file\", \"bim-add-comment\", \"bim-add-ids\",\r\n \"bim-add-ifc\", \"bim-add-bcf\", \"bim-add-cad\", \"bim-add-sensor\",\r\n ]\r\n if (bimAddModes.includes(currentToolId as BimToolbarToolsType)) {\r\n setAddingMode(currentToolId as BimToolbarToolsType)\r\n }\r\n }, [currentToolId])\r\n\r\n const startAdding = React.useCallback((mode: BimToolbarToolsType) => {\r\n setAddingMode(mode)\r\n toolsDispatch({ type: \"SET-TOOL\", payload: { currentToolId: mode } })\r\n // Crosshair is set by useFilePlacement.handleFileSelect after the user picks a file,\r\n // not here — so the cursor stays normal while the file picker is open.\r\n }, [toolsDispatch])\r\n\r\n const cancelAdding = React.useCallback(() => {\r\n setAddingMode(null)\r\n filePlacement.cancelPlacement()\r\n }, [filePlacement])\r\n\r\n // Sidebar navigation callbacks\r\n const openFileTab = React.useCallback(() => {\r\n setOpenInfo(true)\r\n menusDispatch({ type: \"SET_SIDEBAR_SELECTED_TAB\", payload: { selectedTab: \"file\" } })\r\n }, [setOpenInfo, menusDispatch])\r\n\r\n const openCommentsTab = React.useCallback(() => {\r\n setOpenInfo(true)\r\n menusDispatch({ type: \"SET_SIDEBAR_SELECTED_TAB\", payload: { selectedTab: \"communication\" } })\r\n }, [setOpenInfo, menusDispatch])\r\n\r\n const openSensorsTab = React.useCallback(() => {\r\n setOpenInfo(true)\r\n menusDispatch({ type: \"SET_SIDEBAR_SELECTED_TAB\", payload: { selectedTab: \"sensors\" } })\r\n }, [setOpenInfo, menusDispatch])\r\n\r\n const handleContextMenuAction = React.useCallback((_action: FileAction, _file: DbFile) => {\r\n openFileTab()\r\n }, [openFileTab])\r\n\r\n return (\r\n <>\r\n {/* File preview tooltip following cursor during placement */}\r\n {filePlacement.selectedFile && filePlacement.isPlacingFile && (\r\n <FilePreview file={filePlacement.selectedFile} mousePosition={filePlacement.mousePosition} />\r\n )}\r\n\r\n {/* Toolbar submenu */}\r\n <AddToBimToolbar\r\n tool={tool}\r\n onStartFile={() => startAdding(\"bim-add-file\")}\r\n onStartComment={() => startAdding(\"bim-add-comment\")}\r\n onStartCAD={() => startAdding(\"bim-add-cad\")}\r\n onStartSensor={() => startAdding(\"bim-add-sensor\")}\r\n fileCount={visibleFileCount}\r\n commentCount={commentCount}\r\n sensorCount={sensorCount}\r\n onFileBadgeClick={openFileTab}\r\n onCommentBadgeClick={openCommentsTab}\r\n onSensorBadgeClick={openSensorsTab}\r\n />\r\n\r\n {/* 3D position/scale card for DXF/GLB placement */}\r\n {filePlacement.show3DScaleCard && filePlacement.selectedFile && filePlacement.current3DFileType && (\r\n <Position3DCard\r\n fileType={filePlacement.current3DFileType}\r\n fileName={filePlacement.selectedFile.name}\r\n scale={filePlacement.fileScale}\r\n rotation={filePlacement.fileRotation}\r\n onScaleChange={filePlacement.setFileScale}\r\n onRotationChange={filePlacement.setFileRotation}\r\n onConfirm={() => {\r\n filePlacement.confirmPlacement()\r\n setAddingMode(null)\r\n }}\r\n onCancel={cancelAdding}\r\n />\r\n )}\r\n\r\n {/* File input card */}\r\n {addingMode === \"bim-add-file\" && !filePlacement.show3DScaleCard && (\r\n <FileAdderDialog\r\n isOpen={true}\r\n onClose={cancelAdding}\r\n title={t('addFile')}\r\n icon={LR.FilePlus}\r\n accept=\"*/*\"\r\n onFileSelect={(e) => filePlacement.handleFileSelect(e, addingMode)}\r\n onFileDrop={(file) => filePlacement.handleFileDrop(file, addingMode)}\r\n dropZoneTitle={t('dropZoneTitle')}\r\n dropZoneSubtext={t('dropZoneSubtext')}\r\n hide={filePlacement.isPlacingFile && !!filePlacement.selectedFile}\r\n />\r\n )}\r\n\r\n {addingMode === \"bim-add-cad\" && !filePlacement.show3DScaleCard && (\r\n <FileAdderDialog\r\n isOpen={true}\r\n onClose={cancelAdding}\r\n title={t('addCadFile')}\r\n icon={LR.DraftingCompass}\r\n accept=\".dxf,.dwg\"\r\n onFileSelect={(e) => filePlacement.handleFileSelect(e, addingMode)}\r\n onFileDrop={(file) => filePlacement.handleFileDrop(file, addingMode)}\r\n dropZoneTitle={t('dropZoneTitleCad')}\r\n dropZoneSubtext={t('dropZoneSubtextCad')}\r\n hide={filePlacement.isPlacingFile && !!filePlacement.selectedFile}\r\n />\r\n )}\r\n\r\n {/* Comment input */}\r\n <CommentInput\r\n viewer={ViewerNames.bim}\r\n layout=\"dialog\"\r\n isOpen={addingMode === \"bim-add-comment\"}\r\n onCancel={cancelAdding}\r\n bim={{\r\n world,\r\n raycast: filePlacement.raycast,\r\n buildingId,\r\n setCursor: filePlacement.setCursor,\r\n addPendingMarker: addPendingComment,\r\n removePendingMarker: removePendingComment,\r\n }}\r\n />\r\n\r\n {/* Sensor input */}\r\n <SensorInput\r\n viewer={ViewerNames.bim}\r\n layout=\"dialog\"\r\n isOpen={addingMode === \"bim-add-sensor\"}\r\n onCancel={cancelAdding}\r\n bim={{\r\n world,\r\n raycast: filePlacement.raycast,\r\n buildingId,\r\n setCursor: filePlacement.setCursor,\r\n addPendingMarker: addPendingSensor,\r\n removePendingMarker: removePendingSensor,\r\n }}\r\n />\r\n\r\n {/* Right-click context menu on BIM scene objects */}\r\n {contextMenu && (\r\n <ViewerContextMenu\r\n x={contextMenu.x}\r\n y={contextMenu.y}\r\n file={contextMenu.file}\r\n options={['view', 'move', 'delete']}\r\n onAction={handleContextMenuAction}\r\n onClose={() => setContextMenu(null)}\r\n />\r\n )}\r\n </>\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","_b"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSensorMarkers.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"useSensorMarkers.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.ts"],"names":[],"mappings":"AAiBA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM;iCAoD9B;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE;8BAMtC,MAAM;;EAsE1D"}
|
|
@@ -28,7 +28,7 @@ import { useCoreHooks } from "../../../../../../../hooks/provider";
|
|
|
28
28
|
import { renderCSS2DMarkers } from "./renderCSS2DMarkers";
|
|
29
29
|
import BimSensor from "./BimSensor";
|
|
30
30
|
import { UNTAGGED_TAG } from "../../../../../../ui/Sensors/SensorsSection";
|
|
31
|
-
function useSensorMarkers(world, buildingId) {
|
|
31
|
+
function useSensorMarkers(world, buildingId, minioBaseUrl) {
|
|
32
32
|
const { state: menusState } = React.useContext(MenusContext);
|
|
33
33
|
const { currentSensorId, visibleSensorTypes, visibleSensorTags } = menusState.menus;
|
|
34
34
|
const registry = React.useRef(/* @__PURE__ */ new Map());
|
|
@@ -115,7 +115,7 @@ function useSensorMarkers(world, buildingId) {
|
|
|
115
115
|
sensorName: sensor.name,
|
|
116
116
|
sensorType: sensorTypes.find((t) => t.id === sensor.typeId),
|
|
117
117
|
tags: sensor.tags,
|
|
118
|
-
dataUrl: ((_a = sensor.url) == null ? void 0 : _a.startsWith("http")) ? sensor.url : `${
|
|
118
|
+
dataUrl: ((_a = sensor.url) == null ? void 0 : _a.startsWith("http")) ? sensor.url : minioBaseUrl ? `${minioBaseUrl}/sensors/${sensor.url}` : "",
|
|
119
119
|
dataFormat: sensor.dataFormat,
|
|
120
120
|
updateFrequency: sensor.updateFrequency,
|
|
121
121
|
buildingId: sensor.buildingId,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.ts"],"sourcesContent":["\"use client\"\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from \"react\"\r\nimport { MenusContext } from \"../../../../../../../store\"\r\nimport { ViewerNames } from \"../../../../../../../types/dbTypes\"\r\nimport { useSensors, useSensor } from \"../../../../../../../hooks/sensors/sensors\"\r\nimport { useUsers } from \"../../../../../../../hooks/users/users\"\r\nimport { useSensorTypes } from \"../../../../../../../hooks/sensorTypes/sensorTypes\"\r\nimport { useCoreHooks } from \"../../../../../../../hooks/provider\"\r\nimport { renderCSS2DMarkers, type MarkerRef } from \"./renderCSS2DMarkers\"\r\nimport BimSensor from \"./BimSensor\"\r\nimport { UNTAGGED_TAG } from \"../../../../../../ui/Sensors/SensorsSection\"\r\n\r\nexport function useSensorMarkers(world: any, buildingId: number) {\r\n const { state: menusState } = React.useContext(MenusContext)\r\n const { currentSensorId, visibleSensorTypes, visibleSensorTags } = menusState.menus\r\n\r\n const registry = React.useRef<Map<string, MarkerRef>>(new Map())\r\n\r\n const { sensors } = useSensors()\r\n const { users } = useUsers()\r\n const { sensorTypes } = useSensorTypes()\r\n const coreHooks = useCoreHooks()\r\n\r\n const [sensorToDelete, setSensorToDelete] = React.useState<number | null>(null)\r\n const { deleteSensor } = useSensor(sensorToDelete)\r\n\r\n const eligibleSensors = sensors\r\n .filter((sensor) => {\r\n const { x, y, z, viewer } = sensor\r\n if (x == null || y == null || z == null) return false\r\n if (viewer !== ViewerNames.bim) return false\r\n if (buildingId !== -1 && sensor.buildingId !== buildingId) return false\r\n return true\r\n })\r\n .map((sensor) => {\r\n const user = users.find(u => u.id === sensor.authorId)\r\n const sensorType = sensorTypes.find(t => t.id === sensor.typeId)\r\n return {\r\n ...sensor,\r\n authorName: user?.name ?? \"Unknown User\",\r\n imageFileId: user?.imageFileId ?? \"images/default-avatar.svg\",\r\n sensorType,\r\n }\r\n })\r\n\r\n // Stable ref so the render effect reads current sensors without re-running on every change\r\n const eligibleSensorsRef = React.useRef(eligibleSensors)\r\n eligibleSensorsRef.current = eligibleSensors\r\n\r\n React.useEffect(() => {\r\n if (sensorToDelete !== null) {\r\n deleteSensor()\r\n setSensorToDelete(null)\r\n }\r\n }, [sensorToDelete, deleteSensor])\r\n\r\n const handleRemoveSensor = React.useCallback((sensorId: number) => {\r\n setSensorToDelete(sensorId)\r\n }, [])\r\n\r\n // Pending markers for loading indicators while sensor is being created\r\n const [pendingSensors, setPendingSensors] = React.useState<Array<{ id: number; x: number; y: number; z: number }>>([])\r\n\r\n const addPendingSensor = React.useCallback((position: { x: number; y: number; z: number }) => {\r\n const id = -Date.now()\r\n setPendingSensors(prev => [...prev, { id, ...position }])\r\n return id\r\n }, [])\r\n\r\n const removePendingSensor = React.useCallback((id: number) => {\r\n setPendingSensors(prev => prev.filter(p => p.id !== id))\r\n }, [])\r\n\r\n // Render sensor markers with visibility filtering\r\n React.useEffect(() => {\r\n const typesVisible = visibleSensorTypes?.[ViewerNames.bim] || []\r\n const tagsVisible = visibleSensorTags?.[ViewerNames.bim] || []\r\n\r\n const visibleSensors = eligibleSensorsRef.current.filter(sensor => {\r\n const matchesType = typesVisible.includes(sensor.typeId)\r\n const hasNoTags = !sensor.tags?.length\r\n const matchesTag = hasNoTags\r\n ? tagsVisible.includes(UNTAGGED_TAG)\r\n : sensor.tags?.some((tag: string) => tagsVisible.includes(tag)) ?? false\r\n return matchesType || matchesTag\r\n })\r\n\r\n const allSensors = [\r\n ...visibleSensors.map(s => ({ ...s, isPending: false })),\r\n ...pendingSensors.map(p => ({\r\n id: p.id,\r\n name: \"Creating...\",\r\n sensorType: undefined,\r\n typeId: undefined,\r\n x: p.x,\r\n y: p.y,\r\n z: p.z,\r\n url: \"\",\r\n dataFormat: \"Json\",\r\n updateFrequency: 0,\r\n createdAt: new Date().toISOString(),\r\n buildingId,\r\n tags: [],\r\n isPending: true,\r\n })),\r\n ]\r\n\r\n renderCSS2DMarkers(world, {\r\n items: allSensors,\r\n markerIdKey: \"sensorId\",\r\n registry,\r\n component: BimSensor,\r\n hooksContextValue: coreHooks,\r\n propsMapper: (sensor) => ({\r\n sensorName: sensor.name,\r\n sensorType: sensorTypes.find(t => t.id === sensor.typeId),\r\n tags: sensor.tags,\r\n dataUrl: sensor.url?.startsWith(\"http\")\r\n ? sensor.url\r\n : `${
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../src/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.ts"],"sourcesContent":["\"use client\"\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from \"react\"\r\nimport { MenusContext } from \"../../../../../../../store\"\r\nimport { ViewerNames } from \"../../../../../../../types/dbTypes\"\r\nimport { useSensors, useSensor } from \"../../../../../../../hooks/sensors/sensors\"\r\nimport { useUsers } from \"../../../../../../../hooks/users/users\"\r\nimport { useSensorTypes } from \"../../../../../../../hooks/sensorTypes/sensorTypes\"\r\nimport { useCoreHooks } from \"../../../../../../../hooks/provider\"\r\nimport { renderCSS2DMarkers, type MarkerRef } from \"./renderCSS2DMarkers\"\r\nimport BimSensor from \"./BimSensor\"\r\nimport { UNTAGGED_TAG } from \"../../../../../../ui/Sensors/SensorsSection\"\r\n//import { useAppConfigContext } from \"../../../../../../../store/AppConfig/context\"\r\n\r\nexport function useSensorMarkers(world: any, buildingId: number, minioBaseUrl?: string) {\r\n const { state: menusState } = React.useContext(MenusContext)\r\n const { currentSensorId, visibleSensorTypes, visibleSensorTags } = menusState.menus\r\n //const { state: appConfigState } = useAppConfigContext()\r\n\r\n const registry = React.useRef<Map<string, MarkerRef>>(new Map())\r\n\r\n const { sensors } = useSensors()\r\n const { users } = useUsers()\r\n const { sensorTypes } = useSensorTypes()\r\n const coreHooks = useCoreHooks()\r\n\r\n const [sensorToDelete, setSensorToDelete] = React.useState<number | null>(null)\r\n const { deleteSensor } = useSensor(sensorToDelete)\r\n\r\n const eligibleSensors = sensors\r\n .filter((sensor) => {\r\n const { x, y, z, viewer } = sensor\r\n if (x == null || y == null || z == null) return false\r\n if (viewer !== ViewerNames.bim) return false\r\n if (buildingId !== -1 && sensor.buildingId !== buildingId) return false\r\n return true\r\n })\r\n .map((sensor) => {\r\n const user = users.find(u => u.id === sensor.authorId)\r\n const sensorType = sensorTypes.find(t => t.id === sensor.typeId)\r\n return {\r\n ...sensor,\r\n authorName: user?.name ?? \"Unknown User\",\r\n imageFileId: user?.imageFileId ?? \"images/default-avatar.svg\",\r\n sensorType,\r\n }\r\n })\r\n\r\n // Stable ref so the render effect reads current sensors without re-running on every change\r\n const eligibleSensorsRef = React.useRef(eligibleSensors)\r\n eligibleSensorsRef.current = eligibleSensors\r\n\r\n React.useEffect(() => {\r\n if (sensorToDelete !== null) {\r\n deleteSensor()\r\n setSensorToDelete(null)\r\n }\r\n }, [sensorToDelete, deleteSensor])\r\n\r\n const handleRemoveSensor = React.useCallback((sensorId: number) => {\r\n setSensorToDelete(sensorId)\r\n }, [])\r\n\r\n // Pending markers for loading indicators while sensor is being created\r\n const [pendingSensors, setPendingSensors] = React.useState<Array<{ id: number; x: number; y: number; z: number }>>([])\r\n\r\n const addPendingSensor = React.useCallback((position: { x: number; y: number; z: number }) => {\r\n const id = -Date.now()\r\n setPendingSensors(prev => [...prev, { id, ...position }])\r\n return id\r\n }, [])\r\n\r\n const removePendingSensor = React.useCallback((id: number) => {\r\n setPendingSensors(prev => prev.filter(p => p.id !== id))\r\n }, [])\r\n\r\n // Render sensor markers with visibility filtering\r\n React.useEffect(() => {\r\n const typesVisible = visibleSensorTypes?.[ViewerNames.bim] || []\r\n const tagsVisible = visibleSensorTags?.[ViewerNames.bim] || []\r\n\r\n const visibleSensors = eligibleSensorsRef.current.filter(sensor => {\r\n const matchesType = typesVisible.includes(sensor.typeId)\r\n const hasNoTags = !sensor.tags?.length\r\n const matchesTag = hasNoTags\r\n ? tagsVisible.includes(UNTAGGED_TAG)\r\n : sensor.tags?.some((tag: string) => tagsVisible.includes(tag)) ?? false\r\n return matchesType || matchesTag\r\n })\r\n\r\n const allSensors = [\r\n ...visibleSensors.map(s => ({ ...s, isPending: false })),\r\n ...pendingSensors.map(p => ({\r\n id: p.id,\r\n name: \"Creating...\",\r\n sensorType: undefined,\r\n typeId: undefined,\r\n x: p.x,\r\n y: p.y,\r\n z: p.z,\r\n url: \"\",\r\n dataFormat: \"Json\",\r\n updateFrequency: 0,\r\n createdAt: new Date().toISOString(),\r\n buildingId,\r\n tags: [],\r\n isPending: true,\r\n })),\r\n ]\r\n\r\n renderCSS2DMarkers(world, {\r\n items: allSensors,\r\n markerIdKey: \"sensorId\",\r\n registry,\r\n component: BimSensor,\r\n hooksContextValue: coreHooks,\r\n propsMapper: (sensor) => ({\r\n sensorName: sensor.name,\r\n sensorType: sensorTypes.find(t => t.id === sensor.typeId),\r\n tags: sensor.tags,\r\n dataUrl: sensor.url?.startsWith(\"http\")\r\n ? sensor.url\r\n : minioBaseUrl\r\n ? `${minioBaseUrl}/sensors/${sensor.url}`\r\n : \"\",\r\n dataFormat: sensor.dataFormat,\r\n updateFrequency: sensor.updateFrequency,\r\n buildingId: sensor.buildingId,\r\n timestamp: new Date(sensor.createdAt),\r\n highlight: currentSensorId === sensor.id,\r\n }),\r\n sphereColor: \"#10b981\",\r\n isVisible: true,\r\n onRemove: handleRemoveSensor,\r\n })\r\n }, [world, sensors, pendingSensors, handleRemoveSensor, visibleSensorTypes, visibleSensorTags, buildingId, currentSensorId, sensorTypes, coreHooks])\r\n\r\n const sensorCount = sensors.filter(\r\n s => s.viewer === ViewerNames.bim && (!buildingId || buildingId === -1 || s.buildingId === buildingId)\r\n ).length\r\n\r\n return { addPendingSensor, removePendingSensor, sensorCount }\r\n}\r\n"],"mappings":"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","names":[]}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Tool } from '../../../../../types/tools';
|
|
2
2
|
export type BimToolbarToolsType = 'bim-add' | 'bim-add-comment' | 'bim-add-file' | 'bim-add-ids' | 'bim-add-ifc' | 'bim-add-bcf' | 'bim-add-cad' | 'bim-add-sensor' | 'bim-add-h2k' | 'bim-clipping' | 'bim-camera-fit' | 'bim-selection' | 'bim-camera' | 'bim-dimensions' | 'bim-inspect' | 'bim-share' | 'bim-explode';
|
|
3
|
-
export declare function bimToolbarTools(
|
|
3
|
+
export declare function bimToolbarTools(config?: {
|
|
4
|
+
minioBaseUrl?: string;
|
|
5
|
+
}): Tool[];
|
|
4
6
|
//# sourceMappingURL=bimToolbar.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bimToolbar.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/bim/src/tools/bimToolbar.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAA;AAYjD,MAAM,MAAM,mBAAmB,GAC/B,SAAS,GACT,iBAAiB,GAAG,cAAc,GAAG,aAAa,GAAG,aAAa,GAAG,aAAa,GAAG,aAAa,GAAG,gBAAgB,GAAG,aAAa,GACpI,cAAc,GACd,gBAAgB,GAAG,eAAe,GAAG,YAAY,GAAG,gBAAgB,GAAG,aAAa,GAAG,WAAW,GAAG,aAAa,CAAA;AAEnH,wBAAgB,eAAe,
|
|
1
|
+
{"version":3,"file":"bimToolbar.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/bim/src/tools/bimToolbar.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,IAAI,EAAE,MAAM,4BAA4B,CAAA;AAYjD,MAAM,MAAM,mBAAmB,GAC/B,SAAS,GACT,iBAAiB,GAAG,cAAc,GAAG,aAAa,GAAG,aAAa,GAAG,aAAa,GAAG,aAAa,GAAG,gBAAgB,GAAG,aAAa,GACpI,cAAc,GACd,gBAAgB,GAAG,eAAe,GAAG,YAAY,GAAG,gBAAgB,GAAG,aAAa,GAAG,WAAW,GAAG,aAAa,CAAA;AAEnH,wBAAgB,eAAe,CAAC,MAAM,CAAC,EAAE;IAAE,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAAE,CAoD1E"}
|
|
@@ -5,8 +5,9 @@ import { MeasureBimTool } from "./measureBimTool";
|
|
|
5
5
|
import { ShareBimTool } from "./shareBimTool";
|
|
6
6
|
import AddToBim from "./AddToBim";
|
|
7
7
|
import { FitCameraTool } from "./FitCameraTool";
|
|
8
|
-
function bimToolbarTools() {
|
|
8
|
+
function bimToolbarTools(config) {
|
|
9
9
|
const t = useTranslations("bimToolbarTools");
|
|
10
|
+
const bimAddExtraProps = config != null ? config : {};
|
|
10
11
|
return [
|
|
11
12
|
// {
|
|
12
13
|
// id: 'bim-selection',
|
|
@@ -36,7 +37,8 @@ function bimToolbarTools() {
|
|
|
36
37
|
id: "bim-add",
|
|
37
38
|
title: t("add"),
|
|
38
39
|
icon: LR.Plus,
|
|
39
|
-
component: AddToBim
|
|
40
|
+
component: AddToBim,
|
|
41
|
+
extraProps: bimAddExtraProps
|
|
40
42
|
},
|
|
41
43
|
{
|
|
42
44
|
id: "bim-dimensions",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../src/core/components/viewers/bim/src/tools/bimToolbar.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport { ClippingTool } from './ClippingTool/ClippingTool';\r\n\r\nimport { Tool } from '../../../../../types/tools'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as LR from 'lucide-react'\r\nimport { MeasureBimTool } from './measureBimTool'\r\nimport { InspectBimTool } from './InspectBimTool'\r\n\r\nimport { ShareBimTool } from './shareBimTool'\r\nimport AddToBim from './AddToBim'\r\nimport { SelectionBimTool } from './selectionBimTool'\r\nimport { FitCameraTool } from './FitCameraTool'\r\nimport { ExplodeByLevelTool } from './ExplodeByLevelTool'\r\n\r\nexport type BimToolbarToolsType = \r\n'bim-add' | \r\n'bim-add-comment' | 'bim-add-file' | 'bim-add-ids' | 'bim-add-ifc' | 'bim-add-bcf' | 'bim-add-cad' | 'bim-add-sensor' | 'bim-add-h2k' | \r\n 'bim-clipping' |\r\n 'bim-camera-fit' | 'bim-selection' | 'bim-camera' | 'bim-dimensions' | 'bim-inspect' | 'bim-share' | 'bim-explode'\r\n\r\nexport function bimToolbarTools(): Tool[] {\r\n // Translation\r\n const t = useTranslations('bimToolbarTools')\r\n\r\n return [\r\n // {\r\n // id: 'bim-selection',\r\n // title: t('selection'),\r\n // icon: LR.MousePointerClick,\r\n // component: SelectionBimTool,\r\n // },\r\n // {\r\n // id: 'bim-explode',\r\n // title: t('explode'),\r\n // icon: LR.Layers3,\r\n // component: ExplodeByLevelTool,\r\n // },\r\n {\r\n id: 'bim-clipping',\r\n title: t('clipping'),\r\n icon: LR.Crop,\r\n component: ClippingTool,\r\n },\r\n {\r\n id: 'bim-camera-fit',\r\n title: t('fit'),\r\n icon: LR.Maximize2,\r\n component: FitCameraTool,\r\n },\r\n {\r\n id: 'bim-add',\r\n title: t('add'),\r\n icon: LR.Plus,\r\n component: AddToBim,\r\n },\r\n {\r\n id: 'bim-dimensions',\r\n title: t('measure'),\r\n icon: LR.Ruler,\r\n component: MeasureBimTool,\r\n },\r\n {\r\n id: 'bim-share',\r\n title: t('share'),\r\n icon: LR.Share2,\r\n component: ShareBimTool\r\n },\r\n // Add more tools here if needed\r\n ]\r\n}\r\n"],"mappings":"AAGA,SAAS,oBAAoB;AAG7B,SAAS,uBAAuB;AAChC,YAAY,QAAQ;AACpB,SAAS,sBAAsB;AAG/B,SAAS,oBAAoB;AAC7B,OAAO,cAAc;AAErB,SAAS,qBAAqB;AASvB,SAAS,
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/core/components/viewers/bim/src/tools/bimToolbar.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport { ClippingTool } from './ClippingTool/ClippingTool';\r\n\r\nimport { Tool } from '../../../../../types/tools'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as LR from 'lucide-react'\r\nimport { MeasureBimTool } from './measureBimTool'\r\nimport { InspectBimTool } from './InspectBimTool'\r\n\r\nimport { ShareBimTool } from './shareBimTool'\r\nimport AddToBim from './AddToBim'\r\nimport { SelectionBimTool } from './selectionBimTool'\r\nimport { FitCameraTool } from './FitCameraTool'\r\nimport { ExplodeByLevelTool } from './ExplodeByLevelTool'\r\n\r\nexport type BimToolbarToolsType = \r\n'bim-add' | \r\n'bim-add-comment' | 'bim-add-file' | 'bim-add-ids' | 'bim-add-ifc' | 'bim-add-bcf' | 'bim-add-cad' | 'bim-add-sensor' | 'bim-add-h2k' | \r\n 'bim-clipping' |\r\n 'bim-camera-fit' | 'bim-selection' | 'bim-camera' | 'bim-dimensions' | 'bim-inspect' | 'bim-share' | 'bim-explode'\r\n\r\nexport function bimToolbarTools(config?: { minioBaseUrl?: string }): Tool[] {\r\n // Translation\r\n const t = useTranslations('bimToolbarTools')\r\n\r\n const bimAddExtraProps = (config ?? {}) as unknown as Record<string, unknown>\r\n\r\n return [\r\n // {\r\n // id: 'bim-selection',\r\n // title: t('selection'),\r\n // icon: LR.MousePointerClick,\r\n // component: SelectionBimTool,\r\n // },\r\n // {\r\n // id: 'bim-explode',\r\n // title: t('explode'),\r\n // icon: LR.Layers3,\r\n // component: ExplodeByLevelTool,\r\n // },\r\n {\r\n id: 'bim-clipping',\r\n title: t('clipping'),\r\n icon: LR.Crop,\r\n component: ClippingTool,\r\n },\r\n {\r\n id: 'bim-camera-fit',\r\n title: t('fit'),\r\n icon: LR.Maximize2,\r\n component: FitCameraTool,\r\n },\r\n {\r\n id: 'bim-add',\r\n title: t('add'),\r\n icon: LR.Plus,\r\n component: AddToBim,\r\n extraProps: bimAddExtraProps,\r\n },\r\n {\r\n id: 'bim-dimensions',\r\n title: t('measure'),\r\n icon: LR.Ruler,\r\n component: MeasureBimTool,\r\n },\r\n {\r\n id: 'bim-share',\r\n title: t('share'),\r\n icon: LR.Share2,\r\n component: ShareBimTool\r\n },\r\n // Add more tools here if needed\r\n ]\r\n}\r\n"],"mappings":"AAGA,SAAS,oBAAoB;AAG7B,SAAS,uBAAuB;AAChC,YAAY,QAAQ;AACpB,SAAS,sBAAsB;AAG/B,SAAS,oBAAoB;AAC7B,OAAO,cAAc;AAErB,SAAS,qBAAqB;AASvB,SAAS,gBAAgB,QAA4C;AAE1E,QAAM,IAAI,gBAAgB,iBAAiB;AAE3C,QAAM,mBAAoB,0BAAU,CAAC;AAErC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAaL;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,UAAU;AAAA,MACnB,MAAM,GAAG;AAAA,MACT,WAAW;AAAA,IACb;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,KAAK;AAAA,MACd,MAAM,GAAG;AAAA,MACT,WAAW;AAAA,IACb;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,KAAK;AAAA,MACd,MAAM,GAAG;AAAA,MACT,WAAW;AAAA,MACX,YAAY;AAAA,IACd;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,SAAS;AAAA,MAClB,MAAM,GAAG;AAAA,MACT,WAAW;AAAA,IACb;AAAA,IACA;AAAA,MACE,IAAI;AAAA,MACJ,OAAO,EAAE,OAAO;AAAA,MAChB,MAAM,GAAG;AAAA,MACT,WAAW;AAAA,IACb;AAAA;AAAA,EAEF;AACF;","names":[]}
|
|
@@ -4,7 +4,9 @@ interface Props {
|
|
|
4
4
|
width?: string;
|
|
5
5
|
height?: string;
|
|
6
6
|
organization: Organization;
|
|
7
|
+
minioBaseUrl?: string;
|
|
8
|
+
maptilerKey?: string;
|
|
7
9
|
}
|
|
8
|
-
export declare function MapViewer({ width, height, organization }: Props): React.JSX.Element;
|
|
10
|
+
export declare function MapViewer({ width, height, organization, minioBaseUrl, maptilerKey }: Props): React.JSX.Element;
|
|
9
11
|
export {};
|
|
10
12
|
//# sourceMappingURL=MapViewer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MapViewer.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/viewers/map/MapViewer.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,OAAO,CAAA;AAazB,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAcrD,UAAU,KAAK;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"MapViewer.d.ts","sourceRoot":"","sources":["../../../../../src/core/components/viewers/map/MapViewer.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,MAAM,OAAO,CAAA;AAazB,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAcrD,UAAU,KAAK;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,YAAY,EAAE,YAAY,CAAA;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,wBAAgB,SAAS,CAAC,EAAE,KAAc,EAAE,MAAe,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,EAAE,KAAK,qBAsL5G"}
|
|
@@ -20,7 +20,7 @@ const CANADA_DEFAULTS = {
|
|
|
20
20
|
};
|
|
21
21
|
const DEFAULT_MAP_STYLE = { name: "Satellite", url: "mapStyles/satellite.json" };
|
|
22
22
|
const MAX_GLOBE_ZOOM = 5;
|
|
23
|
-
function MapViewer({ width = "100%", height = "100%", organization }) {
|
|
23
|
+
function MapViewer({ width = "100%", height = "100%", organization, minioBaseUrl, maptilerKey }) {
|
|
24
24
|
var _a, _b, _c;
|
|
25
25
|
const searchParams = useSearchParams();
|
|
26
26
|
const [isMapLoaded, setIsMapLoaded] = React.useState(false);
|
|
@@ -144,7 +144,7 @@ function MapViewer({ width = "100%", height = "100%", organization }) {
|
|
|
144
144
|
/* @__PURE__ */ jsx(NavigationControl, { visualizePitch: true }),
|
|
145
145
|
/* @__PURE__ */ jsx(SettingsButton, {}),
|
|
146
146
|
isMapLoaded && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
147
|
-
/* @__PURE__ */ jsx(MapLayers, {}),
|
|
147
|
+
/* @__PURE__ */ jsx(MapLayers, { minioBaseUrl, organization, maptilerKey }),
|
|
148
148
|
/* @__PURE__ */ jsxs("div", { className: "absolute bottom-[10px] left-3 z-10 flex flex-col gap-2 pointer-events-none", children: [
|
|
149
149
|
/* @__PURE__ */ jsx("div", { id: "wms-time-slot", style: { display: "contents" } }),
|
|
150
150
|
/* @__PURE__ */ jsx(MapLegendHost, {}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../src/core/components/viewers/map/MapViewer.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport Map, { MapRef, NavigationControl } from 'react-map-gl/maplibre'\r\nimport React from 'react'\r\n\r\nimport maplibregl from 'maplibre-gl'\r\nimport { useSearchParams } from 'next/navigation'\r\n\r\nimport { MapContext } from '../../../store'\r\nimport { resolveBounds } from './utils/validateBounds'\r\n\r\nimport { MapClickManager } from './utils/MapEventManager/MapClickManager'\r\nimport DatasetManagerMenu from './datasets/DatasetManager'\r\nimport { MapLegendHost } from './legends/MapLegendHost'\r\nimport { StatsOverlay } from '../../ui/stats'\r\nimport { MapHoverManager } from './utils/MapEventManager/MapHoverManager'\r\nimport { Organization } from '../../../types/dbTypes'\r\nimport { CurrentLocation } from '../../../types/map'\r\nimport { MapLayers } from './src/MapLayers'\r\nimport SettingsButton from '../../ui/SettingsButton'\r\n\r\nconst CANADA_DEFAULTS = {\r\n zoom: 3,\r\n lat: 56.415,\r\n long: -98.74,\r\n} as const\r\n\r\nconst DEFAULT_MAP_STYLE = { name: 'Satellite', url: 'mapStyles/satellite.json' } as const\r\nconst MAX_GLOBE_ZOOM = 5\r\n\r\ninterface Props {\r\n width?: string\r\n height?: string\r\n organization: Organization\r\n}\r\n\r\nexport function MapViewer({ width = '100%', height = '100%', organization }: Props) {\r\n\r\n const searchParams = useSearchParams()\r\n\r\n // Add state to track if map is loaded\r\n const [isMapLoaded, setIsMapLoaded] = React.useState(false)\r\n\r\n const viewState = React.useMemo(() => {\r\n return searchParams.size === 0\r\n ? {\r\n zoom: organization.zoom ?? CANADA_DEFAULTS.zoom,\r\n bearing: organization.bearing ?? 0,\r\n pitch: organization.pitch ?? 0,\r\n longitude: organization.long ?? CANADA_DEFAULTS.long,\r\n latitude: organization.lat ?? CANADA_DEFAULTS.lat,\r\n }\r\n : {\r\n latitude: searchParams.has('lat') ? Number.parseFloat(searchParams.get('lat')) : organization.lat ?? CANADA_DEFAULTS.lat,\r\n longitude: searchParams.has('lng') ? Number.parseFloat(searchParams.get('lng')) : organization.long ?? CANADA_DEFAULTS.long,\r\n bearing: searchParams.has('bearing') ? Number.parseFloat(searchParams.get('bearing')) : organization.bearing ?? 0,\r\n pitch: searchParams.has('pitch') ? Number.parseFloat(searchParams.get('pitch')) : organization.pitch ?? 0,\r\n zoom: searchParams.has('zoom') ? Number.parseFloat(searchParams.get('zoom')) : organization.zoom ?? CANADA_DEFAULTS.zoom,\r\n }\r\n }, [searchParams, organization])\r\n\r\n const initialProjection = viewState.zoom > MAX_GLOBE_ZOOM ? 'mercator' : 'globe'\r\n\r\n // Memoize the inline style object that gets passed to <Map> for a stable prop identity.\r\n const mapContainerStyle = React.useMemo(\r\n () => ({ width, height, backgroundColor: 'black' }),\r\n [width, height],\r\n )\r\n\r\n // Adaptive pixel ratio. A hardcoded 2 doubled fragment-shader cost on 1× DPR\r\n // desktops for zero visual gain; capping at 2 keeps phones (DPR 3-4) effective.\r\n const pixelRatio = React.useMemo(\r\n () => Math.min(typeof window !== 'undefined' ? window.devicePixelRatio : 1, 2),\r\n [],\r\n )\r\n\r\n const mapRef = React.useRef<MapRef>(null)\r\n const { dispatch: mapDispatch, state: mapState } = React.useContext(MapContext)\r\n\r\n // Keep the projection in sync with zoom at all times — not only while the\r\n // map-settings sidebar is mounted. The globe projection degrades past\r\n // MAX_GLOBE_ZOOM, so we force mercator regardless of which panels are open.\r\n const activeMap = mapState?.map?.map\r\n\r\n React.useEffect(() => {\r\n if (!activeMap) return\r\n\r\n const enforceProjectionForZoom = () => {\r\n if (activeMap.getZoom() <= MAX_GLOBE_ZOOM) return\r\n\r\n const projection = activeMap.getProjection()\r\n const currentType =\r\n typeof projection === 'string'\r\n ? projection\r\n : (projection as { type?: string; name?: string })?.type ?? (projection as { type?: string; name?: string })?.name\r\n\r\n if (currentType !== 'mercator') {\r\n activeMap.setProjection({ type: 'mercator' })\r\n }\r\n }\r\n\r\n enforceProjectionForZoom()\r\n activeMap.on('zoom', enforceProjectionForZoom)\r\n\r\n return () => {\r\n activeMap.off('zoom', enforceProjectionForZoom)\r\n }\r\n }, [activeMap])\r\n\r\n const handleMapLoad = () => {\r\n const map = mapRef.current.getMap()\r\n\r\n if (map.getZoom() > MAX_GLOBE_ZOOM) {\r\n map.setProjection({ type: 'mercator' })\r\n }\r\n\r\n // Only dispatch SET_MAP after map is fully loaded\r\n if (mapRef.current) {\r\n mapDispatch({\r\n type: 'SET_MAP',\r\n payload: { map },\r\n })\r\n }\r\n // initilize a new click manager\r\n const mapClickManager = new MapClickManager(map)\r\n mapDispatch({\r\n type: 'ADD_MAP_CLICK_MANAGER',\r\n payload: { mapClickManager },\r\n })\r\n\r\n const mapHoverManager = new MapHoverManager(map)\r\n mapDispatch({\r\n type: 'ADD_MAP_HOVER_MANAGER',\r\n payload: { mapHoverManager },\r\n })\r\n\r\n // update current Location with URL params or fallback to theme location\r\n const updatedLocation: CurrentLocation = {\r\n // Then override with URL params (this ensures URL params take precedence)\r\n lat: searchParams.has('lat') ? Number.parseFloat(searchParams.get('lat')) : organization.lat ?? CANADA_DEFAULTS.lat,\r\n lng: searchParams.has('lng') ? Number.parseFloat(searchParams.get('lng')) : organization.long ?? CANADA_DEFAULTS.long,\r\n bearing: searchParams.has('bearing') ? Number.parseFloat(searchParams.get('bearing')) : organization.bearing ?? 0,\r\n pitch: searchParams.has('pitch') ? Number.parseFloat(searchParams.get('pitch')) : organization.pitch ?? 0,\r\n zoom: searchParams.has('zoom') ? Number.parseFloat(searchParams.get('zoom')) : organization.zoom ?? CANADA_DEFAULTS.zoom,\r\n // Add location details from URL params if available\r\n countrySubdivision: searchParams.has('countrySubdivision') ? searchParams.get('countrySubdivision') : (organization.countrySubdivision ?? ''),\r\n municipality: searchParams.has('municipality') ? searchParams.get('municipality') : (organization.municipality ?? ''),\r\n address: searchParams.has('address') ? searchParams.get('address') : '', // organization.address,\r\n site: searchParams.has('site') ? searchParams.get('site') : String(organization.locationSiteId ?? ''),\r\n id: String(organization.id),\r\n }\r\n\r\n mapDispatch({\r\n type: 'UPDATE_LOCATION',\r\n payload: { currentLocation: updatedLocation },\r\n })\r\n\r\n // Set map as loaded after all dispatches are complete\r\n setIsMapLoaded(true)\r\n }\r\n\r\n // Enable the perf HUD by appending ?debug=1 to the URL. Never reaches\r\n // production users unless they explicitly opt in.\r\n const isDebug = searchParams.get('debug') === '1'\r\n\r\n // useCallback so the onDblClick prop identity is stable across renders of\r\n // MapViewer; a new function each render caused react-map-gl to detach/re-attach\r\n // the listener. The console.log is gated behind a dev-mode check.\r\n const onDblClick = React.useCallback((e) => {\r\n if (process.env.NODE_ENV === 'production') return\r\n const { lng, lat } = e.lngLat\r\n const elevation = mapRef.current?.queryTerrainElevation([lng, lat]) || 0\r\n const coordinates = { lng, lat, elevation, zoom: mapRef.current?.getZoom() }\r\n console.log('📍 Map coordinates:', coordinates)\r\n }, [])\r\n\r\n const mapStyle = mapState?.map.mapStyle ?? DEFAULT_MAP_STYLE;\r\n\r\n return (\r\n <>\r\n <Map\r\n id=\"map-component\"\r\n mapStyle={mapStyle.url}\r\n mapLib={maplibregl}\r\n onLoad={handleMapLoad}\r\n ref={mapRef}\r\n style={mapContainerStyle}\r\n initialViewState={viewState}\r\n maxPitch={60}\r\n minZoom={organization?.minZoom ?? CANADA_DEFAULTS.zoom}\r\n maxBounds={resolveBounds(organization?.maxBounds)}\r\n projection={initialProjection}\r\n doubleClickZoom={false}\r\n onDblClick={onDblClick}\r\n pixelRatio={pixelRatio}\r\n >\r\n <NavigationControl visualizePitch />\r\n <SettingsButton />\r\n {isMapLoaded\r\n && (\r\n <>\r\n <MapLayers />\r\n {/* Bottom-left stack: legend above the layers/styling card, gap auto-managed by flex. */}\r\n <div className=\"absolute bottom-[10px] left-3 z-10 flex flex-col gap-2 pointer-events-none\">\r\n {/* Portal slot for on-map WMS time controls; display:contents so an\r\n empty slot adds no flex item / gap, but a mounted control stacks\r\n above the legend + dataset-manager cards. */}\r\n <div id=\"wms-time-slot\" style={{ display: 'contents' }} />\r\n <MapLegendHost />\r\n <DatasetManagerMenu />\r\n </div>\r\n </>\r\n )}\r\n </Map>\r\n <StatsOverlay mapRef={mapRef} enabled={isDebug} />\r\n </>\r\n\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","_b","_c"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../src/core/components/viewers/map/MapViewer.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport Map, { MapRef, NavigationControl } from 'react-map-gl/maplibre'\r\nimport React from 'react'\r\n\r\nimport maplibregl from 'maplibre-gl'\r\nimport { useSearchParams } from 'next/navigation'\r\n\r\nimport { MapContext } from '../../../store'\r\nimport { resolveBounds } from './utils/validateBounds'\r\n\r\nimport { MapClickManager } from './utils/MapEventManager/MapClickManager'\r\nimport DatasetManagerMenu from './datasets/DatasetManager'\r\nimport { MapLegendHost } from './legends/MapLegendHost'\r\nimport { StatsOverlay } from '../../ui/stats'\r\nimport { MapHoverManager } from './utils/MapEventManager/MapHoverManager'\r\nimport { Organization } from '../../../types/dbTypes'\r\nimport { CurrentLocation } from '../../../types/map'\r\nimport { MapLayers } from './src/MapLayers'\r\nimport SettingsButton from '../../ui/SettingsButton'\r\n\r\nconst CANADA_DEFAULTS = {\r\n zoom: 3,\r\n lat: 56.415,\r\n long: -98.74,\r\n} as const\r\n\r\nconst DEFAULT_MAP_STYLE = { name: 'Satellite', url: 'mapStyles/satellite.json' } as const\r\nconst MAX_GLOBE_ZOOM = 5\r\n\r\ninterface Props {\r\n width?: string\r\n height?: string\r\n organization: Organization\r\n minioBaseUrl?: string\r\n maptilerKey?: string\r\n}\r\n\r\nexport function MapViewer({ width = '100%', height = '100%', organization, minioBaseUrl, maptilerKey }: Props) {\r\n\r\n const searchParams = useSearchParams()\r\n\r\n // Add state to track if map is loaded\r\n const [isMapLoaded, setIsMapLoaded] = React.useState(false)\r\n\r\n const viewState = React.useMemo(() => {\r\n return searchParams.size === 0\r\n ? {\r\n zoom: organization.zoom ?? CANADA_DEFAULTS.zoom,\r\n bearing: organization.bearing ?? 0,\r\n pitch: organization.pitch ?? 0,\r\n longitude: organization.long ?? CANADA_DEFAULTS.long,\r\n latitude: organization.lat ?? CANADA_DEFAULTS.lat,\r\n }\r\n : {\r\n latitude: searchParams.has('lat') ? Number.parseFloat(searchParams.get('lat')) : organization.lat ?? CANADA_DEFAULTS.lat,\r\n longitude: searchParams.has('lng') ? Number.parseFloat(searchParams.get('lng')) : organization.long ?? CANADA_DEFAULTS.long,\r\n bearing: searchParams.has('bearing') ? Number.parseFloat(searchParams.get('bearing')) : organization.bearing ?? 0,\r\n pitch: searchParams.has('pitch') ? Number.parseFloat(searchParams.get('pitch')) : organization.pitch ?? 0,\r\n zoom: searchParams.has('zoom') ? Number.parseFloat(searchParams.get('zoom')) : organization.zoom ?? CANADA_DEFAULTS.zoom,\r\n }\r\n }, [searchParams, organization])\r\n\r\n const initialProjection = viewState.zoom > MAX_GLOBE_ZOOM ? 'mercator' : 'globe'\r\n\r\n // Memoize the inline style object that gets passed to <Map> for a stable prop identity.\r\n const mapContainerStyle = React.useMemo(\r\n () => ({ width, height, backgroundColor: 'black' }),\r\n [width, height],\r\n )\r\n\r\n // Adaptive pixel ratio. A hardcoded 2 doubled fragment-shader cost on 1× DPR\r\n // desktops for zero visual gain; capping at 2 keeps phones (DPR 3-4) effective.\r\n const pixelRatio = React.useMemo(\r\n () => Math.min(typeof window !== 'undefined' ? window.devicePixelRatio : 1, 2),\r\n [],\r\n )\r\n\r\n const mapRef = React.useRef<MapRef>(null)\r\n const { dispatch: mapDispatch, state: mapState } = React.useContext(MapContext)\r\n\r\n // Keep the projection in sync with zoom at all times — not only while the\r\n // map-settings sidebar is mounted. The globe projection degrades past\r\n // MAX_GLOBE_ZOOM, so we force mercator regardless of which panels are open.\r\n const activeMap = mapState?.map?.map\r\n\r\n React.useEffect(() => {\r\n if (!activeMap) return\r\n\r\n const enforceProjectionForZoom = () => {\r\n if (activeMap.getZoom() <= MAX_GLOBE_ZOOM) return\r\n\r\n const projection = activeMap.getProjection()\r\n const currentType =\r\n typeof projection === 'string'\r\n ? projection\r\n : (projection as { type?: string; name?: string })?.type ?? (projection as { type?: string; name?: string })?.name\r\n\r\n if (currentType !== 'mercator') {\r\n activeMap.setProjection({ type: 'mercator' })\r\n }\r\n }\r\n\r\n enforceProjectionForZoom()\r\n activeMap.on('zoom', enforceProjectionForZoom)\r\n\r\n return () => {\r\n activeMap.off('zoom', enforceProjectionForZoom)\r\n }\r\n }, [activeMap])\r\n\r\n const handleMapLoad = () => {\r\n const map = mapRef.current.getMap()\r\n\r\n if (map.getZoom() > MAX_GLOBE_ZOOM) {\r\n map.setProjection({ type: 'mercator' })\r\n }\r\n\r\n // Only dispatch SET_MAP after map is fully loaded\r\n if (mapRef.current) {\r\n mapDispatch({\r\n type: 'SET_MAP',\r\n payload: { map },\r\n })\r\n }\r\n // initilize a new click manager\r\n const mapClickManager = new MapClickManager(map)\r\n mapDispatch({\r\n type: 'ADD_MAP_CLICK_MANAGER',\r\n payload: { mapClickManager },\r\n })\r\n\r\n const mapHoverManager = new MapHoverManager(map)\r\n mapDispatch({\r\n type: 'ADD_MAP_HOVER_MANAGER',\r\n payload: { mapHoverManager },\r\n })\r\n\r\n // update current Location with URL params or fallback to theme location\r\n const updatedLocation: CurrentLocation = {\r\n // Then override with URL params (this ensures URL params take precedence)\r\n lat: searchParams.has('lat') ? Number.parseFloat(searchParams.get('lat')) : organization.lat ?? CANADA_DEFAULTS.lat,\r\n lng: searchParams.has('lng') ? Number.parseFloat(searchParams.get('lng')) : organization.long ?? CANADA_DEFAULTS.long,\r\n bearing: searchParams.has('bearing') ? Number.parseFloat(searchParams.get('bearing')) : organization.bearing ?? 0,\r\n pitch: searchParams.has('pitch') ? Number.parseFloat(searchParams.get('pitch')) : organization.pitch ?? 0,\r\n zoom: searchParams.has('zoom') ? Number.parseFloat(searchParams.get('zoom')) : organization.zoom ?? CANADA_DEFAULTS.zoom,\r\n // Add location details from URL params if available\r\n countrySubdivision: searchParams.has('countrySubdivision') ? searchParams.get('countrySubdivision') : (organization.countrySubdivision ?? ''),\r\n municipality: searchParams.has('municipality') ? searchParams.get('municipality') : (organization.municipality ?? ''),\r\n address: searchParams.has('address') ? searchParams.get('address') : '', // organization.address,\r\n site: searchParams.has('site') ? searchParams.get('site') : String(organization.locationSiteId ?? ''),\r\n id: String(organization.id),\r\n }\r\n\r\n mapDispatch({\r\n type: 'UPDATE_LOCATION',\r\n payload: { currentLocation: updatedLocation },\r\n })\r\n\r\n // Set map as loaded after all dispatches are complete\r\n setIsMapLoaded(true)\r\n }\r\n\r\n // Enable the perf HUD by appending ?debug=1 to the URL. Never reaches\r\n // production users unless they explicitly opt in.\r\n const isDebug = searchParams.get('debug') === '1'\r\n\r\n // useCallback so the onDblClick prop identity is stable across renders of\r\n // MapViewer; a new function each render caused react-map-gl to detach/re-attach\r\n // the listener. The console.log is gated behind a dev-mode check.\r\n const onDblClick = React.useCallback((e) => {\r\n if (process.env.NODE_ENV === 'production') return\r\n const { lng, lat } = e.lngLat\r\n const elevation = mapRef.current?.queryTerrainElevation([lng, lat]) || 0\r\n const coordinates = { lng, lat, elevation, zoom: mapRef.current?.getZoom() }\r\n console.log('📍 Map coordinates:', coordinates)\r\n }, [])\r\n\r\n const mapStyle = mapState?.map.mapStyle ?? DEFAULT_MAP_STYLE;\r\n\r\n return (\r\n <>\r\n <Map\r\n id=\"map-component\"\r\n mapStyle={mapStyle.url}\r\n mapLib={maplibregl}\r\n onLoad={handleMapLoad}\r\n ref={mapRef}\r\n style={mapContainerStyle}\r\n initialViewState={viewState}\r\n maxPitch={60}\r\n minZoom={organization?.minZoom ?? CANADA_DEFAULTS.zoom}\r\n maxBounds={resolveBounds(organization?.maxBounds)}\r\n projection={initialProjection}\r\n doubleClickZoom={false}\r\n onDblClick={onDblClick}\r\n pixelRatio={pixelRatio}\r\n >\r\n <NavigationControl visualizePitch />\r\n <SettingsButton />\r\n {isMapLoaded\r\n && (\r\n <>\r\n <MapLayers minioBaseUrl={minioBaseUrl} organization={organization} maptilerKey={maptilerKey} />\r\n {/* Bottom-left stack: legend above the layers/styling card, gap auto-managed by flex. */}\r\n <div className=\"absolute bottom-[10px] left-3 z-10 flex flex-col gap-2 pointer-events-none\">\r\n {/* Portal slot for on-map WMS time controls; display:contents so an\r\n empty slot adds no flex item / gap, but a mounted control stacks\r\n above the legend + dataset-manager cards. */}\r\n <div id=\"wms-time-slot\" style={{ display: 'contents' }} />\r\n <MapLegendHost />\r\n <DatasetManagerMenu />\r\n </div>\r\n </>\r\n )}\r\n </Map>\r\n <StatsOverlay mapRef={mapRef} enabled={isDebug} />\r\n </>\r\n\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","_b","_c"]}
|