@collabdt/core 0.0.56 → 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 +10 -7
- 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 +3 -5
- package/dist/core/components/authentication/AuthPage.js.map +1 -1
- package/dist/core/components/authentication/Signin.d.ts +2 -1
- package/dist/core/components/authentication/Signin.d.ts.map +1 -1
- package/dist/core/components/authentication/Signin.js +2 -2
- 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 -5
- 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 -5
- package/dist/core/components/ui/AnimatedBackground.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 -4
- 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 +3 -5
- 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 -6
- 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/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 +4 -6
- 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 -14
- 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 -52
- 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 +5 -6
- 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 +15 -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 -23
- 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 +5 -0
- 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/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,3 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
export declare function PointCloudManagementTable(
|
|
2
|
+
export declare function PointCloudManagementTable({ pointcloudApiUrl }: {
|
|
3
|
+
pointcloudApiUrl?: string;
|
|
4
|
+
}): React.JSX.Element;
|
|
3
5
|
//# sourceMappingURL=PointCloudManagementTable.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PointCloudManagementTable.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,wBAAgB,yBAAyB,
|
|
1
|
+
{"version":3,"file":"PointCloudManagementTable.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAW/B,wBAAgB,yBAAyB,CAAC,EAAE,gBAAgB,EAAE,EAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,qBAkB5F"}
|
|
@@ -8,17 +8,19 @@ var PAGE = /* @__PURE__ */ ((PAGE2) => {
|
|
|
8
8
|
PAGE2["UPLOAD"] = "upload";
|
|
9
9
|
return PAGE2;
|
|
10
10
|
})(PAGE || {});
|
|
11
|
-
function PointCloudManagementTable() {
|
|
11
|
+
function PointCloudManagementTable({ pointcloudApiUrl }) {
|
|
12
12
|
const [currentPage, setCurrentPage] = React.useState("table" /* TABLE */);
|
|
13
13
|
return /* @__PURE__ */ jsx("div", { children: currentPage == "table" /* TABLE */ ? /* @__PURE__ */ jsx(
|
|
14
14
|
PointCloudTable,
|
|
15
15
|
{
|
|
16
|
-
onUploadButtonClick: () => setCurrentPage("upload" /* UPLOAD */)
|
|
16
|
+
onUploadButtonClick: () => setCurrentPage("upload" /* UPLOAD */),
|
|
17
|
+
pointcloudApiUrl
|
|
17
18
|
}
|
|
18
19
|
) : /* @__PURE__ */ jsx(
|
|
19
20
|
UploadPointCloudPage,
|
|
20
21
|
{
|
|
21
|
-
onGoBackButtonClick: () => setCurrentPage("table" /* TABLE */)
|
|
22
|
+
onGoBackButtonClick: () => setCurrentPage("table" /* TABLE */),
|
|
23
|
+
pointcloudApiUrl
|
|
22
24
|
}
|
|
23
25
|
) });
|
|
24
26
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.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 { PointCloudTable } from \"./PointCloudTable\";\r\nimport UploadPointCloudPage from \"./PointCloudUploadPanel\";\r\n\r\ntype StatusFilter = \"all\" | \"uploaded\" | \"converted\" | \"not-converted\";\r\n\r\nenum PAGE {\r\n TABLE = \"table\",\r\n UPLOAD = \"upload\",\r\n}\r\n\r\nexport function PointCloudManagementTable() {\r\n const [currentPage, setCurrentPage] = React.useState<PAGE>(PAGE.TABLE)\r\n\r\n return(\r\n <div>\r\n {currentPage == PAGE.TABLE
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.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 { PointCloudTable } from \"./PointCloudTable\";\r\nimport UploadPointCloudPage from \"./PointCloudUploadPanel\";\r\n\r\ntype StatusFilter = \"all\" | \"uploaded\" | \"converted\" | \"not-converted\";\r\n\r\nenum PAGE {\r\n TABLE = \"table\",\r\n UPLOAD = \"upload\",\r\n}\r\n\r\nexport function PointCloudManagementTable({ pointcloudApiUrl }: { pointcloudApiUrl?: string }) {\r\n const [currentPage, setCurrentPage] = React.useState<PAGE>(PAGE.TABLE)\r\n\r\n return(\r\n <div>\r\n {currentPage == PAGE.TABLE ?\r\n <PointCloudTable\r\n onUploadButtonClick = {() => setCurrentPage(PAGE.UPLOAD)}\r\n pointcloudApiUrl={pointcloudApiUrl}\r\n />\r\n :\r\n <UploadPointCloudPage\r\n onGoBackButtonClick = {() => setCurrentPage(PAGE.TABLE)}\r\n pointcloudApiUrl={pointcloudApiUrl}\r\n />\r\n }\r\n </div>\r\n )\r\n}\r\n\r\n"],"mappings":";AAsBQ;AAjBR,YAAY,WAAW;AACvB,SAAS,uBAAuB;AAChC,OAAO,0BAA0B;AAIjC,IAAK,OAAL,kBAAKA,UAAL;AACE,EAAAA,MAAA,WAAQ;AACR,EAAAA,MAAA,YAAS;AAFN,SAAAA;AAAA,GAAA;AAKE,SAAS,0BAA0B,EAAE,iBAAiB,GAAkC;AAC7F,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAe,mBAAU;AAErE,SACE,oBAAC,SACE,yBAAe,sBACd;AAAA,IAAC;AAAA;AAAA,MACC,qBAAuB,MAAM,eAAe,qBAAW;AAAA,MACvD;AAAA;AAAA,EACF,IAEA;AAAA,IAAC;AAAA;AAAA,MACC,qBAAuB,MAAM,eAAe,mBAAU;AAAA,MACtD;AAAA;AAAA,EACF,GAEJ;AAEJ;","names":["PAGE"]}
|
package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
type PointCloudTableProps = React.HTMLAttributes<HTMLDivElement> & {
|
|
3
3
|
onUploadButtonClick: () => void;
|
|
4
|
+
pointcloudApiUrl?: string;
|
|
4
5
|
};
|
|
5
|
-
export declare function PointCloudTable({ onUploadButtonClick, ...divProps }: PointCloudTableProps): React.JSX.Element;
|
|
6
|
+
export declare function PointCloudTable({ onUploadButtonClick, pointcloudApiUrl, ...divProps }: PointCloudTableProps): React.JSX.Element;
|
|
6
7
|
export {};
|
|
7
8
|
//# sourceMappingURL=PointCloudTable.d.ts.map
|
package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PointCloudTable.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAgD/B,KAAK,oBAAoB,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG;IAC/D,mBAAmB,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"PointCloudTable.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAgD/B,KAAK,oBAAoB,GAAG,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG;IAC/D,mBAAmB,EAAE,MAAM,IAAI,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,wBAAgB,eAAe,CAAC,EAC5B,mBAAmB,EACnB,gBAAgB,EAChB,GAAG,QAAQ,EACd,EAAE,oBAAoB,qBAmZtB"}
|
|
@@ -30,7 +30,6 @@ import { useRouter, usePathname } from "next/navigation";
|
|
|
30
30
|
import { useTranslations } from "next-intl";
|
|
31
31
|
import { toast } from "sonner";
|
|
32
32
|
import ConfirmDialog from "../../../../ConfirmDialog";
|
|
33
|
-
import { useAppConfigContext } from "../../../../../store/AppConfig/context";
|
|
34
33
|
import {
|
|
35
34
|
Star,
|
|
36
35
|
StarOff,
|
|
@@ -48,13 +47,13 @@ var PAGE = /* @__PURE__ */ ((PAGE2) => {
|
|
|
48
47
|
})(PAGE || {});
|
|
49
48
|
function PointCloudTable(_a) {
|
|
50
49
|
var _b = _a, {
|
|
51
|
-
onUploadButtonClick
|
|
50
|
+
onUploadButtonClick,
|
|
51
|
+
pointcloudApiUrl
|
|
52
52
|
} = _b, divProps = __objRest(_b, [
|
|
53
|
-
"onUploadButtonClick"
|
|
53
|
+
"onUploadButtonClick",
|
|
54
|
+
"pointcloudApiUrl"
|
|
54
55
|
]);
|
|
55
|
-
|
|
56
|
-
const { state: appConfigState } = useAppConfigContext();
|
|
57
|
-
const API_BASE = (_a2 = appConfigState.runtimeConfig.pointcloudApiUrl) != null ? _a2 : "http://localhost:5101";
|
|
56
|
+
const API_BASE = pointcloudApiUrl != null ? pointcloudApiUrl : "http://localhost:5101";
|
|
58
57
|
const [pointClouds, setPointClouds] = React.useState([]);
|
|
59
58
|
const [loading, setLoading] = React.useState(false);
|
|
60
59
|
const [error, setError] = React.useState(null);
|
package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.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 {\r\n Table,\r\n TableBody,\r\n TableCell,\r\n TableHead,\r\n TableHeader,\r\n TableRow,\r\n} from \"../../../../ui/Table\";\r\n\r\nimport { Badge, Button, Checkbox, Input, ScrollArea } from '../../../../ui';\r\n\r\nimport { Tabs, TabsList, TabsTrigger } from \"../../../../ui/Tabs\";\r\n\r\nimport { useRouter, usePathname } from 'next/navigation'\r\nimport { useTranslations } from 'next-intl'\r\nimport { toast } from 'sonner'\r\nimport ConfirmDialog from '../../../../ConfirmDialog'\r\nimport { useAppConfigContext } from '../../../../../store/AppConfig/context'\r\n\r\nimport {\r\n Star,\r\n StarOff,\r\n Eye,\r\n Trash2,\r\n Filter,\r\n RotateCcw,\r\n ChevronLeft,\r\n ChevronRight,\r\n} from \"lucide-react\";\r\n\r\ntype PointCloud = {\r\n id: string;\r\n name: string;\r\n point_cloud_uploaded: boolean;\r\n point_cloud_potree_converted: boolean;\r\n createdAt: string;\r\n potree_metadata_presigned_url?: string | null;\r\n potree_metadata_file_key?: string | null;\r\n};\r\n\r\ntype StatusFilter = \"all\" | \"uploaded\" | \"converted\" | \"not-converted\";\r\n\r\nenum PAGE {\r\n TABLE = \"table\",\r\n UPLOAD = \"upload\",\r\n}\r\n\r\ntype PointCloudTableProps = React.HTMLAttributes<HTMLDivElement> & {\r\n onUploadButtonClick: () => void;\r\n};\r\n\r\nexport function PointCloudTable({\r\n onUploadButtonClick,\r\n ...divProps\r\n}: PointCloudTableProps) {\r\n const { state: appConfigState } = useAppConfigContext()\r\n const API_BASE = appConfigState.runtimeConfig.pointcloudApiUrl ?? 'http://localhost:5101'\r\n const [pointClouds, setPointClouds] = React.useState<PointCloud[]>([]);\r\n const [loading, setLoading] = React.useState(false);\r\n const [error, setError] = React.useState<string | null>(null);\r\n const [search, setSearch] = React.useState(\"\");\r\n const [statusFilter, setStatusFilter] = React.useState<StatusFilter>(\"all\");\r\n const [favorites, setFavorites] = React.useState<Set<string>>(new Set());\r\n const [currentUrl, setCurrentUrl] = React.useState<URL | null>(null);\r\n const [deleteTarget, setDeleteTarget] = React.useState<PointCloud | null>(null)\r\n const [isDeleting, setIsDeleting] = React.useState(false)\r\n const t = useTranslations('PointCloudManagement')\r\n\r\n React.useEffect(() => {\r\n // This only runs in the browser\r\n const url = new URL(window.location.href);\r\n setCurrentUrl(url);\r\n }, []);\r\n\r\n const [currentPage, setCurrentPage] = React.useState<PAGE>(PAGE.TABLE)\r\n\r\n // route and navigation\r\n const router = useRouter()\r\n const pathname = usePathname()\r\n\r\n const loadPointClouds = React.useCallback(async () => {\r\n setLoading(true);\r\n setError(null);\r\n\r\n try {\r\n const res = await fetch(`${API_BASE}/point-cloud`, {\r\n headers: { \"Accept\": \"application/json\" },\r\n });\r\n\r\n if (!res.ok) {\r\n throw new Error(`Failed to fetch point clouds (${res.status})`);\r\n }\r\n\r\n const data: PointCloud[] = await res.json();\r\n setPointClouds(Array.isArray(data) ? data : []);\r\n } catch (err) {\r\n console.error(err);\r\n setError(\r\n err instanceof Error ? err.message : \"Unknown error while loading data\",\r\n );\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, []);\r\n\r\n React.useEffect(() => {\r\n loadPointClouds();\r\n }, [loadPointClouds]);\r\n\r\n const openViewer = (pointCloudId) => {\r\n if (!pointCloudId) return;\r\n const origin = window.location.origin\r\n const pathname = window.location.pathname\r\n const params = new URLSearchParams(currentUrl.search)\r\n params.set('viewer', 'pointcloud')\r\n params.set('pointCloudId', pointCloudId)\r\n const newurl = `${origin}${pathname}?${params.toString()}`\r\n router.push(newurl, { scroll: false }) // push but do not refresh\r\n };\r\n\r\n const handleDelete = async () => {\r\n if (!deleteTarget) return\r\n\r\n setIsDeleting(true)\r\n\r\n try {\r\n const res = await fetch(`${API_BASE}/point-cloud/${deleteTarget.id}`, {\r\n method: \"DELETE\",\r\n });\r\n\r\n if (!res.ok) {\r\n const msg = await res.text();\r\n throw new Error(msg || `Delete failed (${res.status})`);\r\n }\r\n\r\n setPointClouds((prev) => prev.filter((pc) => pc.id !== deleteTarget.id));\r\n setFavorites((prev) => {\r\n const next = new Set(prev);\r\n next.delete(deleteTarget.id);\r\n return next;\r\n });\r\n toast.success(t('deleteSuccess', { name: deleteTarget.name }))\r\n } catch (err) {\r\n console.error(err);\r\n toast.error(\r\n err instanceof Error\r\n ? t('deleteFailedWithReason', { error: err.message })\r\n : t('deleteFailed'),\r\n );\r\n } finally {\r\n setIsDeleting(false)\r\n setDeleteTarget(null)\r\n }\r\n };\r\n\r\n const toggleFavorite = (id: string) => {\r\n setFavorites((prev) => {\r\n const next = new Set(prev);\r\n if (next.has(id)) next.delete(id);\r\n else next.add(id);\r\n return next;\r\n });\r\n };\r\n\r\n const filtered = React.useMemo(() => {\r\n return pointClouds.filter((pc) => {\r\n const matchesSearch =\r\n !search ||\r\n pc.name.toLowerCase().includes(search.toLowerCase()) ||\r\n pc.id.toLowerCase().includes(search.toLowerCase());\r\n\r\n let matchesStatus = true;\r\n if (statusFilter === \"uploaded\") {\r\n matchesStatus = pc.point_cloud_uploaded;\r\n } else if (statusFilter === \"converted\") {\r\n matchesStatus = pc.point_cloud_potree_converted;\r\n } else if (statusFilter === \"not-converted\") {\r\n matchesStatus =\r\n pc.point_cloud_uploaded && !pc.point_cloud_potree_converted;\r\n }\r\n\r\n return matchesSearch && matchesStatus;\r\n });\r\n }, [pointClouds, search, statusFilter]);\r\n\r\n return (\r\n <div className={`p-2 mt-20 ${divProps}`}>\r\n {/* Header */}\r\n <div className=\"flex items-start justify-between gap-4\">\r\n <div className=\"space-y-1\">\r\n <h1 className=\"text-2xl font-semibold tracking-tight\">\r\n Point Clouds\r\n </h1>\r\n </div>\r\n\r\n <div className=\"flex items-center gap-2\">\r\n <Input\r\n placeholder=\"Search point clouds...\"\r\n className=\"w-[240px]\"\r\n value={search}\r\n onChange={(e) => setSearch(e.target.value)}\r\n />\r\n <Button variant=\"outline\" size=\"icon\" title=\"Filters (not wired)\">\r\n <Filter className=\"h-4 w-4\" />\r\n </Button>\r\n <Button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n onClick={loadPointClouds}\r\n disabled={loading}\r\n title=\"Refresh\"\r\n >\r\n <RotateCcw className=\"h-4 w-4\" />\r\n </Button>\r\n </div>\r\n </div>\r\n\r\n {/* Tabs row */}\r\n <Tabs\r\n value={statusFilter}\r\n onValueChange={(val) => setStatusFilter(val as StatusFilter)}\r\n className=\"w-full mb-2\"\r\n >\r\n <TabsList className=\"h-8\">\r\n <TabsTrigger value=\"all\" className=\"px-3\">\r\n All\r\n </TabsTrigger>\r\n <TabsTrigger value=\"uploaded\" className=\"px-3\">\r\n Uploaded\r\n </TabsTrigger>\r\n <TabsTrigger value=\"converted\" className=\"px-3\">\r\n Converted\r\n </TabsTrigger>\r\n <TabsTrigger value=\"not-converted\" className=\"px-3\">\r\n Needs conversion\r\n </TabsTrigger>\r\n </TabsList>\r\n </Tabs>\r\n\r\n {/* Table card */}\r\n <div className=\"rounded-md border bg-background\">\r\n <ScrollArea className=\"max-h-[520px]\">\r\n <Table>\r\n <TableHeader className=\"sticky top-0 z-10 bg-background/95 backdrop-blur\">\r\n <TableRow>\r\n <TableHead className=\"w-[40px] pl-4\">\r\n <Checkbox aria-label=\"Select all\" />\r\n </TableHead>\r\n <TableHead className=\"w-[48px]\"></TableHead>\r\n <TableHead className=\"min-w-[220px]\">Name</TableHead>\r\n <TableHead className=\"w-[200px]\">Status</TableHead>\r\n <TableHead className=\"w-[220px]\">Created</TableHead>\r\n <TableHead className=\"w-[160px]\">Metadata</TableHead>\r\n <TableHead className=\"w-[140px] text-right pr-4\">\r\n Actions\r\n </TableHead>\r\n </TableRow>\r\n </TableHeader>\r\n\r\n <TableBody>\r\n {loading && pointClouds.length === 0 && (\r\n <TableRow>\r\n <TableCell colSpan={7} className=\"h-24 text-center\">\r\n Loading point clouds…\r\n </TableCell>\r\n </TableRow>\r\n )}\r\n\r\n {!loading && error && (\r\n <TableRow>\r\n <TableCell colSpan={7} className=\"h-24 text-center\">\r\n <span className=\"text-sm text-destructive\">\r\n {error}\r\n </span>\r\n </TableCell>\r\n </TableRow>\r\n )}\r\n\r\n {!loading && !error && filtered.length === 0 && (\r\n <TableRow>\r\n <TableCell colSpan={7} className=\"h-24 text-center\">\r\n <span className=\"text-sm text-muted-foreground\">\r\n No point clouds found.\r\n </span>\r\n </TableCell>\r\n </TableRow>\r\n )}\r\n\r\n {filtered.map((pc) => {\r\n const isFavorite = favorites.has(pc.id);\r\n return (\r\n <TableRow\r\n key={pc.id}\r\n className=\"hover:bg-muted/50 transition-colors\"\r\n >\r\n <TableCell className=\"pl-4\">\r\n <Checkbox aria-label={`Select ${pc.name}`} />\r\n </TableCell>\r\n\r\n {/* Favorite star */}\r\n <TableCell className=\"text-center\">\r\n <button\r\n type=\"button\"\r\n onClick={() => toggleFavorite(pc.id)}\r\n className=\"inline-flex h-6 w-6 items-center justify-center rounded-full text-muted-foreground hover:text-yellow-500\"\r\n aria-label={\r\n isFavorite\r\n ? `Remove ${pc.name} from favourites`\r\n : `Add ${pc.name} to favourites`\r\n }\r\n >\r\n {isFavorite ? (\r\n <Star className=\"h-4 w-4 fill-yellow-400\" />\r\n ) : (\r\n <StarOff className=\"h-4 w-4\" />\r\n )}\r\n </button>\r\n </TableCell>\r\n\r\n {/* Name & ID */}\r\n <TableCell>\r\n <div className=\"font-medium\">{pc.name}</div>\r\n <div className=\"text-xs text-muted-foreground\">\r\n {pc.id}\r\n </div>\r\n </TableCell>\r\n\r\n {/* Status badges */}\r\n <TableCell>\r\n <div className=\"flex flex-wrap gap-1\">\r\n <Badge\r\n className={`text-xs border ${\r\n pc.point_cloud_uploaded\r\n ? \"bg-emerald-50 text-emerald-700 border-emerald-200\"\r\n : \"bg-rose-50 text-rose-700 border-rose-200\"\r\n }`}\r\n >\r\n {pc.point_cloud_uploaded ? \"Uploaded\" : \"Not uploaded\"}\r\n </Badge>\r\n\r\n <Badge\r\n className={`text-xs border ${\r\n pc.point_cloud_potree_converted\r\n ? \"bg-sky-50 text-sky-700 border-sky-200\"\r\n : \"bg-amber-50 text-amber-700 border-amber-200\"\r\n }`}\r\n >\r\n {pc.point_cloud_potree_converted\r\n ? \"Ready to view\"\r\n : \"Needs conversion\"}\r\n </Badge>\r\n </div>\r\n </TableCell>\r\n\r\n {/* Created date */}\r\n <TableCell className=\"whitespace-nowrap text-sm text-muted-foreground\">\r\n {new Date(pc.createdAt).toLocaleString()}\r\n </TableCell>\r\n\r\n {/* Metadata link */}\r\n <TableCell>\r\n {pc.potree_metadata_presigned_url ? (\r\n <Button\r\n asChild\r\n variant=\"link\"\r\n size=\"sm\"\r\n className=\"px-0\"\r\n >\r\n <a\r\n href={pc.potree_metadata_presigned_url}\r\n target=\"_blank\"\r\n rel=\"noreferrer\"\r\n >\r\n metadata.json\r\n </a>\r\n </Button>\r\n ) : (\r\n <span className=\"text-xs text-muted-foreground\">—</span>\r\n )}\r\n </TableCell>\r\n\r\n {/* Actions */}\r\n <TableCell className=\"pr-4 text-right\">\r\n <div className=\"flex justify-end gap-2\">\r\n <Button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n disabled={!pc.potree_metadata_file_key}\r\n onClick={() =>\r\n openViewer(pc.id)\r\n }\r\n title=\"Open Potree viewer\"\r\n >\r\n <Eye className=\"h-4 w-4\" />\r\n </Button>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"text-destructive hover:text-destructive\"\r\n onClick={() => setDeleteTarget(pc)}\r\n title={t('deleteTitle')}\r\n >\r\n <Trash2 className=\"h-4 w-4\" />\r\n </Button>\r\n </div>\r\n </TableCell>\r\n </TableRow>\r\n );\r\n })}\r\n </TableBody>\r\n </Table>\r\n </ScrollArea>\r\n\r\n {/* Faux pagination / footer */}\r\n <div className=\"flex items-center justify-between border-t px-4 py-2 text-xs text-muted-foreground\">\r\n <div>\r\n Showing <span className=\"font-medium\">{filtered.length}</span> of{\" \"}\r\n <span className=\"font-medium\">{pointClouds.length}</span> point\r\n clouds\r\n </div>\r\n <div className=\"flex items-center gap-1\">\r\n <Button variant=\"ghost\" size=\"icon\" disabled>\r\n <ChevronLeft className=\"h-4 w-4\" />\r\n </Button>\r\n <Button variant=\"ghost\" size=\"icon\" disabled>\r\n <ChevronRight className=\"h-4 w-4\" />\r\n </Button>\r\n </div>\r\n </div>\r\n\r\n </div>\r\n\r\n <Button\r\n onClick={() => {\r\n if (onUploadButtonClick != undefined){\r\n onUploadButtonClick()\r\n }\r\n }}\r\n className=\"mt-1 flex gap-2\"\r\n >\r\n Upload point cloud →\r\n </Button>\r\n\r\n <ConfirmDialog\r\n isOpen={deleteTarget != null}\r\n isDeleting={isDeleting}\r\n onOpenChange={(open) => {\r\n if (!open) setDeleteTarget(null)\r\n }}\r\n handleConfirm={async (e) => {\r\n e.preventDefault()\r\n await handleDelete()\r\n }}\r\n itemName={deleteTarget?.name}\r\n dataType={t('pointCloudItem')}\r\n />\r\n </div>\r\n );\r\n}\r\n"],"mappings":"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","names":["PAGE","_a","pathname"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.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 {\r\n Table,\r\n TableBody,\r\n TableCell,\r\n TableHead,\r\n TableHeader,\r\n TableRow,\r\n} from \"../../../../ui/Table\";\r\n\r\nimport { Badge, Button, Checkbox, Input, ScrollArea } from '../../../../ui';\r\n\r\nimport { Tabs, TabsList, TabsTrigger } from \"../../../../ui/Tabs\";\r\n\r\nimport { useRouter, usePathname } from 'next/navigation'\r\nimport { useTranslations } from 'next-intl'\r\nimport { toast } from 'sonner'\r\nimport ConfirmDialog from '../../../../ConfirmDialog'\r\n// import { useAppConfigContext } from '../../../../../store/AppConfig/context'\r\n\r\nimport {\r\n Star,\r\n StarOff,\r\n Eye,\r\n Trash2,\r\n Filter,\r\n RotateCcw,\r\n ChevronLeft,\r\n ChevronRight,\r\n} from \"lucide-react\";\r\n\r\ntype PointCloud = {\r\n id: string;\r\n name: string;\r\n point_cloud_uploaded: boolean;\r\n point_cloud_potree_converted: boolean;\r\n createdAt: string;\r\n potree_metadata_presigned_url?: string | null;\r\n potree_metadata_file_key?: string | null;\r\n};\r\n\r\ntype StatusFilter = \"all\" | \"uploaded\" | \"converted\" | \"not-converted\";\r\n\r\nenum PAGE {\r\n TABLE = \"table\",\r\n UPLOAD = \"upload\",\r\n}\r\n\r\ntype PointCloudTableProps = React.HTMLAttributes<HTMLDivElement> & {\r\n onUploadButtonClick: () => void;\r\n pointcloudApiUrl?: string;\r\n};\r\n\r\nexport function PointCloudTable({\r\n onUploadButtonClick,\r\n pointcloudApiUrl,\r\n ...divProps\r\n}: PointCloudTableProps) {\r\n const API_BASE = pointcloudApiUrl ?? 'http://localhost:5101'\r\n const [pointClouds, setPointClouds] = React.useState<PointCloud[]>([]);\r\n const [loading, setLoading] = React.useState(false);\r\n const [error, setError] = React.useState<string | null>(null);\r\n const [search, setSearch] = React.useState(\"\");\r\n const [statusFilter, setStatusFilter] = React.useState<StatusFilter>(\"all\");\r\n const [favorites, setFavorites] = React.useState<Set<string>>(new Set());\r\n const [currentUrl, setCurrentUrl] = React.useState<URL | null>(null);\r\n const [deleteTarget, setDeleteTarget] = React.useState<PointCloud | null>(null)\r\n const [isDeleting, setIsDeleting] = React.useState(false)\r\n const t = useTranslations('PointCloudManagement')\r\n\r\n React.useEffect(() => {\r\n // This only runs in the browser\r\n const url = new URL(window.location.href);\r\n setCurrentUrl(url);\r\n }, []);\r\n\r\n const [currentPage, setCurrentPage] = React.useState<PAGE>(PAGE.TABLE)\r\n\r\n // route and navigation\r\n const router = useRouter()\r\n const pathname = usePathname()\r\n\r\n const loadPointClouds = React.useCallback(async () => {\r\n setLoading(true);\r\n setError(null);\r\n\r\n try {\r\n const res = await fetch(`${API_BASE}/point-cloud`, {\r\n headers: { \"Accept\": \"application/json\" },\r\n });\r\n\r\n if (!res.ok) {\r\n throw new Error(`Failed to fetch point clouds (${res.status})`);\r\n }\r\n\r\n const data: PointCloud[] = await res.json();\r\n setPointClouds(Array.isArray(data) ? data : []);\r\n } catch (err) {\r\n console.error(err);\r\n setError(\r\n err instanceof Error ? err.message : \"Unknown error while loading data\",\r\n );\r\n } finally {\r\n setLoading(false);\r\n }\r\n }, []);\r\n\r\n React.useEffect(() => {\r\n loadPointClouds();\r\n }, [loadPointClouds]);\r\n\r\n const openViewer = (pointCloudId) => {\r\n if (!pointCloudId) return;\r\n const origin = window.location.origin\r\n const pathname = window.location.pathname\r\n const params = new URLSearchParams(currentUrl.search)\r\n params.set('viewer', 'pointcloud')\r\n params.set('pointCloudId', pointCloudId)\r\n const newurl = `${origin}${pathname}?${params.toString()}`\r\n router.push(newurl, { scroll: false }) // push but do not refresh\r\n };\r\n\r\n const handleDelete = async () => {\r\n if (!deleteTarget) return\r\n\r\n setIsDeleting(true)\r\n\r\n try {\r\n const res = await fetch(`${API_BASE}/point-cloud/${deleteTarget.id}`, {\r\n method: \"DELETE\",\r\n });\r\n\r\n if (!res.ok) {\r\n const msg = await res.text();\r\n throw new Error(msg || `Delete failed (${res.status})`);\r\n }\r\n\r\n setPointClouds((prev) => prev.filter((pc) => pc.id !== deleteTarget.id));\r\n setFavorites((prev) => {\r\n const next = new Set(prev);\r\n next.delete(deleteTarget.id);\r\n return next;\r\n });\r\n toast.success(t('deleteSuccess', { name: deleteTarget.name }))\r\n } catch (err) {\r\n console.error(err);\r\n toast.error(\r\n err instanceof Error\r\n ? t('deleteFailedWithReason', { error: err.message })\r\n : t('deleteFailed'),\r\n );\r\n } finally {\r\n setIsDeleting(false)\r\n setDeleteTarget(null)\r\n }\r\n };\r\n\r\n const toggleFavorite = (id: string) => {\r\n setFavorites((prev) => {\r\n const next = new Set(prev);\r\n if (next.has(id)) next.delete(id);\r\n else next.add(id);\r\n return next;\r\n });\r\n };\r\n\r\n const filtered = React.useMemo(() => {\r\n return pointClouds.filter((pc) => {\r\n const matchesSearch =\r\n !search ||\r\n pc.name.toLowerCase().includes(search.toLowerCase()) ||\r\n pc.id.toLowerCase().includes(search.toLowerCase());\r\n\r\n let matchesStatus = true;\r\n if (statusFilter === \"uploaded\") {\r\n matchesStatus = pc.point_cloud_uploaded;\r\n } else if (statusFilter === \"converted\") {\r\n matchesStatus = pc.point_cloud_potree_converted;\r\n } else if (statusFilter === \"not-converted\") {\r\n matchesStatus =\r\n pc.point_cloud_uploaded && !pc.point_cloud_potree_converted;\r\n }\r\n\r\n return matchesSearch && matchesStatus;\r\n });\r\n }, [pointClouds, search, statusFilter]);\r\n\r\n return (\r\n <div className={`p-2 mt-20 ${divProps}`}>\r\n {/* Header */}\r\n <div className=\"flex items-start justify-between gap-4\">\r\n <div className=\"space-y-1\">\r\n <h1 className=\"text-2xl font-semibold tracking-tight\">\r\n Point Clouds\r\n </h1>\r\n </div>\r\n\r\n <div className=\"flex items-center gap-2\">\r\n <Input\r\n placeholder=\"Search point clouds...\"\r\n className=\"w-[240px]\"\r\n value={search}\r\n onChange={(e) => setSearch(e.target.value)}\r\n />\r\n <Button variant=\"outline\" size=\"icon\" title=\"Filters (not wired)\">\r\n <Filter className=\"h-4 w-4\" />\r\n </Button>\r\n <Button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n onClick={loadPointClouds}\r\n disabled={loading}\r\n title=\"Refresh\"\r\n >\r\n <RotateCcw className=\"h-4 w-4\" />\r\n </Button>\r\n </div>\r\n </div>\r\n\r\n {/* Tabs row */}\r\n <Tabs\r\n value={statusFilter}\r\n onValueChange={(val) => setStatusFilter(val as StatusFilter)}\r\n className=\"w-full mb-2\"\r\n >\r\n <TabsList className=\"h-8\">\r\n <TabsTrigger value=\"all\" className=\"px-3\">\r\n All\r\n </TabsTrigger>\r\n <TabsTrigger value=\"uploaded\" className=\"px-3\">\r\n Uploaded\r\n </TabsTrigger>\r\n <TabsTrigger value=\"converted\" className=\"px-3\">\r\n Converted\r\n </TabsTrigger>\r\n <TabsTrigger value=\"not-converted\" className=\"px-3\">\r\n Needs conversion\r\n </TabsTrigger>\r\n </TabsList>\r\n </Tabs>\r\n\r\n {/* Table card */}\r\n <div className=\"rounded-md border bg-background\">\r\n <ScrollArea className=\"max-h-[520px]\">\r\n <Table>\r\n <TableHeader className=\"sticky top-0 z-10 bg-background/95 backdrop-blur\">\r\n <TableRow>\r\n <TableHead className=\"w-[40px] pl-4\">\r\n <Checkbox aria-label=\"Select all\" />\r\n </TableHead>\r\n <TableHead className=\"w-[48px]\"></TableHead>\r\n <TableHead className=\"min-w-[220px]\">Name</TableHead>\r\n <TableHead className=\"w-[200px]\">Status</TableHead>\r\n <TableHead className=\"w-[220px]\">Created</TableHead>\r\n <TableHead className=\"w-[160px]\">Metadata</TableHead>\r\n <TableHead className=\"w-[140px] text-right pr-4\">\r\n Actions\r\n </TableHead>\r\n </TableRow>\r\n </TableHeader>\r\n\r\n <TableBody>\r\n {loading && pointClouds.length === 0 && (\r\n <TableRow>\r\n <TableCell colSpan={7} className=\"h-24 text-center\">\r\n Loading point clouds…\r\n </TableCell>\r\n </TableRow>\r\n )}\r\n\r\n {!loading && error && (\r\n <TableRow>\r\n <TableCell colSpan={7} className=\"h-24 text-center\">\r\n <span className=\"text-sm text-destructive\">\r\n {error}\r\n </span>\r\n </TableCell>\r\n </TableRow>\r\n )}\r\n\r\n {!loading && !error && filtered.length === 0 && (\r\n <TableRow>\r\n <TableCell colSpan={7} className=\"h-24 text-center\">\r\n <span className=\"text-sm text-muted-foreground\">\r\n No point clouds found.\r\n </span>\r\n </TableCell>\r\n </TableRow>\r\n )}\r\n\r\n {filtered.map((pc) => {\r\n const isFavorite = favorites.has(pc.id);\r\n return (\r\n <TableRow\r\n key={pc.id}\r\n className=\"hover:bg-muted/50 transition-colors\"\r\n >\r\n <TableCell className=\"pl-4\">\r\n <Checkbox aria-label={`Select ${pc.name}`} />\r\n </TableCell>\r\n\r\n {/* Favorite star */}\r\n <TableCell className=\"text-center\">\r\n <button\r\n type=\"button\"\r\n onClick={() => toggleFavorite(pc.id)}\r\n className=\"inline-flex h-6 w-6 items-center justify-center rounded-full text-muted-foreground hover:text-yellow-500\"\r\n aria-label={\r\n isFavorite\r\n ? `Remove ${pc.name} from favourites`\r\n : `Add ${pc.name} to favourites`\r\n }\r\n >\r\n {isFavorite ? (\r\n <Star className=\"h-4 w-4 fill-yellow-400\" />\r\n ) : (\r\n <StarOff className=\"h-4 w-4\" />\r\n )}\r\n </button>\r\n </TableCell>\r\n\r\n {/* Name & ID */}\r\n <TableCell>\r\n <div className=\"font-medium\">{pc.name}</div>\r\n <div className=\"text-xs text-muted-foreground\">\r\n {pc.id}\r\n </div>\r\n </TableCell>\r\n\r\n {/* Status badges */}\r\n <TableCell>\r\n <div className=\"flex flex-wrap gap-1\">\r\n <Badge\r\n className={`text-xs border ${\r\n pc.point_cloud_uploaded\r\n ? \"bg-emerald-50 text-emerald-700 border-emerald-200\"\r\n : \"bg-rose-50 text-rose-700 border-rose-200\"\r\n }`}\r\n >\r\n {pc.point_cloud_uploaded ? \"Uploaded\" : \"Not uploaded\"}\r\n </Badge>\r\n\r\n <Badge\r\n className={`text-xs border ${\r\n pc.point_cloud_potree_converted\r\n ? \"bg-sky-50 text-sky-700 border-sky-200\"\r\n : \"bg-amber-50 text-amber-700 border-amber-200\"\r\n }`}\r\n >\r\n {pc.point_cloud_potree_converted\r\n ? \"Ready to view\"\r\n : \"Needs conversion\"}\r\n </Badge>\r\n </div>\r\n </TableCell>\r\n\r\n {/* Created date */}\r\n <TableCell className=\"whitespace-nowrap text-sm text-muted-foreground\">\r\n {new Date(pc.createdAt).toLocaleString()}\r\n </TableCell>\r\n\r\n {/* Metadata link */}\r\n <TableCell>\r\n {pc.potree_metadata_presigned_url ? (\r\n <Button\r\n asChild\r\n variant=\"link\"\r\n size=\"sm\"\r\n className=\"px-0\"\r\n >\r\n <a\r\n href={pc.potree_metadata_presigned_url}\r\n target=\"_blank\"\r\n rel=\"noreferrer\"\r\n >\r\n metadata.json\r\n </a>\r\n </Button>\r\n ) : (\r\n <span className=\"text-xs text-muted-foreground\">—</span>\r\n )}\r\n </TableCell>\r\n\r\n {/* Actions */}\r\n <TableCell className=\"pr-4 text-right\">\r\n <div className=\"flex justify-end gap-2\">\r\n <Button\r\n variant=\"outline\"\r\n size=\"icon\"\r\n disabled={!pc.potree_metadata_file_key}\r\n onClick={() =>\r\n openViewer(pc.id)\r\n }\r\n title=\"Open Potree viewer\"\r\n >\r\n <Eye className=\"h-4 w-4\" />\r\n </Button>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"text-destructive hover:text-destructive\"\r\n onClick={() => setDeleteTarget(pc)}\r\n title={t('deleteTitle')}\r\n >\r\n <Trash2 className=\"h-4 w-4\" />\r\n </Button>\r\n </div>\r\n </TableCell>\r\n </TableRow>\r\n );\r\n })}\r\n </TableBody>\r\n </Table>\r\n </ScrollArea>\r\n\r\n {/* Faux pagination / footer */}\r\n <div className=\"flex items-center justify-between border-t px-4 py-2 text-xs text-muted-foreground\">\r\n <div>\r\n Showing <span className=\"font-medium\">{filtered.length}</span> of{\" \"}\r\n <span className=\"font-medium\">{pointClouds.length}</span> point\r\n clouds\r\n </div>\r\n <div className=\"flex items-center gap-1\">\r\n <Button variant=\"ghost\" size=\"icon\" disabled>\r\n <ChevronLeft className=\"h-4 w-4\" />\r\n </Button>\r\n <Button variant=\"ghost\" size=\"icon\" disabled>\r\n <ChevronRight className=\"h-4 w-4\" />\r\n </Button>\r\n </div>\r\n </div>\r\n\r\n </div>\r\n\r\n <Button\r\n onClick={() => {\r\n if (onUploadButtonClick != undefined){\r\n onUploadButtonClick()\r\n }\r\n }}\r\n className=\"mt-1 flex gap-2\"\r\n >\r\n Upload point cloud →\r\n </Button>\r\n\r\n <ConfirmDialog\r\n isOpen={deleteTarget != null}\r\n isDeleting={isDeleting}\r\n onOpenChange={(open) => {\r\n if (!open) setDeleteTarget(null)\r\n }}\r\n handleConfirm={async (e) => {\r\n e.preventDefault()\r\n await handleDelete()\r\n }}\r\n itemName={deleteTarget?.name}\r\n dataType={t('pointCloudItem')}\r\n />\r\n </div>\r\n );\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;AAqMoB,cAKJ,YALI;AAhMpB,YAAY,WAAW;AACvB;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AAEP,SAAS,OAAO,QAAQ,UAAU,OAAO,kBAAkB;AAE3D,SAAS,MAAM,UAAU,mBAAmB;AAE5C,SAAS,WAAW,mBAAmB;AACvC,SAAS,uBAAuB;AAChC,SAAS,aAAa;AACtB,OAAO,mBAAmB;AAG1B;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AAcP,IAAK,OAAL,kBAAKA,UAAL;AACI,EAAAA,MAAA,WAAQ;AACR,EAAAA,MAAA,YAAS;AAFR,SAAAA;AAAA,GAAA;AAUE,SAAS,gBAAgB,IAIP;AAJO,eAC5B;AAAA;AAAA,IACA;AAAA,EA5DJ,IA0DgC,IAGzB,qBAHyB,IAGzB;AAAA,IAFH;AAAA,IACA;AAAA;AAGA,QAAM,WAAW,8CAAoB;AACrC,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAuB,CAAC,CAAC;AACrE,QAAM,CAAC,SAAS,UAAU,IAAI,MAAM,SAAS,KAAK;AAClD,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAwB,IAAI;AAC5D,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAAS,EAAE;AAC7C,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAuB,KAAK;AAC1E,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAsB,oBAAI,IAAI,CAAC;AACvE,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAqB,IAAI;AACnE,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAA4B,IAAI;AAC9E,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,KAAK;AACxD,QAAM,IAAI,gBAAgB,sBAAsB;AAEhD,QAAM,UAAU,MAAM;AAElB,UAAM,MAAM,IAAI,IAAI,OAAO,SAAS,IAAI;AACxC,kBAAc,GAAG;AAAA,EACrB,GAAG,CAAC,CAAC;AAEL,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,SAAe,mBAAU;AAGrE,QAAM,SAAS,UAAU;AACzB,QAAM,WAAW,YAAY;AAE7B,QAAM,kBAAkB,MAAM,YAAY,YAAY;AAClD,eAAW,IAAI;AACf,aAAS,IAAI;AAEb,QAAI;AACA,YAAM,MAAM,MAAM,MAAM,GAAG,QAAQ,gBAAgB;AAAA,QAC/C,SAAS,EAAE,UAAU,mBAAmB;AAAA,MAC5C,CAAC;AAED,UAAI,CAAC,IAAI,IAAI;AACT,cAAM,IAAI,MAAM,iCAAiC,IAAI,MAAM,GAAG;AAAA,MAClE;AAEA,YAAM,OAAqB,MAAM,IAAI,KAAK;AAC1C,qBAAe,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,CAAC;AAAA,IAClD,SAAS,KAAK;AACV,cAAQ,MAAM,GAAG;AACjB;AAAA,QACI,eAAe,QAAQ,IAAI,UAAU;AAAA,MACzC;AAAA,IACJ,UAAE;AACE,iBAAW,KAAK;AAAA,IACpB;AAAA,EACJ,GAAG,CAAC,CAAC;AAEL,QAAM,UAAU,MAAM;AAClB,oBAAgB;AAAA,EACpB,GAAG,CAAC,eAAe,CAAC;AAEpB,QAAM,aAAa,CAAC,iBAAiB;AACjC,QAAI,CAAC,aAAc;AACnB,UAAM,SAAS,OAAO,SAAS;AAC/B,UAAMC,YAAW,OAAO,SAAS;AACjC,UAAM,SAAS,IAAI,gBAAgB,WAAW,MAAM;AACpD,WAAO,IAAI,UAAU,YAAY;AACjC,WAAO,IAAI,gBAAgB,YAAY;AACvC,UAAM,SAAS,GAAG,MAAM,GAAGA,SAAQ,IAAI,OAAO,SAAS,CAAC;AACxD,WAAO,KAAK,QAAQ,EAAE,QAAQ,MAAM,CAAC;AAAA,EACzC;AAEA,QAAM,eAAe,YAAY;AAC7B,QAAI,CAAC,aAAc;AAEnB,kBAAc,IAAI;AAElB,QAAI;AACA,YAAM,MAAM,MAAM,MAAM,GAAG,QAAQ,gBAAgB,aAAa,EAAE,IAAI;AAAA,QAClE,QAAQ;AAAA,MACZ,CAAC;AAED,UAAI,CAAC,IAAI,IAAI;AACT,cAAM,MAAM,MAAM,IAAI,KAAK;AAC3B,cAAM,IAAI,MAAM,OAAO,kBAAkB,IAAI,MAAM,GAAG;AAAA,MAC1D;AAEA,qBAAe,CAAC,SAAS,KAAK,OAAO,CAAC,OAAO,GAAG,OAAO,aAAa,EAAE,CAAC;AACvE,mBAAa,CAAC,SAAS;AACnB,cAAM,OAAO,IAAI,IAAI,IAAI;AACzB,aAAK,OAAO,aAAa,EAAE;AAC3B,eAAO;AAAA,MACX,CAAC;AACD,YAAM,QAAQ,EAAE,iBAAiB,EAAE,MAAM,aAAa,KAAK,CAAC,CAAC;AAAA,IACjE,SAAS,KAAK;AACV,cAAQ,MAAM,GAAG;AACjB,YAAM;AAAA,QACF,eAAe,QACT,EAAE,0BAA0B,EAAE,OAAO,IAAI,QAAQ,CAAC,IAClD,EAAE,cAAc;AAAA,MAC1B;AAAA,IACJ,UAAE;AACE,oBAAc,KAAK;AACnB,sBAAgB,IAAI;AAAA,IACxB;AAAA,EACJ;AAEA,QAAM,iBAAiB,CAAC,OAAe;AACnC,iBAAa,CAAC,SAAS;AACnB,YAAM,OAAO,IAAI,IAAI,IAAI;AACzB,UAAI,KAAK,IAAI,EAAE,EAAG,MAAK,OAAO,EAAE;AAAA,UAC3B,MAAK,IAAI,EAAE;AAChB,aAAO;AAAA,IACX,CAAC;AAAA,EACL;AAEA,QAAM,WAAW,MAAM,QAAQ,MAAM;AACjC,WAAO,YAAY,OAAO,CAAC,OAAO;AAC9B,YAAM,gBACF,CAAC,UACD,GAAG,KAAK,YAAY,EAAE,SAAS,OAAO,YAAY,CAAC,KACnD,GAAG,GAAG,YAAY,EAAE,SAAS,OAAO,YAAY,CAAC;AAErD,UAAI,gBAAgB;AACpB,UAAI,iBAAiB,YAAY;AAC7B,wBAAgB,GAAG;AAAA,MACvB,WAAW,iBAAiB,aAAa;AACrC,wBAAgB,GAAG;AAAA,MACvB,WAAW,iBAAiB,iBAAiB;AACzC,wBACI,GAAG,wBAAwB,CAAC,GAAG;AAAA,MACvC;AAEA,aAAO,iBAAiB;AAAA,IAC5B,CAAC;AAAA,EACL,GAAG,CAAC,aAAa,QAAQ,YAAY,CAAC;AAEtC,SACI,qBAAC,SAAI,WAAW,aAAa,QAAQ,IAEjC;AAAA,yBAAC,SAAI,WAAU,0CACX;AAAA,0BAAC,SAAI,WAAU,aACX,8BAAC,QAAG,WAAU,yCAAwC,0BAEtD,GACJ;AAAA,MAEA,qBAAC,SAAI,WAAU,2BACX;AAAA;AAAA,UAAC;AAAA;AAAA,YACG,aAAY;AAAA,YACZ,WAAU;AAAA,YACV,OAAO;AAAA,YACP,UAAU,CAAC,MAAM,UAAU,EAAE,OAAO,KAAK;AAAA;AAAA,QAC7C;AAAA,QACA,oBAAC,UAAO,SAAQ,WAAU,MAAK,QAAO,OAAM,uBACxC,8BAAC,UAAO,WAAU,WAAU,GAChC;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACG,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,SAAS;AAAA,YACT,UAAU;AAAA,YACV,OAAM;AAAA,YAEN,8BAAC,aAAU,WAAU,WAAU;AAAA;AAAA,QACnC;AAAA,SACJ;AAAA,OACJ;AAAA,IAGA;AAAA,MAAC;AAAA;AAAA,QACG,OAAO;AAAA,QACP,eAAe,CAAC,QAAQ,gBAAgB,GAAmB;AAAA,QAC3D,WAAU;AAAA,QAEV,+BAAC,YAAS,WAAU,OAChB;AAAA,8BAAC,eAAY,OAAM,OAAM,WAAU,QAAO,iBAE1C;AAAA,UACA,oBAAC,eAAY,OAAM,YAAW,WAAU,QAAO,sBAE/C;AAAA,UACA,oBAAC,eAAY,OAAM,aAAY,WAAU,QAAO,uBAEhD;AAAA,UACA,oBAAC,eAAY,OAAM,iBAAgB,WAAU,QAAO,8BAEpD;AAAA,WACJ;AAAA;AAAA,IACJ;AAAA,IAGA,qBAAC,SAAI,WAAU,mCACX;AAAA,0BAAC,cAAW,WAAU,iBAClB,+BAAC,SACG;AAAA,4BAAC,eAAY,WAAU,oDACnB,+BAAC,YACG;AAAA,8BAAC,aAAU,WAAU,iBACjB,8BAAC,YAAS,cAAW,cAAa,GACtC;AAAA,UACA,oBAAC,aAAU,WAAU,YAAW;AAAA,UAChC,oBAAC,aAAU,WAAU,iBAAgB,kBAAI;AAAA,UACzC,oBAAC,aAAU,WAAU,aAAY,oBAAM;AAAA,UACvC,oBAAC,aAAU,WAAU,aAAY,qBAAO;AAAA,UACxC,oBAAC,aAAU,WAAU,aAAY,sBAAQ;AAAA,UACzC,oBAAC,aAAU,WAAU,6BAA4B,qBAEjD;AAAA,WACJ,GACJ;AAAA,QAEA,qBAAC,aACI;AAAA,qBAAW,YAAY,WAAW,KAC/B,oBAAC,YACG,8BAAC,aAAU,SAAS,GAAG,WAAU,oBAAmB,wCAEpD,GACJ;AAAA,UAGH,CAAC,WAAW,SACT,oBAAC,YACG,8BAAC,aAAU,SAAS,GAAG,WAAU,oBAC7B,8BAAC,UAAK,WAAU,4BACX,iBACL,GACJ,GACJ;AAAA,UAGH,CAAC,WAAW,CAAC,SAAS,SAAS,WAAW,KACvC,oBAAC,YACG,8BAAC,aAAU,SAAS,GAAG,WAAU,oBAC7B,8BAAC,UAAK,WAAU,iCAAgC,oCAEhD,GACJ,GACJ;AAAA,UAGH,SAAS,IAAI,CAAC,OAAO;AAClB,kBAAM,aAAa,UAAU,IAAI,GAAG,EAAE;AACtC,mBACI;AAAA,cAAC;AAAA;AAAA,gBAEG,WAAU;AAAA,gBAEV;AAAA,sCAAC,aAAU,WAAU,QACjB,8BAAC,YAAS,cAAY,UAAU,GAAG,IAAI,IAAI,GAC/C;AAAA,kBAGA,oBAAC,aAAU,WAAU,eACjB;AAAA,oBAAC;AAAA;AAAA,sBACG,MAAK;AAAA,sBACL,SAAS,MAAM,eAAe,GAAG,EAAE;AAAA,sBACnC,WAAU;AAAA,sBACV,cACI,aACM,UAAU,GAAG,IAAI,qBACjB,OAAO,GAAG,IAAI;AAAA,sBAGvB,uBACG,oBAAC,QAAK,WAAU,2BAA0B,IAE1C,oBAAC,WAAQ,WAAU,WAAU;AAAA;AAAA,kBAErC,GACJ;AAAA,kBAGA,qBAAC,aACG;AAAA,wCAAC,SAAI,WAAU,eAAe,aAAG,MAAK;AAAA,oBACtC,oBAAC,SAAI,WAAU,iCACV,aAAG,IACR;AAAA,qBACJ;AAAA,kBAGD,oBAAC,aACI,+BAAC,SAAI,WAAU,wBACX;AAAA;AAAA,sBAAC;AAAA;AAAA,wBACD,WAAW,kBACP,GAAG,uBACD,sDACA,0CACN;AAAA,wBAEC,aAAG,uBAAuB,aAAa;AAAA;AAAA,oBACxC;AAAA,oBAEA;AAAA,sBAAC;AAAA;AAAA,wBACD,WAAW,kBACP,GAAG,+BACD,0CACA,6CACN;AAAA,wBAEC,aAAG,+BACE,kBACA;AAAA;AAAA,oBACN;AAAA,qBACJ,GACJ;AAAA,kBAGA,oBAAC,aAAU,WAAU,mDAChB,cAAI,KAAK,GAAG,SAAS,EAAE,eAAe,GAC3C;AAAA,kBAGA,oBAAC,aACI,aAAG,gCACA;AAAA,oBAAC;AAAA;AAAA,sBACG,SAAO;AAAA,sBACP,SAAQ;AAAA,sBACR,MAAK;AAAA,sBACL,WAAU;AAAA,sBAEV;AAAA,wBAAC;AAAA;AAAA,0BACG,MAAM,GAAG;AAAA,0BACT,QAAO;AAAA,0BACP,KAAI;AAAA,0BACP;AAAA;AAAA,sBAED;AAAA;AAAA,kBACJ,IAEA,oBAAC,UAAK,WAAU,iCAAgC,oBAAC,GAEzD;AAAA,kBAGA,oBAAC,aAAU,WAAU,mBACjB,+BAAC,SAAI,WAAU,0BACX;AAAA;AAAA,sBAAC;AAAA;AAAA,wBACG,SAAQ;AAAA,wBACR,MAAK;AAAA,wBACL,UAAU,CAAC,GAAG;AAAA,wBACd,SAAS,MACL,WAAW,GAAG,EAAE;AAAA,wBAEpB,OAAM;AAAA,wBAEN,8BAAC,OAAI,WAAU,WAAU;AAAA;AAAA,oBAC7B;AAAA,oBACA;AAAA,sBAAC;AAAA;AAAA,wBACG,SAAQ;AAAA,wBACR,MAAK;AAAA,wBACL,WAAU;AAAA,wBACV,SAAS,MAAM,gBAAgB,EAAE;AAAA,wBACjC,OAAO,EAAE,aAAa;AAAA,wBAEtB,8BAAC,UAAO,WAAU,WAAU;AAAA;AAAA,oBAChC;AAAA,qBACJ,GACJ;AAAA;AAAA;AAAA,cAjHK,GAAG;AAAA,YAkHZ;AAAA,UAER,CAAC;AAAA,WACL;AAAA,SACJ,GACJ;AAAA,MAGA,qBAAC,SAAI,WAAU,sFACX;AAAA,6BAAC,SAAI;AAAA;AAAA,UACO,oBAAC,UAAK,WAAU,eAAe,mBAAS,QAAO;AAAA,UAAO;AAAA,UAAI;AAAA,UAClE,oBAAC,UAAK,WAAU,eAAe,sBAAY,QAAO;AAAA,UAAO;AAAA,WAE7D;AAAA,QACA,qBAAC,SAAI,WAAU,2BACX;AAAA,8BAAC,UAAO,SAAQ,SAAQ,MAAK,QAAO,UAAQ,MACxC,8BAAC,eAAY,WAAU,WAAU,GACrC;AAAA,UACA,oBAAC,UAAO,SAAQ,SAAQ,MAAK,QAAO,UAAQ,MACxC,8BAAC,gBAAa,WAAU,WAAU,GACtC;AAAA,WACJ;AAAA,SACJ;AAAA,OAEJ;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACG,SAAS,MAAM;AACX,cAAI,uBAAuB,QAAU;AACjC,gCAAoB;AAAA,UACxB;AAAA,QACJ;AAAA,QACA,WAAU;AAAA,QACb;AAAA;AAAA,IAED;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACG,QAAQ,gBAAgB;AAAA,QACxB;AAAA,QACA,cAAc,CAAC,SAAS;AACpB,cAAI,CAAC,KAAM,iBAAgB,IAAI;AAAA,QACnC;AAAA,QACA,eAAe,OAAO,MAAM;AACxB,YAAE,eAAe;AACjB,gBAAM,aAAa;AAAA,QACvB;AAAA,QACA,UAAU,6CAAc;AAAA,QACxB,UAAU,EAAE,gBAAgB;AAAA;AAAA,IAChC;AAAA,KACJ;AAER;","names":["PAGE","pathname"]}
|
package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
type UploadPointCloudPageProps = {
|
|
3
3
|
onGoBackButtonClick?: () => void;
|
|
4
|
+
pointcloudApiUrl?: string;
|
|
4
5
|
};
|
|
5
|
-
export default function UploadPointCloudPage({ onGoBackButtonClick, }: UploadPointCloudPageProps): React.JSX.Element;
|
|
6
|
+
export default function UploadPointCloudPage({ onGoBackButtonClick, pointcloudApiUrl, }: UploadPointCloudPageProps): React.JSX.Element;
|
|
6
7
|
export {};
|
|
7
8
|
//# sourceMappingURL=PointCloudUploadPanel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PointCloudUploadPanel.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAyC/B,KAAK,yBAAyB,GAAG;IAC/B,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"PointCloudUploadPanel.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAyC/B,KAAK,yBAAyB,GAAG;IAC/B,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,oBAAoB,CAAC,EAC3C,mBAAmB,EACnB,gBAAgB,GACjB,EAAE,yBAAyB,qBA2X3B"}
|
package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.js
CHANGED
|
@@ -5,7 +5,7 @@ import { useSession } from "next-auth/react";
|
|
|
5
5
|
import { useOrganization } from "../../../../../hooks/organizations/organizations";
|
|
6
6
|
import { ProgressBar } from "../../../map/src/tools/AddTools/AddFile/ProgressBar";
|
|
7
7
|
import { Button, Input, ScrollArea } from "../../../../ui";
|
|
8
|
-
import {
|
|
8
|
+
import { toast } from "sonner";
|
|
9
9
|
const CONVERSION_STATUS = Object.freeze({
|
|
10
10
|
STARTED: "conversion_started",
|
|
11
11
|
DOWNLOAD: "download",
|
|
@@ -16,16 +16,17 @@ const CONVERSION_STATUS = Object.freeze({
|
|
|
16
16
|
FINISHED: "finished"
|
|
17
17
|
});
|
|
18
18
|
function UploadPointCloudPage({
|
|
19
|
-
onGoBackButtonClick
|
|
19
|
+
onGoBackButtonClick,
|
|
20
|
+
pointcloudApiUrl
|
|
20
21
|
}) {
|
|
21
|
-
var _a, _b
|
|
22
|
-
const
|
|
23
|
-
const API_BASE = (_a = appConfigState.runtimeConfig.pointcloudApiUrl) != null ? _a : "http://localhost:5101";
|
|
22
|
+
var _a, _b;
|
|
23
|
+
const API_BASE = pointcloudApiUrl != null ? pointcloudApiUrl : "http://localhost:5101";
|
|
24
24
|
const { data: session } = useSession();
|
|
25
|
-
const organizationId = (
|
|
25
|
+
const organizationId = (_b = (_a = session == null ? void 0 : session.user) == null ? void 0 : _a.organizationId) != null ? _b : null;
|
|
26
26
|
const { organization } = useOrganization(organizationId ? organizationId.toString() : null);
|
|
27
27
|
const [name, setName] = React.useState("");
|
|
28
28
|
const [file, setFile] = React.useState(null);
|
|
29
|
+
const [uploadSuccess, setUploadSuccess] = React.useState(false);
|
|
29
30
|
const [progress, setProgress] = React.useState(0);
|
|
30
31
|
const [status, setStatus] = React.useState("idle");
|
|
31
32
|
const [pointCloudId, setPointCloudId] = React.useState(null);
|
|
@@ -111,7 +112,7 @@ function UploadPointCloudPage({
|
|
|
111
112
|
);
|
|
112
113
|
};
|
|
113
114
|
es.addEventListener("progress", (event) => {
|
|
114
|
-
var _a2, _b2,
|
|
115
|
+
var _a2, _b2, _c;
|
|
115
116
|
try {
|
|
116
117
|
const msgEvent = event;
|
|
117
118
|
const data = JSON.parse(msgEvent.data);
|
|
@@ -119,7 +120,7 @@ function UploadPointCloudPage({
|
|
|
119
120
|
"[progress]",
|
|
120
121
|
(_a2 = data.status) != null ? _a2 : "",
|
|
121
122
|
(_b2 = data.message) != null ? _b2 : "",
|
|
122
|
-
(
|
|
123
|
+
(_c = data.progress) != null ? _c : ""
|
|
123
124
|
);
|
|
124
125
|
if (data.status && Object.values(CONVERSION_STATUS).includes(data.status)) {
|
|
125
126
|
setStatus(data.status);
|
|
@@ -135,6 +136,7 @@ function UploadPointCloudPage({
|
|
|
135
136
|
appendLog("[finished] Conversion completed");
|
|
136
137
|
setStatus(CONVERSION_STATUS.FINISHED);
|
|
137
138
|
setProgress(100);
|
|
139
|
+
toast.success("Point cloud conversion completed");
|
|
138
140
|
es.close();
|
|
139
141
|
esRef.current = null;
|
|
140
142
|
});
|
|
@@ -163,6 +165,7 @@ function UploadPointCloudPage({
|
|
|
163
165
|
setPointCloudId(null);
|
|
164
166
|
setJobId(null);
|
|
165
167
|
setStatus("idle");
|
|
168
|
+
setUploadSuccess(false);
|
|
166
169
|
try {
|
|
167
170
|
appendLog("\u{1F7E6} 1) Creating point cloud...");
|
|
168
171
|
setStatus("creating");
|
|
@@ -177,6 +180,8 @@ function UploadPointCloudPage({
|
|
|
177
180
|
(pct) => setProgress(pct)
|
|
178
181
|
);
|
|
179
182
|
appendLog("\u2714 Upload finished");
|
|
183
|
+
setUploadSuccess(true);
|
|
184
|
+
toast.success("LAZ file uploaded successfully", { duration: 6e3 });
|
|
180
185
|
appendLog("\u{1F7E6} 3) Starting conversion...");
|
|
181
186
|
setStatus(CONVERSION_STATUS.STARTED);
|
|
182
187
|
const conversion = await startConversion(pointCloud.id);
|
|
@@ -301,7 +306,8 @@ function UploadPointCloudPage({
|
|
|
301
306
|
] })
|
|
302
307
|
] }),
|
|
303
308
|
/* @__PURE__ */ jsx(ProgressBar, { value: progress })
|
|
304
|
-
] })
|
|
309
|
+
] }),
|
|
310
|
+
uploadSuccess && /* @__PURE__ */ jsx("div", { className: "rounded-md bg-green-50 border border-green-200 px-3 py-2 text-sm text-green-800 font-medium", children: "\u2714 LAZ file uploaded successfully \u2014 conversion in progress" })
|
|
305
311
|
] })
|
|
306
312
|
] }),
|
|
307
313
|
/* @__PURE__ */ jsxs("div", { className: "rounded-md border bg-muted/20 p-3 flex flex-col gap-2", children: [
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.tsx"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// app/point-clouds/upload/page.tsx\r\n\"use client\";\r\n\r\nimport * as React from \"react\";\r\n\r\nimport { useSession } from \"next-auth/react\";\r\nimport { useOrganization } from \"../../../../../hooks/organizations/organizations\";\r\nimport { ProgressBar } from \"../../../map/src/tools/AddTools/AddFile/ProgressBar\";\r\nimport { Button, Input, ScrollArea } from '../../../../ui';\r\nimport { useAppConfigContext } from '../../../../../store/AppConfig/context'\r\n\r\nconst CONVERSION_STATUS = Object.freeze({\r\n STARTED: \"conversion_started\",\r\n DOWNLOAD: \"download\",\r\n CONVERT: \"convert\",\r\n UPLOAD: \"upload\",\r\n CLEAN_UP: \"clean_up\",\r\n FAILED: \"failed\",\r\n FINISHED: \"finished\",\r\n});\r\n\r\n// All possible status values:\r\n// - local client-only phases: \"idle\", \"creating\", \"uploading\"\r\n// - plus all statuses from the backend (CONVERSION_STATUS values)\r\ntype ConversionStatus =\r\n | \"idle\"\r\n | \"creating\"\r\n | \"uploading\"\r\n | (typeof CONVERSION_STATUS)[keyof typeof CONVERSION_STATUS];\r\n\r\ntype CreatePointCloudResponse = {\r\n pointCloud: {\r\n id: string;\r\n name: string;\r\n };\r\n upload: {\r\n uploadUrl: string;\r\n };\r\n};\r\n\r\ntype StartConversionResponse = {\r\n jobId: string;\r\n};\r\n\r\ntype UploadPointCloudPageProps = {\r\n onGoBackButtonClick?: () => void;\r\n};\r\n\r\nexport default function UploadPointCloudPage({\r\n onGoBackButtonClick,\r\n}: UploadPointCloudPageProps) {\r\n const { state: appConfigState } = useAppConfigContext()\r\n const API_BASE = appConfigState.runtimeConfig.pointcloudApiUrl ?? 'http://localhost:5101'\r\n const { data: session } = useSession();\r\n const organizationId = session?.user?.organizationId ?? null;\r\n const { organization } = useOrganization(organizationId ? organizationId.toString() : null);\r\n\r\n const [name, setName] = React.useState(\"\");\r\n const [file, setFile] = React.useState<File | null>(null);\r\n\r\n const [progress, setProgress] = React.useState(0);\r\n const [status, setStatus] = React.useState<ConversionStatus>(\"idle\");\r\n const [pointCloudId, setPointCloudId] = React.useState<string | null>(null);\r\n const [jobId, setJobId] = React.useState<string | null>(null);\r\n const [logLines, setLogLines] = React.useState<string[]>([]);\r\n\r\n const esRef = React.useRef<EventSource | null>(null);\r\n\r\n const appendLog = React.useCallback((...parts: unknown[]) => {\r\n const line = parts\r\n .map((p) => (typeof p === \"string\" ? p : JSON.stringify(p, null, 2)))\r\n .join(\" \");\r\n setLogLines((prev) => [...prev, line]);\r\n }, []);\r\n\r\n React.useEffect(() => {\r\n return () => {\r\n if (esRef.current) {\r\n esRef.current.close();\r\n }\r\n };\r\n }, []);\r\n\r\n async function createPointCloud(\r\n name: string,\r\n ): Promise<CreatePointCloudResponse> {\r\n const res = await fetch(`${API_BASE}/point-cloud`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ name, organizationId, organizationName: organization?.name }),\r\n });\r\n\r\n if (!res.ok) {\r\n const msg = await res.text();\r\n throw new Error(`Create point-cloud failed: ${msg || res.status}`);\r\n }\r\n\r\n return res.json();\r\n }\r\n\r\n function uploadToPresignedUrl(\r\n url: string,\r\n file: File,\r\n onProgress: (pct: number) => void,\r\n ): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n try {\r\n const xhr = new XMLHttpRequest();\r\n xhr.open(\"PUT\", url, true);\r\n\r\n xhr.upload.onprogress = (evt) => {\r\n if (evt.lengthComputable) {\r\n const pct = Math.round((evt.loaded / evt.total) * 100);\r\n onProgress(pct);\r\n }\r\n };\r\n\r\n xhr.onload = () => {\r\n if (xhr.status >= 200 && xhr.status < 300) resolve();\r\n else reject(new Error(`Upload failed with status ${xhr.status}`));\r\n };\r\n\r\n xhr.onerror = () => reject(new Error(\"Network error during upload\"));\r\n xhr.send(file);\r\n } catch (err) {\r\n reject(err);\r\n }\r\n });\r\n }\r\n\r\n async function startConversion(\r\n pointCloudId: string,\r\n ): Promise<StartConversionResponse> {\r\n const res = await fetch(\r\n `${API_BASE}/point-cloud/${encodeURIComponent(\r\n pointCloudId,\r\n )}/convert-to-potree`,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ options: { sampling_method: \"poisson\" } }),\r\n },\r\n );\r\n\r\n if (!res.ok) {\r\n const msg = await res.text();\r\n throw new Error(`convert-to-potree failed: ${msg || res.status}`);\r\n }\r\n\r\n return res.json();\r\n }\r\n\r\n function subscribeToProgress(jobId: string) {\r\n if (!jobId) return;\r\n\r\n if (esRef.current) {\r\n esRef.current.close();\r\n }\r\n\r\n const es = new EventSource(\r\n `${API_BASE}/events/convert-progress/${encodeURIComponent(jobId)}`,\r\n );\r\n esRef.current = es;\r\n\r\n es.onopen = () => appendLog(\"🟢 SSE connection opened\");\r\n\r\n es.onerror = (event) => {\r\n appendLog(\"❌ SSE error:\", event);\r\n setStatus((prev) =>\r\n prev === CONVERSION_STATUS.FINISHED ? prev : CONVERSION_STATUS.FAILED,\r\n );\r\n };\r\n\r\n es.addEventListener(\"progress\", (event) => {\r\n try {\r\n const msgEvent = event as MessageEvent;\r\n const data = JSON.parse(msgEvent.data);\r\n\r\n appendLog(\r\n \"[progress]\",\r\n data.status ?? \"\",\r\n data.message ?? \"\",\r\n data.progress ?? \"\",\r\n );\r\n\r\n // If backend sends a status field matching our constants, use it\r\n if (\r\n data.status &&\r\n Object.values(CONVERSION_STATUS).includes(data.status)\r\n ) {\r\n setStatus(data.status as ConversionStatus);\r\n }\r\n\r\n if (typeof data.progress === \"number\") {\r\n setProgress(data.progress);\r\n }\r\n } catch (err) {\r\n appendLog(\"❌ Failed to parse progress event\", err);\r\n }\r\n });\r\n\r\n es.addEventListener(\"finished\", () => {\r\n appendLog(\"[finished] Conversion completed\");\r\n setStatus(CONVERSION_STATUS.FINISHED);\r\n setProgress(100);\r\n es.close();\r\n esRef.current = null;\r\n });\r\n\r\n es.addEventListener(\"failed\", () => {\r\n appendLog(\"[failed] Conversion failed\");\r\n setStatus(CONVERSION_STATUS.FAILED);\r\n es.close();\r\n esRef.current = null;\r\n });\r\n\r\n es.addEventListener(\"connected\", (event) => {\r\n const msgEvent = event as MessageEvent;\r\n appendLog(\"[connected]\", msgEvent.data);\r\n });\r\n\r\n es.onmessage = (event) => {\r\n appendLog(\"[message]\", event.data);\r\n };\r\n }\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!name.trim() || !file) {\r\n alert(\"Please provide a name and select a LAZ/LAS file.\");\r\n return;\r\n }\r\n\r\n setLogLines([]);\r\n setProgress(0);\r\n setPointCloudId(null);\r\n setJobId(null);\r\n setStatus(\"idle\");\r\n\r\n try {\r\n appendLog(\"🟦 1) Creating point cloud...\");\r\n setStatus(\"creating\");\r\n\r\n const { pointCloud, upload } = await createPointCloud(name.trim());\r\n appendLog(pointCloud);\r\n setPointCloudId(pointCloud.id);\r\n\r\n appendLog(\"🟦 2) Uploading to presigned URL...\");\r\n setStatus(\"uploading\");\r\n await uploadToPresignedUrl(upload.uploadUrl, file, (pct) =>\r\n setProgress(pct),\r\n );\r\n appendLog(\"✔ Upload finished\");\r\n\r\n appendLog(\"🟦 3) Starting conversion...\");\r\n // Mark that the conversion has started (using backend status constant)\r\n setStatus(CONVERSION_STATUS.STARTED);\r\n const conversion = await startConversion(pointCloud.id);\r\n appendLog(conversion);\r\n\r\n const jobId = conversion.jobId;\r\n setJobId(jobId);\r\n\r\n appendLog(\"🟦 4) Subscribing to SSE…\");\r\n subscribeToProgress(jobId);\r\n } catch (err) {\r\n const message =\r\n err instanceof Error ? err.message : \"Unknown upload error\";\r\n appendLog(\"🔥 ERROR:\", message);\r\n setStatus(CONVERSION_STATUS.FAILED);\r\n alert(message);\r\n }\r\n };\r\n\r\n const busy =\r\n status !== \"idle\" &&\r\n status !== CONVERSION_STATUS.FINISHED &&\r\n status !== CONVERSION_STATUS.FAILED;\r\n\r\n const statusLabel: string = (() => {\r\n switch (status) {\r\n case \"idle\":\r\n return \"Idle\";\r\n case \"creating\":\r\n return \"Creating point cloud…\";\r\n case \"uploading\":\r\n return \"Uploading LAZ…\";\r\n\r\n case CONVERSION_STATUS.STARTED:\r\n return \"Conversion started…\";\r\n case CONVERSION_STATUS.DOWNLOAD:\r\n return \"Downloading source file…\";\r\n case CONVERSION_STATUS.CONVERT:\r\n return \"Running Potree converter…\";\r\n case CONVERSION_STATUS.UPLOAD:\r\n return \"Uploading Potree output…\";\r\n case CONVERSION_STATUS.CLEAN_UP:\r\n return \"Cleaning up temporary files…\";\r\n case CONVERSION_STATUS.FINISHED:\r\n return \"Done 🎉\";\r\n case CONVERSION_STATUS.FAILED:\r\n return \"Error – see log\";\r\n default:\r\n return \"Unknown status\";\r\n }\r\n })();\r\n\r\n return (\r\n <div className=\"p-2 mt-16\">\r\n <div className=\"flex items-center justify-between gap-2 mb-4\">\r\n <div>\r\n <h1 className=\"text-2xl font-semibold tracking-tight\">\r\n Upload & Convert Point Cloud\r\n </h1>\r\n </div>\r\n\r\n <Button\r\n variant=\"outline\"\r\n onClick={() => {\r\n if (onGoBackButtonClick) onGoBackButtonClick();\r\n }}\r\n >\r\n ← Back to list\r\n </Button>\r\n </div>\r\n\r\n <div className=\"grid gap-4 md:grid-cols-[2fr,1.2fr]\">\r\n {/* Upload card */}\r\n <div className=\"rounded-md border bg-background p-4 space-y-4\">\r\n <div className=\"flex items-center justify-between gap-2 text-sm\">\r\n <span className=\"font-semibold\">Upload point cloud</span>\r\n <span className=\"text-xs text-muted-foreground\">\r\n {statusLabel}\r\n </span>\r\n </div>\r\n\r\n <form onSubmit={handleSubmit} className=\"space-y-3 text-sm\">\r\n <div className=\"space-y-1\">\r\n <div className=\"text-xs font-medium\">Name</div>\r\n <Input\r\n placeholder=\"e.g. Campus north wing\"\r\n value={name}\r\n onChange={(e) => setName(e.target.value)}\r\n />\r\n </div>\r\n\r\n <div className=\"space-y-1\">\r\n <div className=\"text-xs font-medium\">LAZ / LAS file</div>\r\n <Input\r\n type=\"file\"\r\n accept=\".laz,.las\"\r\n onChange={(e) => {\r\n const f = e.target.files?.[0] ?? null;\r\n setFile(f);\r\n }}\r\n />\r\n {file && (\r\n <div className=\"text-[11px] text-muted-foreground\">\r\n Selected: <span className=\"font-medium\">{file.name}</span>\r\n </div>\r\n )}\r\n </div>\r\n\r\n <div className=\"flex items-center gap-3\">\r\n <Button\r\n type=\"submit\"\r\n disabled={!name.trim() || !file || busy}\r\n size=\"sm\"\r\n >\r\n {busy ? \"Working...\" : \"Upload & Convert\"}\r\n </Button>\r\n\r\n <div className=\"flex flex-col text-[11px] text-muted-foreground\">\r\n <span>\r\n PointCloud ID:{\" \"}\r\n <code className=\"text-xs\">{pointCloudId ?? \"—\"}</code>\r\n </span>\r\n <span>\r\n Job ID: <code className=\"text-xs\">{jobId ?? \"—\"}</code>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <div className=\"space-y-1\">\r\n <div className=\"flex items-center justify-between text-[11px] text-muted-foreground\">\r\n <span>Upload / conversion progress</span>\r\n <span>{progress}%</span>\r\n </div>\r\n <ProgressBar value={progress} />\r\n </div>\r\n </form>\r\n </div>\r\n\r\n {/* Log card */}\r\n <div className=\"rounded-md border bg-muted/20 p-3 flex flex-col gap-2\">\r\n <div className=\"flex items-center justify-between text-xs\">\r\n <h2 className=\"font-semibold uppercase tracking-wide\">\r\n Conversion log\r\n </h2>\r\n <Button\r\n type=\"button\"\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n className=\"h-6 px-2 text-[11px]\"\r\n onClick={() => setLogLines([])}\r\n >\r\n Clear\r\n </Button>\r\n </div>\r\n\r\n <ScrollArea className=\"h-[200px] rounded border bg-background\">\r\n <pre className=\"p-2 text-[11px] leading-snug whitespace-pre-wrap\">\r\n {logLines.length ? logLines.join(\"\\n\") : \"No activity yet.\"}\r\n </pre>\r\n </ScrollArea>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"mappings":"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","names":["name","file","pointCloudId","jobId","_a","_b","_c"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.tsx"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// app/point-clouds/upload/page.tsx\r\n\"use client\";\r\n\r\nimport * as React from \"react\";\r\n\r\nimport { useSession } from \"next-auth/react\";\r\nimport { useOrganization } from \"../../../../../hooks/organizations/organizations\";\r\nimport { ProgressBar } from \"../../../map/src/tools/AddTools/AddFile/ProgressBar\";\r\nimport { Button, Input, ScrollArea } from '../../../../ui';\r\nimport { toast } from 'sonner'\r\n\r\nconst CONVERSION_STATUS = Object.freeze({\r\n STARTED: \"conversion_started\",\r\n DOWNLOAD: \"download\",\r\n CONVERT: \"convert\",\r\n UPLOAD: \"upload\",\r\n CLEAN_UP: \"clean_up\",\r\n FAILED: \"failed\",\r\n FINISHED: \"finished\",\r\n});\r\n\r\n// All possible status values:\r\n// - local client-only phases: \"idle\", \"creating\", \"uploading\"\r\n// - plus all statuses from the backend (CONVERSION_STATUS values)\r\ntype ConversionStatus =\r\n | \"idle\"\r\n | \"creating\"\r\n | \"uploading\"\r\n | (typeof CONVERSION_STATUS)[keyof typeof CONVERSION_STATUS];\r\n\r\ntype CreatePointCloudResponse = {\r\n pointCloud: {\r\n id: string;\r\n name: string;\r\n };\r\n upload: {\r\n uploadUrl: string;\r\n };\r\n};\r\n\r\ntype StartConversionResponse = {\r\n jobId: string;\r\n};\r\n\r\ntype UploadPointCloudPageProps = {\r\n onGoBackButtonClick?: () => void;\r\n pointcloudApiUrl?: string;\r\n};\r\n\r\nexport default function UploadPointCloudPage({\r\n onGoBackButtonClick,\r\n pointcloudApiUrl,\r\n}: UploadPointCloudPageProps) {\r\n const API_BASE = pointcloudApiUrl ?? 'http://localhost:5101'\r\n const { data: session } = useSession();\r\n const organizationId = session?.user?.organizationId ?? null;\r\n const { organization } = useOrganization(organizationId ? organizationId.toString() : null);\r\n\r\n const [name, setName] = React.useState(\"\");\r\n const [file, setFile] = React.useState<File | null>(null);\r\n const [uploadSuccess, setUploadSuccess] = React.useState(false);\r\n\r\n const [progress, setProgress] = React.useState(0);\r\n const [status, setStatus] = React.useState<ConversionStatus>(\"idle\");\r\n const [pointCloudId, setPointCloudId] = React.useState<string | null>(null);\r\n const [jobId, setJobId] = React.useState<string | null>(null);\r\n const [logLines, setLogLines] = React.useState<string[]>([]);\r\n\r\n const esRef = React.useRef<EventSource | null>(null);\r\n\r\n const appendLog = React.useCallback((...parts: unknown[]) => {\r\n const line = parts\r\n .map((p) => (typeof p === \"string\" ? p : JSON.stringify(p, null, 2)))\r\n .join(\" \");\r\n setLogLines((prev) => [...prev, line]);\r\n }, []);\r\n\r\n React.useEffect(() => {\r\n return () => {\r\n if (esRef.current) {\r\n esRef.current.close();\r\n }\r\n };\r\n }, []);\r\n\r\n async function createPointCloud(\r\n name: string,\r\n ): Promise<CreatePointCloudResponse> {\r\n const res = await fetch(`${API_BASE}/point-cloud`, {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ name, organizationId, organizationName: organization?.name }),\r\n });\r\n\r\n if (!res.ok) {\r\n const msg = await res.text();\r\n throw new Error(`Create point-cloud failed: ${msg || res.status}`);\r\n }\r\n\r\n return res.json();\r\n }\r\n\r\n function uploadToPresignedUrl(\r\n url: string,\r\n file: File,\r\n onProgress: (pct: number) => void,\r\n ): Promise<void> {\r\n return new Promise((resolve, reject) => {\r\n try {\r\n const xhr = new XMLHttpRequest();\r\n xhr.open(\"PUT\", url, true);\r\n\r\n xhr.upload.onprogress = (evt) => {\r\n if (evt.lengthComputable) {\r\n const pct = Math.round((evt.loaded / evt.total) * 100);\r\n onProgress(pct);\r\n }\r\n };\r\n\r\n xhr.onload = () => {\r\n if (xhr.status >= 200 && xhr.status < 300) resolve();\r\n else reject(new Error(`Upload failed with status ${xhr.status}`));\r\n };\r\n\r\n xhr.onerror = () => reject(new Error(\"Network error during upload\"));\r\n xhr.send(file);\r\n } catch (err) {\r\n reject(err);\r\n }\r\n });\r\n }\r\n\r\n async function startConversion(\r\n pointCloudId: string,\r\n ): Promise<StartConversionResponse> {\r\n const res = await fetch(\r\n `${API_BASE}/point-cloud/${encodeURIComponent(\r\n pointCloudId,\r\n )}/convert-to-potree`,\r\n {\r\n method: \"POST\",\r\n headers: { \"Content-Type\": \"application/json\" },\r\n body: JSON.stringify({ options: { sampling_method: \"poisson\" } }),\r\n },\r\n );\r\n\r\n if (!res.ok) {\r\n const msg = await res.text();\r\n throw new Error(`convert-to-potree failed: ${msg || res.status}`);\r\n }\r\n\r\n return res.json();\r\n }\r\n\r\n function subscribeToProgress(jobId: string) {\r\n if (!jobId) return;\r\n\r\n if (esRef.current) {\r\n esRef.current.close();\r\n }\r\n\r\n const es = new EventSource(\r\n `${API_BASE}/events/convert-progress/${encodeURIComponent(jobId)}`,\r\n );\r\n esRef.current = es;\r\n\r\n es.onopen = () => appendLog(\"🟢 SSE connection opened\");\r\n\r\n es.onerror = (event) => {\r\n appendLog(\"❌ SSE error:\", event);\r\n setStatus((prev) =>\r\n prev === CONVERSION_STATUS.FINISHED ? prev : CONVERSION_STATUS.FAILED,\r\n );\r\n };\r\n\r\n es.addEventListener(\"progress\", (event) => {\r\n try {\r\n const msgEvent = event as MessageEvent;\r\n const data = JSON.parse(msgEvent.data);\r\n\r\n appendLog(\r\n \"[progress]\",\r\n data.status ?? \"\",\r\n data.message ?? \"\",\r\n data.progress ?? \"\",\r\n );\r\n\r\n // If backend sends a status field matching our constants, use it\r\n if (\r\n data.status &&\r\n Object.values(CONVERSION_STATUS).includes(data.status)\r\n ) {\r\n setStatus(data.status as ConversionStatus);\r\n }\r\n\r\n if (typeof data.progress === \"number\") {\r\n setProgress(data.progress);\r\n }\r\n } catch (err) {\r\n appendLog(\"❌ Failed to parse progress event\", err);\r\n }\r\n });\r\n\r\n es.addEventListener(\"finished\", () => {\r\n appendLog(\"[finished] Conversion completed\");\r\n setStatus(CONVERSION_STATUS.FINISHED);\r\n setProgress(100);\r\n toast.success(\"Point cloud conversion completed\");\r\n es.close();\r\n esRef.current = null;\r\n });\r\n\r\n es.addEventListener(\"failed\", () => {\r\n appendLog(\"[failed] Conversion failed\");\r\n setStatus(CONVERSION_STATUS.FAILED);\r\n es.close();\r\n esRef.current = null;\r\n });\r\n\r\n es.addEventListener(\"connected\", (event) => {\r\n const msgEvent = event as MessageEvent;\r\n appendLog(\"[connected]\", msgEvent.data);\r\n });\r\n\r\n es.onmessage = (event) => {\r\n appendLog(\"[message]\", event.data);\r\n };\r\n }\r\n\r\n const handleSubmit = async (e: React.FormEvent) => {\r\n e.preventDefault();\r\n if (!name.trim() || !file) {\r\n alert(\"Please provide a name and select a LAZ/LAS file.\");\r\n return;\r\n }\r\n\r\n setLogLines([]);\r\n setProgress(0);\r\n setPointCloudId(null);\r\n setJobId(null);\r\n setStatus(\"idle\");\r\n setUploadSuccess(false);\r\n\r\n try {\r\n appendLog(\"🟦 1) Creating point cloud...\");\r\n setStatus(\"creating\");\r\n\r\n const { pointCloud, upload } = await createPointCloud(name.trim());\r\n appendLog(pointCloud);\r\n setPointCloudId(pointCloud.id);\r\n\r\n appendLog(\"🟦 2) Uploading to presigned URL...\");\r\n setStatus(\"uploading\");\r\n await uploadToPresignedUrl(upload.uploadUrl, file, (pct) =>\r\n setProgress(pct),\r\n );\r\n appendLog(\"✔ Upload finished\");\r\n setUploadSuccess(true);\r\n toast.success(\"LAZ file uploaded successfully\", { duration: 6000 });\r\n\r\n appendLog(\"🟦 3) Starting conversion...\");\r\n // Mark that the conversion has started (using backend status constant)\r\n setStatus(CONVERSION_STATUS.STARTED);\r\n const conversion = await startConversion(pointCloud.id);\r\n appendLog(conversion);\r\n\r\n const jobId = conversion.jobId;\r\n setJobId(jobId);\r\n\r\n appendLog(\"🟦 4) Subscribing to SSE…\");\r\n subscribeToProgress(jobId);\r\n } catch (err) {\r\n const message =\r\n err instanceof Error ? err.message : \"Unknown upload error\";\r\n appendLog(\"🔥 ERROR:\", message);\r\n setStatus(CONVERSION_STATUS.FAILED);\r\n alert(message);\r\n }\r\n };\r\n\r\n const busy =\r\n status !== \"idle\" &&\r\n status !== CONVERSION_STATUS.FINISHED &&\r\n status !== CONVERSION_STATUS.FAILED;\r\n\r\n const statusLabel: string = (() => {\r\n switch (status) {\r\n case \"idle\":\r\n return \"Idle\";\r\n case \"creating\":\r\n return \"Creating point cloud…\";\r\n case \"uploading\":\r\n return \"Uploading LAZ…\";\r\n\r\n case CONVERSION_STATUS.STARTED:\r\n return \"Conversion started…\";\r\n case CONVERSION_STATUS.DOWNLOAD:\r\n return \"Downloading source file…\";\r\n case CONVERSION_STATUS.CONVERT:\r\n return \"Running Potree converter…\";\r\n case CONVERSION_STATUS.UPLOAD:\r\n return \"Uploading Potree output…\";\r\n case CONVERSION_STATUS.CLEAN_UP:\r\n return \"Cleaning up temporary files…\";\r\n case CONVERSION_STATUS.FINISHED:\r\n return \"Done 🎉\";\r\n case CONVERSION_STATUS.FAILED:\r\n return \"Error – see log\";\r\n default:\r\n return \"Unknown status\";\r\n }\r\n })();\r\n\r\n return (\r\n <div className=\"p-2 mt-16\">\r\n <div className=\"flex items-center justify-between gap-2 mb-4\">\r\n <div>\r\n <h1 className=\"text-2xl font-semibold tracking-tight\">\r\n Upload & Convert Point Cloud\r\n </h1>\r\n </div>\r\n\r\n <Button\r\n variant=\"outline\"\r\n onClick={() => {\r\n if (onGoBackButtonClick) onGoBackButtonClick();\r\n }}\r\n >\r\n ← Back to list\r\n </Button>\r\n </div>\r\n\r\n <div className=\"grid gap-4 md:grid-cols-[2fr,1.2fr]\">\r\n {/* Upload card */}\r\n <div className=\"rounded-md border bg-background p-4 space-y-4\">\r\n <div className=\"flex items-center justify-between gap-2 text-sm\">\r\n <span className=\"font-semibold\">Upload point cloud</span>\r\n <span className=\"text-xs text-muted-foreground\">\r\n {statusLabel}\r\n </span>\r\n </div>\r\n\r\n <form onSubmit={handleSubmit} className=\"space-y-3 text-sm\">\r\n <div className=\"space-y-1\">\r\n <div className=\"text-xs font-medium\">Name</div>\r\n <Input\r\n placeholder=\"e.g. Campus north wing\"\r\n value={name}\r\n onChange={(e) => setName(e.target.value)}\r\n />\r\n </div>\r\n\r\n <div className=\"space-y-1\">\r\n <div className=\"text-xs font-medium\">LAZ / LAS file</div>\r\n <Input\r\n type=\"file\"\r\n accept=\".laz,.las\"\r\n onChange={(e) => {\r\n const f = e.target.files?.[0] ?? null;\r\n setFile(f);\r\n }}\r\n />\r\n {file && (\r\n <div className=\"text-[11px] text-muted-foreground\">\r\n Selected: <span className=\"font-medium\">{file.name}</span>\r\n </div>\r\n )}\r\n </div>\r\n\r\n <div className=\"flex items-center gap-3\">\r\n <Button\r\n type=\"submit\"\r\n disabled={!name.trim() || !file || busy}\r\n size=\"sm\"\r\n >\r\n {busy ? \"Working...\" : \"Upload & Convert\"}\r\n </Button>\r\n\r\n <div className=\"flex flex-col text-[11px] text-muted-foreground\">\r\n <span>\r\n PointCloud ID:{\" \"}\r\n <code className=\"text-xs\">{pointCloudId ?? \"—\"}</code>\r\n </span>\r\n <span>\r\n Job ID: <code className=\"text-xs\">{jobId ?? \"—\"}</code>\r\n </span>\r\n </div>\r\n </div>\r\n\r\n <div className=\"space-y-1\">\r\n <div className=\"flex items-center justify-between text-[11px] text-muted-foreground\">\r\n <span>Upload / conversion progress</span>\r\n <span>{progress}%</span>\r\n </div>\r\n <ProgressBar value={progress} />\r\n </div>\r\n\r\n {uploadSuccess && (\r\n <div className=\"rounded-md bg-green-50 border border-green-200 px-3 py-2 text-sm text-green-800 font-medium\">\r\n ✔ LAZ file uploaded successfully — conversion in progress\r\n </div>\r\n )}\r\n </form>\r\n </div>\r\n\r\n {/* Log card */}\r\n <div className=\"rounded-md border bg-muted/20 p-3 flex flex-col gap-2\">\r\n <div className=\"flex items-center justify-between text-xs\">\r\n <h2 className=\"font-semibold uppercase tracking-wide\">\r\n Conversion log\r\n </h2>\r\n <Button\r\n type=\"button\"\r\n variant=\"ghost\"\r\n size=\"sm\"\r\n className=\"h-6 px-2 text-[11px]\"\r\n onClick={() => setLogLines([])}\r\n >\r\n Clear\r\n </Button>\r\n </div>\r\n\r\n <ScrollArea className=\"h-[200px] rounded border bg-background\">\r\n <pre className=\"p-2 text-[11px] leading-snug whitespace-pre-wrap\">\r\n {logLines.length ? logLines.join(\"\\n\") : \"No activity yet.\"}\r\n </pre>\r\n </ScrollArea>\r\n </div>\r\n </div>\r\n </div>\r\n );\r\n}\r\n"],"mappings":"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","names":["name","file","pointCloudId","jobId","_a","_b"]}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
|
|
2
|
+
import type { Organization } from '../../../../../types/dbTypes';
|
|
3
|
+
export declare function PointCloudSidebar({ pointcloudApiUrl, organization }: {
|
|
4
|
+
pointcloudApiUrl?: 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/pointcloud/src/PointCloudSidebar/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudSidebar/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAS9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAEhE,wBAAgB,iBAAiB,CAAC,EAAE,gBAAgB,EAAE,YAAY,EAAE,EAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,YAAY,CAAA;CAAE,qBAwB/H"}
|
|
@@ -6,7 +6,7 @@ import { PointCloudContext, MenusContext } from "../../../../../store";
|
|
|
6
6
|
import { FileTab } from "./src/FileTab";
|
|
7
7
|
import { SettingsTab } from "./src/SettingsTab";
|
|
8
8
|
import { InfoSidebarContainer } from "../../../../../components/ui/InfoSidebar/Container";
|
|
9
|
-
function PointCloudSidebar() {
|
|
9
|
+
function PointCloudSidebar({ pointcloudApiUrl, organization }) {
|
|
10
10
|
const { state: pointCloudState } = React.useContext(PointCloudContext);
|
|
11
11
|
const { state: menusState, dispatch: menusDispatch } = React.useContext(MenusContext);
|
|
12
12
|
const { selectedTab } = menusState.menus;
|
|
@@ -16,6 +16,7 @@ function PointCloudSidebar() {
|
|
|
16
16
|
return /* @__PURE__ */ jsxs(
|
|
17
17
|
InfoSidebarContainer,
|
|
18
18
|
{
|
|
19
|
+
organization,
|
|
19
20
|
tabSelector: /* @__PURE__ */ jsx(
|
|
20
21
|
TabSelector,
|
|
21
22
|
{
|
|
@@ -24,7 +25,7 @@ function PointCloudSidebar() {
|
|
|
24
25
|
}
|
|
25
26
|
),
|
|
26
27
|
children: [
|
|
27
|
-
selectedTab === "file" && /* @__PURE__ */ jsx(FileTab, {}),
|
|
28
|
+
selectedTab === "file" && /* @__PURE__ */ jsx(FileTab, { pointcloudApiUrl }),
|
|
28
29
|
selectedTab === "settings" && /* @__PURE__ */ jsx(SettingsTab, {})
|
|
29
30
|
]
|
|
30
31
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudSidebar/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 { InfoSidebar } from '../../../../../components/ui/InfoSidebar'\r\nimport { TabSelector } from './TabSelector'\r\nimport { PointCloudContext, MenusContext } from '../../../../../store'\r\nimport { SidebarTabType } from '../../../../../store/Menus/reducer'\r\nimport { FileTab } from './src/FileTab'\r\n\r\nimport { SettingsTab } from './src/SettingsTab'\r\nimport { InfoSidebarContainer } from '../../../../../components/ui/InfoSidebar/Container'\r\n\r\nexport function PointCloudSidebar() {\r\n const { state: pointCloudState } = React.useContext(PointCloudContext)\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' && <PointCloudLayersTab />}*/}\r\n {selectedTab === 'settings' && <SettingsTab />} \r\n </InfoSidebarContainer>\r\n )\r\n}"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudSidebar/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 { InfoSidebar } from '../../../../../components/ui/InfoSidebar'\r\nimport { TabSelector } from './TabSelector'\r\nimport { PointCloudContext, MenusContext } from '../../../../../store'\r\nimport { SidebarTabType } from '../../../../../store/Menus/reducer'\r\nimport { FileTab } from './src/FileTab'\r\n\r\nimport { SettingsTab } from './src/SettingsTab'\r\nimport { InfoSidebarContainer } from '../../../../../components/ui/InfoSidebar/Container'\r\nimport type { Organization } from '../../../../../types/dbTypes'\r\n\r\nexport function PointCloudSidebar({ pointcloudApiUrl, organization }: { pointcloudApiUrl?: string; organization?: Organization }) {\r\n const { state: pointCloudState } = React.useContext(PointCloudContext)\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 pointcloudApiUrl={pointcloudApiUrl} />}\r\n {/* {selectedTab === 'layers' && <PointCloudLayersTab />}*/}\r\n {selectedTab === 'settings' && <SettingsTab />} \r\n </InfoSidebarContainer>\r\n )\r\n}"],"mappings":";AA0BI,SAGI,KAHJ;AArBJ,YAAY,WAAW;AAEvB,SAAS,mBAAmB;AAC5B,SAAS,mBAAmB,oBAAoB;AAEhD,SAAS,eAAe;AAExB,SAAS,mBAAmB;AAC5B,SAAS,4BAA4B;AAG9B,SAAS,kBAAkB,EAAE,kBAAkB,aAAa,GAA+D;AAChI,QAAM,EAAE,OAAO,gBAAgB,IAAI,MAAM,WAAW,iBAAiB;AACrE,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,kBAAoC;AAAA,QAEvE,gBAAgB,cAAc,oBAAC,eAAY;AAAA;AAAA;AAAA,EAC9C;AAEJ;","names":["selectedTab"]}
|
package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B,wBAAgB,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAQ9B,wBAAgB,OAAO,CAAC,EAAE,gBAAgB,EAAE,EAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAAE,qBAiC1E"}
|
|
@@ -6,7 +6,7 @@ import { PointCloudsSection } from "./src/PointCloudSection";
|
|
|
6
6
|
import { BuildingsContext } from "../../../../../../../store";
|
|
7
7
|
import { useSearchParams } from "next/navigation";
|
|
8
8
|
import { useFilesByBuildingId } from "../../../../../../../hooks/files/files";
|
|
9
|
-
function FileTab() {
|
|
9
|
+
function FileTab({ pointcloudApiUrl }) {
|
|
10
10
|
var _a;
|
|
11
11
|
const { state: buildingState } = React.useContext(BuildingsContext);
|
|
12
12
|
const { building } = buildingState.buildings;
|
|
@@ -25,7 +25,7 @@ function FileTab() {
|
|
|
25
25
|
}
|
|
26
26
|
});
|
|
27
27
|
return /* @__PURE__ */ jsxs("div", { className: "flex-1 flex flex-col space-y-6 h-full py-4 overflow-hidden", children: [
|
|
28
|
-
/* @__PURE__ */ jsx(PointCloudsSection, { files: pointCloudFiles }),
|
|
28
|
+
/* @__PURE__ */ jsx(PointCloudsSection, { files: pointCloudFiles, pointcloudApiUrl }),
|
|
29
29
|
/* @__PURE__ */ jsx(FilesSection, { files: nonPointCloudFiles })
|
|
30
30
|
] });
|
|
31
31
|
}
|
package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/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 { FilesSection } from './src/FilesSection'\r\nimport { PointCloudsSection } from './src/PointCloudSection'\r\nimport { BuildingsContext } from '../../../../../../../store'\r\nimport { useSearchParams } from 'next/navigation'\r\nimport { useFilesByBuildingId } from '../../../../../../../hooks/files/files'\r\nimport { DbFile } from '../../../../../../../types/dbTypes'\r\n\r\nexport function FileTab() {\r\n const { state: buildingState } = React.useContext(BuildingsContext)\r\n const { building } = buildingState.buildings\r\n\r\n const urlBuildingId = useSearchParams().get('buildingId')\r\n // Resolve from the store building, else the URL param; undefined if neither is\r\n // ready yet (e.g. mid viewer-switch) — the hook handles undefined → no files.\r\n const buildingId = building?.id ?? (urlBuildingId ? Number(urlBuildingId) : undefined)\r\n\r\n const filesData: DbFile[] = useFilesByBuildingId(buildingId).files || []\r\n\r\n const pointCloudFiles: DbFile[] = []\r\n const nonPointCloudFiles: DbFile[] = []\r\n\r\n // single .map pass to populate both arrays\r\n filesData.map((file) => {\r\n const {extension, type} = file\r\n // const isPointCloud = extension.toLowerCase() === 'laz' || extension.toLowerCase() === 'las'\r\n const isPointCloud = type?.toLowerCase() === 'point-cloud-file'\r\n\r\n if (isPointCloud) {\r\n pointCloudFiles.push(file)\r\n } else {\r\n nonPointCloudFiles.push(file)\r\n }\r\n })\r\n\r\n return (\r\n <div className=\"flex-1 flex flex-col space-y-6 h-full py-4 overflow-hidden\">\r\n <PointCloudsSection files={pointCloudFiles} />\r\n <FilesSection files={nonPointCloudFiles} />\r\n </div>\r\n )\r\n}\r\n"],"mappings":";AAyCI,SACE,KADF;AApCJ,YAAY,WAAW;AACvB,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,4BAA4B;AAG9B,SAAS,
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/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 { FilesSection } from './src/FilesSection'\r\nimport { PointCloudsSection } from './src/PointCloudSection'\r\nimport { BuildingsContext } from '../../../../../../../store'\r\nimport { useSearchParams } from 'next/navigation'\r\nimport { useFilesByBuildingId } from '../../../../../../../hooks/files/files'\r\nimport { DbFile } from '../../../../../../../types/dbTypes'\r\n\r\nexport function FileTab({ pointcloudApiUrl }: { pointcloudApiUrl?: string }) {\r\n const { state: buildingState } = React.useContext(BuildingsContext)\r\n const { building } = buildingState.buildings\r\n\r\n const urlBuildingId = useSearchParams().get('buildingId')\r\n // Resolve from the store building, else the URL param; undefined if neither is\r\n // ready yet (e.g. mid viewer-switch) — the hook handles undefined → no files.\r\n const buildingId = building?.id ?? (urlBuildingId ? Number(urlBuildingId) : undefined)\r\n\r\n const filesData: DbFile[] = useFilesByBuildingId(buildingId).files || []\r\n\r\n const pointCloudFiles: DbFile[] = []\r\n const nonPointCloudFiles: DbFile[] = []\r\n\r\n // single .map pass to populate both arrays\r\n filesData.map((file) => {\r\n const {extension, type} = file\r\n // const isPointCloud = extension.toLowerCase() === 'laz' || extension.toLowerCase() === 'las'\r\n const isPointCloud = type?.toLowerCase() === 'point-cloud-file'\r\n\r\n if (isPointCloud) {\r\n pointCloudFiles.push(file)\r\n } else {\r\n nonPointCloudFiles.push(file)\r\n }\r\n })\r\n\r\n return (\r\n <div className=\"flex-1 flex flex-col space-y-6 h-full py-4 overflow-hidden\">\r\n <PointCloudsSection files={pointCloudFiles} pointcloudApiUrl={pointcloudApiUrl} />\r\n <FilesSection files={nonPointCloudFiles} />\r\n </div>\r\n )\r\n}\r\n"],"mappings":";AAyCI,SACE,KADF;AApCJ,YAAY,WAAW;AACvB,SAAS,oBAAoB;AAC7B,SAAS,0BAA0B;AACnC,SAAS,wBAAwB;AACjC,SAAS,uBAAuB;AAChC,SAAS,4BAA4B;AAG9B,SAAS,QAAQ,EAAE,iBAAiB,GAAkC;AAb7E;AAcE,QAAM,EAAE,OAAO,cAAc,IAAI,MAAM,WAAW,gBAAgB;AAClE,QAAM,EAAE,SAAS,IAAI,cAAc;AAEnC,QAAM,gBAAgB,gBAAgB,EAAE,IAAI,YAAY;AAGxD,QAAM,cAAa,0CAAU,OAAV,YAAiB,gBAAgB,OAAO,aAAa,IAAI;AAE5E,QAAM,YAAsB,qBAAqB,UAAU,EAAE,SAAS,CAAC;AAEvE,QAAM,kBAA4B,CAAC;AACnC,QAAM,qBAA+B,CAAC;AAGtC,YAAU,IAAI,CAAC,SAAS;AACtB,UAAM,EAAC,WAAW,KAAI,IAAI;AAE1B,UAAM,gBAAe,6BAAM,mBAAkB;AAE7C,QAAI,cAAc;AAChB,sBAAgB,KAAK,IAAI;AAAA,IAC3B,OAAO;AACL,yBAAmB,KAAK,IAAI;AAAA,IAC9B;AAAA,EACF,CAAC;AAED,SACE,qBAAC,SAAI,WAAU,8DACb;AAAA,wBAAC,sBAAmB,OAAO,iBAAiB,kBAAoC;AAAA,IAChF,oBAAC,gBAAa,OAAO,oBAAoB;AAAA,KAC3C;AAEJ;","names":[]}
|
|
@@ -2,7 +2,8 @@ import * as React from 'react';
|
|
|
2
2
|
import { DbFile } from '../../../../../../../../types/dbTypes';
|
|
3
3
|
interface PointCloudsSectionProps {
|
|
4
4
|
files: DbFile[];
|
|
5
|
+
pointcloudApiUrl?: string;
|
|
5
6
|
}
|
|
6
|
-
export declare function PointCloudsSection({ files }: PointCloudsSectionProps): React.JSX.Element;
|
|
7
|
+
export declare function PointCloudsSection({ files, pointcloudApiUrl }: PointCloudsSectionProps): React.JSX.Element;
|
|
7
8
|
export {};
|
|
8
9
|
//# sourceMappingURL=PointCloudSection.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PointCloudSection.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"PointCloudSection.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAS9B,OAAO,EAAE,MAAM,EAAE,MAAM,uCAAuC,CAAA;AAoB9D,UAAU,uBAAuB;IAC/B,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,gBAAgB,EAAE,EAAE,uBAAuB,qBAqYtF"}
|