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