@collabdt/core 0.3.1 → 0.3.3
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/authentication/ForgotPassword.d.ts.map +1 -1
- package/dist/core/components/authentication/ForgotPassword.js +0 -1
- package/dist/core/components/authentication/ForgotPassword.js.map +1 -1
- package/dist/core/components/ui/Comments/CollapsibleCommentItem.d.ts +12 -2
- package/dist/core/components/ui/Comments/CollapsibleCommentItem.d.ts.map +1 -1
- package/dist/core/components/ui/Comments/CollapsibleCommentItem.js +137 -139
- package/dist/core/components/ui/Comments/CollapsibleCommentItem.js.map +1 -1
- package/dist/core/components/ui/Comments/Comment.d.ts +18 -1
- package/dist/core/components/ui/Comments/Comment.d.ts.map +1 -1
- package/dist/core/components/ui/Comments/Comment.js +94 -23
- package/dist/core/components/ui/Comments/Comment.js.map +1 -1
- package/dist/core/components/ui/Comments/CommentActionButtons.d.ts +38 -0
- package/dist/core/components/ui/Comments/CommentActionButtons.d.ts.map +1 -0
- package/dist/core/components/ui/Comments/CommentActionButtons.js +134 -0
- package/dist/core/components/ui/Comments/CommentActionButtons.js.map +1 -0
- package/dist/core/components/ui/Comments/CommentInput.d.ts.map +1 -1
- package/dist/core/components/ui/Comments/CommentInput.js +5 -2
- package/dist/core/components/ui/Comments/CommentInput.js.map +1 -1
- package/dist/core/components/ui/Comments/CommentsSection.d.ts.map +1 -1
- package/dist/core/components/ui/Comments/CommentsSection.js +86 -42
- package/dist/core/components/ui/Comments/CommentsSection.js.map +1 -1
- package/dist/core/components/ui/Comments/commentUtils.d.ts.map +1 -1
- package/dist/core/components/ui/Comments/commentUtils.js +2 -1
- package/dist/core/components/ui/Comments/commentUtils.js.map +1 -1
- package/dist/core/components/ui/FilesManager/src/useFileUploadWithProgress.d.ts.map +1 -1
- package/dist/core/components/ui/FilesManager/src/useFileUploadWithProgress.js +0 -1
- package/dist/core/components/ui/FilesManager/src/useFileUploadWithProgress.js.map +1 -1
- package/dist/core/components/ui/InfoSidebar/Container.d.ts.map +1 -1
- package/dist/core/components/ui/InfoSidebar/Container.js +16 -12
- package/dist/core/components/ui/InfoSidebar/Container.js.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts +1 -2
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js +66 -94
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js.map +1 -1
- package/dist/core/components/ui/Sensors/Sensor.d.ts +16 -3
- package/dist/core/components/ui/Sensors/Sensor.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/Sensor.js +76 -37
- package/dist/core/components/ui/Sensors/Sensor.js.map +1 -1
- package/dist/core/components/ui/Sensors/SensorChart.d.ts +12 -2
- package/dist/core/components/ui/Sensors/SensorChart.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/SensorChart.js +49 -12
- package/dist/core/components/ui/Sensors/SensorChart.js.map +1 -1
- package/dist/core/components/ui/Sensors/SensorDetailDialog.d.ts +9 -0
- package/dist/core/components/ui/Sensors/SensorDetailDialog.d.ts.map +1 -0
- package/dist/core/components/ui/Sensors/SensorDetailDialog.js +128 -0
- package/dist/core/components/ui/Sensors/SensorDetailDialog.js.map +1 -0
- package/dist/core/components/ui/Sensors/SensorInput.d.ts +6 -1
- package/dist/core/components/ui/Sensors/SensorInput.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/SensorInput.js +94 -9
- package/dist/core/components/ui/Sensors/SensorInput.js.map +1 -1
- package/dist/core/components/ui/Sensors/SensorTagsSection.d.ts +3 -1
- package/dist/core/components/ui/Sensors/SensorTagsSection.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/SensorTagsSection.js +4 -1
- package/dist/core/components/ui/Sensors/SensorTagsSection.js.map +1 -1
- package/dist/core/components/ui/Sensors/SensorsSection.d.ts +1 -3
- package/dist/core/components/ui/Sensors/SensorsSection.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/SensorsSection.js +33 -10
- package/dist/core/components/ui/Sensors/SensorsSection.js.map +1 -1
- package/dist/core/components/ui/Sensors/TimeZoneSelect.d.ts +7 -0
- package/dist/core/components/ui/Sensors/TimeZoneSelect.d.ts.map +1 -0
- package/dist/core/components/ui/Sensors/TimeZoneSelect.js +56 -0
- package/dist/core/components/ui/Sensors/TimeZoneSelect.js.map +1 -0
- package/dist/core/components/ui/Sensors/sensorData.d.ts +42 -0
- package/dist/core/components/ui/Sensors/sensorData.d.ts.map +1 -0
- package/dist/core/components/ui/Sensors/sensorData.js +118 -0
- package/dist/core/components/ui/Sensors/sensorData.js.map +1 -0
- package/dist/core/components/ui/Sensors/sensorRange.d.ts +24 -0
- package/dist/core/components/ui/Sensors/sensorRange.d.ts.map +1 -0
- package/dist/core/components/ui/Sensors/sensorRange.js +34 -0
- package/dist/core/components/ui/Sensors/sensorRange.js.map +1 -0
- package/dist/core/components/ui/Sensors/useSensorSeries.d.ts +15 -0
- package/dist/core/components/ui/Sensors/useSensorSeries.d.ts.map +1 -0
- package/dist/core/components/ui/Sensors/useSensorSeries.js +63 -0
- package/dist/core/components/ui/Sensors/useSensorSeries.js.map +1 -0
- package/dist/core/components/ui/Sidebar.d.ts.map +1 -1
- package/dist/core/components/ui/Sidebar.js +27 -4
- package/dist/core/components/ui/Sidebar.js.map +1 -1
- package/dist/core/components/ui/ToolbarButton.d.ts.map +1 -1
- package/dist/core/components/ui/ToolbarButton.js +0 -1
- package/dist/core/components/ui/ToolbarButton.js.map +1 -1
- package/dist/core/components/viewers/Data/advancedFilter/FiltersDialog.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/advancedFilter/FiltersDialog.js +0 -2
- package/dist/core/components/viewers/Data/advancedFilter/FiltersDialog.js.map +1 -1
- package/dist/core/components/viewers/Data/details/EnergySourcesGrid.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/details/EnergySourcesGrid.js +0 -10
- package/dist/core/components/viewers/Data/details/EnergySourcesGrid.js.map +1 -1
- package/dist/core/components/viewers/Data/files/DatatableFileAdder.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/files/DatatableFileAdder.js +0 -1
- package/dist/core/components/viewers/Data/files/DatatableFileAdder.js.map +1 -1
- package/dist/core/components/viewers/Data/files/utils/fuzzySearch.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/files/utils/fuzzySearch.js +0 -1
- package/dist/core/components/viewers/Data/files/utils/fuzzySearch.js.map +1 -1
- package/dist/core/components/viewers/Data/userDetails/UserMoreOptions.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/userDetails/UserMoreOptions.js +0 -1
- package/dist/core/components/viewers/Data/userDetails/UserMoreOptions.js.map +1 -1
- package/dist/core/components/viewers/Data/utils/filterHelper.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/utils/filterHelper.js +0 -2
- package/dist/core/components/viewers/Data/utils/filterHelper.js.map +1 -1
- package/dist/core/components/viewers/Viewer.js +1 -1
- package/dist/core/components/viewers/Viewer.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/CommunicationTab/src/TopicsSection.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/CommunicationTab/src/TopicsSection.js +0 -3
- package/dist/core/components/viewers/bim/src/BimSidebar/src/CommunicationTab/src/TopicsSection.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js +1 -7
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/FilesSection.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.js +1 -9
- package/dist/core/components/viewers/bim/src/BimSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.d.ts +1 -3
- 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/TabSelector.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/TabSelector.js +4 -3
- package/dist/core/components/viewers/bim/src/BimSidebar/src/TabSelector.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/index.js +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/ClippingPlane.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/ClippingPlane.js +0 -1
- package/dist/core/components/viewers/bim/src/ClippingPlane.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts +1 -2
- 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 +25 -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/BimComment.d.ts +16 -10
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimComment.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimComment.js +26 -6
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimComment.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimCommentCluster.d.ts +2 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimCommentCluster.d.ts.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimCommentCluster.js +5 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimCommentCluster.js.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.d.ts +8 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js +15 -3
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/BimSensor.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/clusterMarkersByScreenSpace.d.ts +44 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/clusterMarkersByScreenSpace.d.ts.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/clusterMarkersByScreenSpace.js +77 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/clusterMarkersByScreenSpace.js.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentCameraUtils.d.ts +3 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentCameraUtils.d.ts.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentCameraUtils.js +5 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentCameraUtils.js.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentMarkerConfig.d.ts +33 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentMarkerConfig.d.ts.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentMarkerConfig.js +90 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/commentMarkerConfig.js.map +1 -0
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/renderCSS2DMarkers.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/renderCSS2DMarkers.js +2 -2
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/renderCSS2DMarkers.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useCommentMarkers.d.ts +7 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useCommentMarkers.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useCommentMarkers.js +50 -73
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useCommentMarkers.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.d.ts +7 -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 +39 -11
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/ClippingTool/ClippingTool.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/ClippingTool/ClippingTool.js +1 -5
- package/dist/core/components/viewers/bim/src/tools/ClippingTool/ClippingTool.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/ExplodeByLevelTool.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/ExplodeByLevelTool.js +0 -1
- package/dist/core/components/viewers/bim/src/tools/ExplodeByLevelTool.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/measureBimTool.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/measureBimTool.js +1 -2
- package/dist/core/components/viewers/bim/src/tools/measureBimTool.js.map +1 -1
- package/dist/core/components/viewers/map/MapViewer.d.ts +1 -2
- 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/src/arcGISDatasets.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/arcGISDatasets.js +11 -14
- package/dist/core/components/viewers/map/datasets/src/arcGISDatasets.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/ckanDatasets.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/ckanDatasets.js +2 -5
- package/dist/core/components/viewers/map/datasets/src/ckanDatasets.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/localDatasets.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/localDatasets.js +0 -3
- package/dist/core/components/viewers/map/datasets/src/localDatasets.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/opendatasoftDatasets.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/src/opendatasoftDatasets.js +0 -11
- package/dist/core/components/viewers/map/datasets/src/opendatasoftDatasets.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.js +0 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/DatabaseBuildingPopover/src/BuildingsTools.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js +0 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/NonDatabaseBuildingPopover.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.js +0 -1
- package/dist/core/components/viewers/map/src/MapFeaturePopoverMenu/src/OpenDataFeaturePopover.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.d.ts +1 -2
- package/dist/core/components/viewers/map/src/MapLayers/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.js +2 -2
- package/dist/core/components/viewers/map/src/MapLayers/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/CommentLayer/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/CommentLayer/index.js +174 -53
- package/dist/core/components/viewers/map/src/MapLayers/src/CommentLayer/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/components/MapFileManager.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/components/MapFileManager.js +2 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/FileLayer/components/MapFileManager.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.d.ts +1 -3
- 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 +74 -42
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/TabSelector.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/TabSelector.js +4 -3
- package/dist/core/components/viewers/map/src/MapSidebar/TabSelector.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/index.js +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.js +0 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.js +1 -5
- package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.d.ts +1 -3
- 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/tools/AddTools/AddFile/utils/uploadToPresignedURLS.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/tools/AddTools/AddFile/utils/uploadToPresignedURLS.js +1 -3
- package/dist/core/components/viewers/map/src/tools/AddTools/AddFile/utils/uploadToPresignedURLS.js.map +1 -1
- package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.js +0 -1
- package/dist/core/components/viewers/map/utils/MapEventManager/MapClickManager.js.map +1 -1
- package/dist/core/components/viewers/map/utils/flyToEach.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/flyToEach.js +0 -1
- package/dist/core/components/viewers/map/utils/flyToEach.js.map +1 -1
- package/dist/core/components/viewers/map/utils/getOsmIdbyCoordinates.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/getOsmIdbyCoordinates.js +0 -2
- package/dist/core/components/viewers/map/utils/getOsmIdbyCoordinates.js.map +1 -1
- package/dist/core/components/viewers/shared/markers/BimMarkerCluster.d.ts +19 -0
- package/dist/core/components/viewers/shared/markers/BimMarkerCluster.d.ts.map +1 -0
- package/dist/core/components/viewers/shared/markers/BimMarkerCluster.js +108 -0
- package/dist/core/components/viewers/shared/markers/BimMarkerCluster.js.map +1 -0
- package/dist/core/components/viewers/shared/markers/computeMarkerLookAt.d.ts +24 -0
- package/dist/core/components/viewers/shared/markers/computeMarkerLookAt.d.ts.map +1 -0
- package/dist/core/components/viewers/shared/markers/computeMarkerLookAt.js +27 -0
- package/dist/core/components/viewers/shared/markers/computeMarkerLookAt.js.map +1 -0
- package/dist/core/components/viewers/shared/markers/types.d.ts +66 -0
- package/dist/core/components/viewers/shared/markers/types.d.ts.map +1 -0
- package/dist/core/components/viewers/shared/markers/types.js +1 -0
- package/dist/core/components/viewers/shared/markers/types.js.map +1 -0
- package/dist/core/components/viewers/shared/markers/useMarkerLayerBim.d.ts +22 -0
- package/dist/core/components/viewers/shared/markers/useMarkerLayerBim.d.ts.map +1 -0
- package/dist/core/components/viewers/shared/markers/useMarkerLayerBim.js +233 -0
- package/dist/core/components/viewers/shared/markers/useMarkerLayerBim.js.map +1 -0
- package/dist/core/hooks/comments/comments.d.ts +11 -0
- package/dist/core/hooks/comments/comments.d.ts.map +1 -1
- package/dist/core/hooks/comments/comments.js +3 -1
- package/dist/core/hooks/comments/comments.js.map +1 -1
- package/dist/core/hooks/comments/createCommentHooks.d.ts +11 -0
- package/dist/core/hooks/comments/createCommentHooks.d.ts.map +1 -1
- package/dist/core/hooks/comments/createCommentHooks.js +30 -1
- package/dist/core/hooks/comments/createCommentHooks.js.map +1 -1
- package/dist/core/hooks/files/files.d.ts.map +1 -1
- package/dist/core/hooks/files/files.js +0 -1
- package/dist/core/hooks/files/files.js.map +1 -1
- package/dist/core/hooks/ui/useResizableSidebarWidth.d.ts +30 -0
- package/dist/core/hooks/ui/useResizableSidebarWidth.d.ts.map +1 -0
- package/dist/core/hooks/ui/useResizableSidebarWidth.js +75 -0
- package/dist/core/hooks/ui/useResizableSidebarWidth.js.map +1 -0
- package/dist/core/i18n/messages/en.json +10 -1
- package/dist/core/i18n/messages/es.json +11 -2
- package/dist/core/i18n/messages/fr.json +11 -2
- package/dist/core/store/AppConfig/context.d.ts.map +1 -1
- package/dist/core/store/AppConfig/context.js +4 -1
- package/dist/core/store/AppConfig/context.js.map +1 -1
- package/dist/core/store/AppConfig/reducer.d.ts +10 -0
- package/dist/core/store/AppConfig/reducer.d.ts.map +1 -1
- package/dist/core/store/AppConfig/reducer.js +10 -0
- package/dist/core/store/AppConfig/reducer.js.map +1 -1
- package/dist/core/store/Datasets/reducer.d.ts.map +1 -1
- package/dist/core/store/Datasets/reducer.js +0 -2
- package/dist/core/store/Datasets/reducer.js.map +1 -1
- package/dist/core/store/Files/reducer.js +0 -1
- package/dist/core/store/Files/reducer.js.map +1 -1
- package/dist/core/store/Menus/context.d.ts.map +1 -1
- package/dist/core/store/Menus/context.js +8 -2
- package/dist/core/store/Menus/context.js.map +1 -1
- package/dist/core/store/Menus/reducer.d.ts +65 -1
- package/dist/core/store/Menus/reducer.d.ts.map +1 -1
- package/dist/core/store/Menus/reducer.js +39 -3
- package/dist/core/store/Menus/reducer.js.map +1 -1
- package/dist/core/utils/markerUtils.d.ts +10 -0
- package/dist/core/utils/markerUtils.d.ts.map +1 -1
- package/dist/core/utils/markerUtils.js +9 -1
- package/dist/core/utils/markerUtils.js.map +1 -1
- package/dist/core/utils/memcache.d.ts.map +1 -1
- package/dist/core/utils/memcache.js +0 -7
- package/dist/core/utils/memcache.js.map +1 -1
- package/dist/core/utils/timeUtils.d.ts +24 -1
- package/dist/core/utils/timeUtils.d.ts.map +1 -1
- package/dist/core/utils/timeUtils.js +52 -3
- package/dist/core/utils/timeUtils.js.map +1 -1
- package/package.json +4 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.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 LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from 'react'\r\nimport { mutate } from 'swr'\r\n\r\nimport { useDeleteFile } from '../../../../../../../../hooks/files/files'\r\nimport { BuildingsContext, FilesContext, MenusContext } from '../../../../../../../../store'\r\nimport ConfirmDialog from '../../../../../../../ConfirmDialog'\r\nimport { CollapsibleSection } from '../../../../../../../ui/CollapsibleSection'\r\nimport { useFileDeleteHandler, FileItemComponent, useFileActions, useFileUploadWithProgress } from '../../../../../../../ui/FilesManager'\r\nimport { LoadingSpinner } from '../../../../../../../ui/LoadingSpinner'\r\n\r\nimport type { DbFile as IFile } from '../../../../../../../../types/dbTypes'\r\n\r\n\r\n\r\n// Hoisted out of the JSX so the array reference is stable across renders.\r\n// Inline `options={['view','move','info','delete']}` gets a new array identity\r\n// on every render, defeating React.memo on FileItemComponent.\r\nconst FILE_OPTIONS: import('../../../../../../../../types/global').FileAction[] = ['view', 'move', 'info', 'delete']\r\n\r\nconst shouldExcludeByTag = (tag?: string | null): boolean => {\r\n if (!tag) return false\r\n return tag === 'user' || tag === 'bim-file' || tag === 'fragment-file' || tag === 'bimModel'\r\n}\r\n\r\nconst shouldExcludeByType = (type?: string | null): boolean => {\r\n if (!type) return false\r\n return type === 'bim-file'\r\n}\r\n\r\ninterface FilesSectionProps {\r\n files: IFile[]\r\n query?: string\r\n}\r\n\r\nexport function FilesSection({ files: _filesProp, query = '' }: FilesSectionProps) {\r\n const t = useTranslations('FileSelection')\r\n\r\n const { state: buildingsState } = React.useContext(BuildingsContext)\r\n const { state: fileState, dispatch: fileDispatch } = React.useContext(FilesContext)\r\n const files = fileState.files.files\r\n const { mapFileIds } = fileState.files\r\n const { building } = buildingsState.buildings\r\n const buildingId = building?.id || -1\r\n\r\n const { deleteFile: deleteFileApi } = useDeleteFile(buildingId)\r\n\r\n // Wrap so the store is updated immediately alongside the API call\r\n const deleteFile = React.useCallback(async (fileId: number) => {\r\n fileDispatch({ type: 'REMOVE_FILE', payload: { id: fileId } })\r\n await deleteFileApi(fileId)\r\n }, [deleteFileApi, fileDispatch])\r\n\r\n const { handleDeleteFile } = useFileDeleteHandler({\r\n deleteFile,\r\n onDeleteSuccess: () => {},\r\n })\r\n\r\n const { handleAddFile, uploadState } = useFileUploadWithProgress({\r\n acceptedFileTypes: '*',\r\n onUploadSuccess: () => {\r\n console.log('File uploaded successfully')\r\n mutate(`/api/files`)\r\n },\r\n onUploadError: (error) => console.error('Error uploading file:', error),\r\n })\r\n\r\n const nonBimFiles = React.useMemo(() => {\r\n return files\r\n .filter(file => file.extension !== 'ifc' && file.extension !== 'frag')\r\n .filter(file => !shouldExcludeByTag(file.tag))\r\n .filter(file => !shouldExcludeByType((file as any).type))\r\n .map(file => ({ ...file, isVisible: mapFileIds.includes(file.id) }))\r\n .sort((a, b) => {\r\n const aOnMap = mapFileIds.includes(a.id)\r\n const bOnMap = mapFileIds.includes(b.id)\r\n if (aOnMap !== bOnMap) return aOnMap ? -1 : 1\r\n return a.name.localeCompare(b.name)\r\n })\r\n }, [files, mapFileIds])\r\n\r\n const [localFiles, setLocalFiles] = React.useState(nonBimFiles)\r\n\r\n React.useEffect(() => {\r\n setLocalFiles(nonBimFiles)\r\n }, [nonBimFiles])\r\n\r\n const handleMoveFile = React.useCallback((file: IFile) => {\r\n fileDispatch({ type: 'EDIT_FILE', payload: { file } })\r\n }, [fileDispatch])\r\n\r\n // useCallback so the onView prop identity stays stable across renders.\r\n // Otherwise useFileActions' internal useCallback dep on onView re-fires every\r\n // render, producing a new handleAction identity, which defeats React.memo on\r\n // FileItemComponent.\r\n const handleViewFile = React.useCallback((file: IFile, newVisibility: boolean) => {\r\n fileDispatch({\r\n type: newVisibility ? 'ADD_TO_MAP' : 'REMOVE_FROM_MAP',\r\n payload: { id: file.id },\r\n })\r\n }, [fileDispatch])\r\n\r\n const { handleAction, deleteDialog } = useFileActions({\r\n files: localFiles,\r\n setFiles: setLocalFiles,\r\n buildingId,\r\n handleDeleteFile,\r\n onView: handleViewFile,\r\n onMove: handleMoveFile,\r\n })\r\n\r\n const areAllMapFilesHidden = React.useMemo(\r\n () => nonBimFiles.every(file => !mapFileIds.includes(file.id)),\r\n [nonBimFiles, mapFileIds]\r\n )\r\n\r\n const filteredFiles = React.useMemo(() => {\r\n if (!query.trim()) return nonBimFiles\r\n return nonBimFiles.filter(file =>\r\n file.name.toLowerCase().includes(query.toLowerCase())\r\n )\r\n }, [nonBimFiles, query])\r\n\r\n const handleSwitchVariant = () => ({\r\n checked: !areAllMapFilesHidden,\r\n onCheckedChange: (checked: boolean) => {\r\n if (checked) {\r\n fileDispatch({ type: 'ADD_ALL_TO_MAP', payload: { ids: nonBimFiles.map(f => f.id) } })\r\n }\r\n else {\r\n fileDispatch({ type: 'REMOVE_ALL_FROM_MAP' } as never)\r\n }\r\n },\r\n })\r\n\r\n return (\r\n <div className=\"h-full min-h-0\">\r\n <CollapsibleSection\r\n title={t('filesTitle')}\r\n icon={LR.FileText}\r\n className=\"h-full min-h-0 flex flex-col\"\r\n style={{ height: '100%', minHeight: 0 }}\r\n itemCount={filteredFiles.length}\r\n onAddItem={uploadState.uploading ? undefined : handleAddFile}\r\n addItemTitle={uploadState.uploading ? `${t('uploadingFile')} ${uploadState.progress}%` : t('addFileTitle')}\r\n switchVariant={handleSwitchVariant()}\r\n >\r\n <div className=\"flex-1 min-h-0 overflow-y-auto space-y-1\">\r\n {uploadState.uploading && (\r\n <div className=\"flex items-center gap-2 px-2 py-2 text-sm text-muted-foreground\">\r\n <LoadingSpinner className=\"h-4 w-4\" />\r\n <span>{t('uploadingFile')} {uploadState.progress}%</span>\r\n </div>\r\n )}\r\n {filteredFiles.map((item) => (\r\n <FileItemComponent\r\n key={item.id}\r\n file={item}\r\n onAction={handleAction}\r\n options={FILE_OPTIONS}\r\n translationKey=\"FileSelection\"\r\n confirmDelete={false}\r\n />\r\n ))}\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <ConfirmDialog\r\n isOpen={deleteDialog.isOpen}\r\n isDeleting={deleteDialog.isDeleting}\r\n onOpenChange={deleteDialog.onOpenChange}\r\n handleConfirm={deleteDialog.onConfirm}\r\n itemName={deleteDialog.itemName}\r\n />\r\n </div>\r\n )\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA4Jc,cACA,YADA;AAvJd,YAAY,QAAQ;AACpB,SAAS,uBAAuB;AAChC,YAAY,WAAW;AACvB,SAAS,cAAc;AAEvB,SAAS,qBAAqB;AAC9B,SAAS,kBAAkB,oBAAkC;AAC7D,OAAO,mBAAmB;AAC1B,SAAS,0BAA0B;AACnC,SAAS,sBAAsB,mBAAmB,gBAAgB,iCAAiC;AACnG,SAAS,sBAAsB;AAS/B,MAAM,eAA4E,CAAC,QAAQ,QAAQ,QAAQ,QAAQ;AAEnH,MAAM,qBAAqB,CAAC,QAAiC;AAC3D,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,QAAQ,UAAU,QAAQ,cAAc,QAAQ,mBAAmB,QAAQ;AACpF;AAEA,MAAM,sBAAsB,CAAC,SAAkC;AAC7D,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,SAAS;AAClB;AAOO,SAAS,aAAa,EAAE,OAAO,YAAY,QAAQ,GAAG,GAAsB;AACjF,QAAM,IAAI,gBAAgB,eAAe;AAEzC,QAAM,EAAE,OAAO,eAAe,IAAI,MAAM,WAAW,gBAAgB;AACnE,QAAM,EAAE,OAAO,WAAW,UAAU,aAAa,IAAI,MAAM,WAAW,YAAY;AAClF,QAAM,QAAQ,UAAU,MAAM;AAC9B,QAAM,EAAE,WAAW,IAAI,UAAU;AACjC,QAAM,EAAE,SAAS,IAAI,eAAe;AACpC,QAAM,cAAa,qCAAU,OAAM;AAEnC,QAAM,EAAE,YAAY,cAAc,IAAI,cAAc,UAAU;AAG9D,QAAM,aAAa,MAAM,YAAY,OAAO,WAAmB;AAC7D,iBAAa,EAAE,MAAM,eAAe,SAAS,EAAE,IAAI,OAAO,EAAE,CAAC;AAC7D,UAAM,cAAc,MAAM;AAAA,EAC5B,GAAG,CAAC,eAAe,YAAY,CAAC;AAEhC,QAAM,EAAE,iBAAiB,IAAI,qBAAqB;AAAA,IAChD;AAAA,IACA,iBAAiB,MAAM;AAAA,IAAC;AAAA,EAC1B,CAAC;AAED,QAAM,EAAE,eAAe,YAAY,IAAI,0BAA0B;AAAA,IAC/D,mBAAmB;AAAA,IACnB,iBAAiB,MAAM;AACrB,cAAQ,IAAI,4BAA4B;AACxC,aAAO,YAAY;AAAA,IACrB;AAAA,IACA,eAAe,CAAC,UAAU,QAAQ,MAAM,yBAAyB,KAAK;AAAA,EACxE,CAAC;AAED,QAAM,cAAc,MAAM,QAAQ,MAAM;AACtC,WAAO,MACJ,OAAO,UAAQ,KAAK,cAAc,SAAS,KAAK,cAAc,MAAM,EACpE,OAAO,UAAQ,CAAC,mBAAmB,KAAK,GAAG,CAAC,EAC5C,OAAO,UAAQ,CAAC,oBAAqB,KAAa,IAAI,CAAC,EACvD,IAAI,UAAS,iCAAK,OAAL,EAAW,WAAW,WAAW,SAAS,KAAK,EAAE,EAAE,EAAE,EAClE,KAAK,CAAC,GAAG,MAAM;AACd,YAAM,SAAS,WAAW,SAAS,EAAE,EAAE;AACvC,YAAM,SAAS,WAAW,SAAS,EAAE,EAAE;AACvC,UAAI,WAAW,OAAQ,QAAO,SAAS,KAAK;AAC5C,aAAO,EAAE,KAAK,cAAc,EAAE,IAAI;AAAA,IACpC,CAAC;AAAA,EACL,GAAG,CAAC,OAAO,UAAU,CAAC;AAEtB,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAAS,WAAW;AAE9D,QAAM,UAAU,MAAM;AACpB,kBAAc,WAAW;AAAA,EAC3B,GAAG,CAAC,WAAW,CAAC;AAEhB,QAAM,iBAAiB,MAAM,YAAY,CAAC,SAAgB;AACxD,iBAAa,EAAE,MAAM,aAAa,SAAS,EAAE,KAAK,EAAE,CAAC;AAAA,EACvD,GAAG,CAAC,YAAY,CAAC;AAMjB,QAAM,iBAAiB,MAAM,YAAY,CAAC,MAAa,kBAA2B;AAChF,iBAAa;AAAA,MACX,MAAM,gBAAgB,eAAe;AAAA,MACrC,SAAS,EAAE,IAAI,KAAK,GAAG;AAAA,IACzB,CAAC;AAAA,EACH,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,EAAE,cAAc,aAAa,IAAI,eAAe;AAAA,IACpD,OAAO;AAAA,IACP,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,uBAAuB,MAAM;AAAA,IACjC,MAAM,YAAY,MAAM,UAAQ,CAAC,WAAW,SAAS,KAAK,EAAE,CAAC;AAAA,IAC7D,CAAC,aAAa,UAAU;AAAA,EAC1B;AAEA,QAAM,gBAAgB,MAAM,QAAQ,MAAM;AACxC,QAAI,CAAC,MAAM,KAAK,EAAG,QAAO;AAC1B,WAAO,YAAY;AAAA,MAAO,UACxB,KAAK,KAAK,YAAY,EAAE,SAAS,MAAM,YAAY,CAAC;AAAA,IACtD;AAAA,EACF,GAAG,CAAC,aAAa,KAAK,CAAC;AAEvB,QAAM,sBAAsB,OAAO;AAAA,IACjC,SAAS,CAAC;AAAA,IACV,iBAAiB,CAAC,YAAqB;AACrC,UAAI,SAAS;AACX,qBAAa,EAAE,MAAM,kBAAkB,SAAS,EAAE,KAAK,YAAY,IAAI,OAAK,EAAE,EAAE,EAAE,EAAE,CAAC;AAAA,MACvF,OACK;AACH,qBAAa,EAAE,MAAM,sBAAsB,CAAU;AAAA,MACvD;AAAA,IACF;AAAA,EACF;AAEA,SACE,qBAAC,SAAI,WAAU,kBACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,YAAY;AAAA,QACrB,MAAM,GAAG;AAAA,QACT,WAAU;AAAA,QACV,OAAO,EAAE,QAAQ,QAAQ,WAAW,EAAE;AAAA,QACtC,WAAW,cAAc;AAAA,QACzB,WAAW,YAAY,YAAY,SAAY;AAAA,QAC/C,cAAc,YAAY,YAAY,GAAG,EAAE,eAAe,CAAC,IAAI,YAAY,QAAQ,MAAM,EAAE,cAAc;AAAA,QACzG,eAAe,oBAAoB;AAAA,QAEnC,+BAAC,SAAI,WAAU,4CACZ;AAAA,sBAAY,aACX,qBAAC,SAAI,WAAU,mEACb;AAAA,gCAAC,kBAAe,WAAU,WAAU;AAAA,YACpC,qBAAC,UAAM;AAAA,gBAAE,eAAe;AAAA,cAAE;AAAA,cAAE,YAAY;AAAA,cAAS;AAAA,eAAC;AAAA,aACpD;AAAA,UAED,cAAc,IAAI,CAAC,SAClB;AAAA,YAAC;AAAA;AAAA,cAEC,MAAM;AAAA,cACN,UAAU;AAAA,cACV,SAAS;AAAA,cACT,gBAAe;AAAA,cACf,eAAe;AAAA;AAAA,YALV,KAAK;AAAA,UAMZ,CACD;AAAA,WACH;AAAA;AAAA,IACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ,aAAa;AAAA,QACrB,YAAY,aAAa;AAAA,QACzB,cAAc,aAAa;AAAA,QAC3B,eAAe,aAAa;AAAA,QAC5B,UAAU,aAAa;AAAA;AAAA,IACzB;AAAA,KACF;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/FilesSection.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 LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from 'react'\r\nimport { mutate } from 'swr'\r\n\r\nimport { useDeleteFile } from '../../../../../../../../hooks/files/files'\r\nimport { BuildingsContext, FilesContext, MenusContext } from '../../../../../../../../store'\r\nimport ConfirmDialog from '../../../../../../../ConfirmDialog'\r\nimport { CollapsibleSection } from '../../../../../../../ui/CollapsibleSection'\r\nimport { useFileDeleteHandler, FileItemComponent, useFileActions, useFileUploadWithProgress } from '../../../../../../../ui/FilesManager'\r\nimport { LoadingSpinner } from '../../../../../../../ui/LoadingSpinner'\r\n\r\nimport type { DbFile as IFile } from '../../../../../../../../types/dbTypes'\r\n\r\n\r\n\r\n// Hoisted out of the JSX so the array reference is stable across renders.\r\n// Inline `options={['view','move','info','delete']}` gets a new array identity\r\n// on every render, defeating React.memo on FileItemComponent.\r\nconst FILE_OPTIONS: import('../../../../../../../../types/global').FileAction[] = ['view', 'move', 'info', 'delete']\r\n\r\nconst shouldExcludeByTag = (tag?: string | null): boolean => {\r\n if (!tag) return false\r\n return tag === 'user' || tag === 'bim-file' || tag === 'fragment-file' || tag === 'bimModel'\r\n}\r\n\r\nconst shouldExcludeByType = (type?: string | null): boolean => {\r\n if (!type) return false\r\n return type === 'bim-file'\r\n}\r\n\r\ninterface FilesSectionProps {\r\n files: IFile[]\r\n query?: string\r\n}\r\n\r\nexport function FilesSection({ files: _filesProp, query = '' }: FilesSectionProps) {\r\n const t = useTranslations('FileSelection')\r\n\r\n const { state: buildingsState } = React.useContext(BuildingsContext)\r\n const { state: fileState, dispatch: fileDispatch } = React.useContext(FilesContext)\r\n const files = fileState.files.files\r\n const { mapFileIds } = fileState.files\r\n const { building } = buildingsState.buildings\r\n const buildingId = building?.id || -1\r\n\r\n const { deleteFile: deleteFileApi } = useDeleteFile(buildingId)\r\n\r\n // Wrap so the store is updated immediately alongside the API call\r\n const deleteFile = React.useCallback(async (fileId: number) => {\r\n fileDispatch({ type: 'REMOVE_FILE', payload: { id: fileId } })\r\n await deleteFileApi(fileId)\r\n }, [deleteFileApi, fileDispatch])\r\n\r\n const { handleDeleteFile } = useFileDeleteHandler({\r\n deleteFile,\r\n onDeleteSuccess: () => {},\r\n })\r\n\r\n const { handleAddFile, uploadState } = useFileUploadWithProgress({\r\n acceptedFileTypes: '*',\r\n onUploadSuccess: () => {\r\n mutate(`/api/files`)\r\n },\r\n onUploadError: (error) => console.error('Error uploading file:', error),\r\n })\r\n\r\n const nonBimFiles = React.useMemo(() => {\r\n return files\r\n .filter(file => file.extension !== 'ifc' && file.extension !== 'frag')\r\n .filter(file => !shouldExcludeByTag(file.tag))\r\n .filter(file => !shouldExcludeByType((file as any).type))\r\n .map(file => ({ ...file, isVisible: mapFileIds.includes(file.id) }))\r\n .sort((a, b) => {\r\n const aOnMap = mapFileIds.includes(a.id)\r\n const bOnMap = mapFileIds.includes(b.id)\r\n if (aOnMap !== bOnMap) return aOnMap ? -1 : 1\r\n return a.name.localeCompare(b.name)\r\n })\r\n }, [files, mapFileIds])\r\n\r\n const [localFiles, setLocalFiles] = React.useState(nonBimFiles)\r\n\r\n React.useEffect(() => {\r\n setLocalFiles(nonBimFiles)\r\n }, [nonBimFiles])\r\n\r\n const handleMoveFile = React.useCallback((file: IFile) => {\r\n fileDispatch({ type: 'EDIT_FILE', payload: { file } })\r\n }, [fileDispatch])\r\n\r\n // useCallback so the onView prop identity stays stable across renders.\r\n // Otherwise useFileActions' internal useCallback dep on onView re-fires every\r\n // render, producing a new handleAction identity, which defeats React.memo on\r\n // FileItemComponent.\r\n const handleViewFile = React.useCallback((file: IFile, newVisibility: boolean) => {\r\n fileDispatch({\r\n type: newVisibility ? 'ADD_TO_MAP' : 'REMOVE_FROM_MAP',\r\n payload: { id: file.id },\r\n })\r\n }, [fileDispatch])\r\n\r\n const { handleAction, deleteDialog } = useFileActions({\r\n files: localFiles,\r\n setFiles: setLocalFiles,\r\n buildingId,\r\n handleDeleteFile,\r\n onView: handleViewFile,\r\n onMove: handleMoveFile,\r\n })\r\n\r\n const areAllMapFilesHidden = React.useMemo(\r\n () => nonBimFiles.every(file => !mapFileIds.includes(file.id)),\r\n [nonBimFiles, mapFileIds]\r\n )\r\n\r\n const filteredFiles = React.useMemo(() => {\r\n if (!query.trim()) return nonBimFiles\r\n return nonBimFiles.filter(file =>\r\n file.name.toLowerCase().includes(query.toLowerCase())\r\n )\r\n }, [nonBimFiles, query])\r\n\r\n const handleSwitchVariant = () => ({\r\n checked: !areAllMapFilesHidden,\r\n onCheckedChange: (checked: boolean) => {\r\n if (checked) {\r\n fileDispatch({ type: 'ADD_ALL_TO_MAP', payload: { ids: nonBimFiles.map(f => f.id) } })\r\n }\r\n else {\r\n fileDispatch({ type: 'REMOVE_ALL_FROM_MAP' } as never)\r\n }\r\n },\r\n })\r\n\r\n return (\r\n <div className=\"h-full min-h-0\">\r\n <CollapsibleSection\r\n title={t('filesTitle')}\r\n icon={LR.FileText}\r\n className=\"h-full min-h-0 flex flex-col\"\r\n style={{ height: '100%', minHeight: 0 }}\r\n itemCount={filteredFiles.length}\r\n onAddItem={uploadState.uploading ? undefined : handleAddFile}\r\n addItemTitle={uploadState.uploading ? `${t('uploadingFile')} ${uploadState.progress}%` : t('addFileTitle')}\r\n switchVariant={handleSwitchVariant()}\r\n >\r\n <div className=\"flex-1 min-h-0 overflow-y-auto space-y-1\">\r\n {uploadState.uploading && (\r\n <div className=\"flex items-center gap-2 px-2 py-2 text-sm text-muted-foreground\">\r\n <LoadingSpinner className=\"h-4 w-4\" />\r\n <span>{t('uploadingFile')} {uploadState.progress}%</span>\r\n </div>\r\n )}\r\n {filteredFiles.map((item) => (\r\n <FileItemComponent\r\n key={item.id}\r\n file={item}\r\n onAction={handleAction}\r\n options={FILE_OPTIONS}\r\n translationKey=\"FileSelection\"\r\n confirmDelete={false}\r\n />\r\n ))}\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <ConfirmDialog\r\n isOpen={deleteDialog.isOpen}\r\n isDeleting={deleteDialog.isDeleting}\r\n onOpenChange={deleteDialog.onOpenChange}\r\n handleConfirm={deleteDialog.onConfirm}\r\n itemName={deleteDialog.itemName}\r\n />\r\n </div>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ModelsSection.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAW9B,OAAO,KAAK,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,uCAAuC,CAAA;AAO7E,UAAU,kBAAkB;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,KAAU,EAAE,EAAE,kBAAkB,
|
|
1
|
+
{"version":3,"file":"ModelsSection.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAW9B,OAAO,KAAK,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,uCAAuC,CAAA;AAO7E,UAAU,kBAAkB;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,KAAU,EAAE,EAAE,kBAAkB,qBAgLtE"}
|
|
@@ -40,15 +40,11 @@ function ModelsSection({ files, query = "" }) {
|
|
|
40
40
|
const { buildings, building: currentBuilding } = buildingsState.buildings;
|
|
41
41
|
const { deleteFile } = useDeleteFile();
|
|
42
42
|
const { handleDeleteFile } = useFileDeleteHandler({
|
|
43
|
-
deleteFile
|
|
44
|
-
onDeleteSuccess: () => {
|
|
45
|
-
console.log("Model file deleted successfully");
|
|
46
|
-
}
|
|
43
|
+
deleteFile
|
|
47
44
|
});
|
|
48
45
|
const { handleAddFile, uploadState } = useFileUploadWithProgress({
|
|
49
46
|
acceptedFileTypes: ".ifc,.frag",
|
|
50
47
|
onUploadSuccess: () => {
|
|
51
|
-
console.log("Model uploaded successfully");
|
|
52
48
|
mutate(`/api/files`);
|
|
53
49
|
},
|
|
54
50
|
onUploadError: (error) => {
|
package/dist/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.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 LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from 'react'\r\nimport { mutate } from 'swr'\r\n\r\nimport { useDeleteFile } from '../../../../../../../../hooks/files/files'\r\nimport { BimContext, BuildingsContext } from '../../../../../../../../store'\r\nimport ConfirmDialog from '../../../../../../../ConfirmDialog'\r\nimport { CollapsibleSection } from '../../../../../../../ui/CollapsibleSection'\r\nimport { useFileDeleteHandler, FileItemComponent, useFileActions, useFileUploadWithProgress } from '../../../../../../../ui/FilesManager'\r\nimport { LoadingSpinner } from '../../../../../../../ui/LoadingSpinner'\r\nimport { toggleBimToMap as dispatchToggleBimToMap } from '../../../../../utils/toggleBimToMap'\r\n\r\nimport type { DbFile as DbFile } from '../../../../../../../../types/dbTypes'\r\n\r\n\r\ntype FileAction = import('../../../../../../../../types/global').FileAction\r\nconst OPTIONS_ON_MAP: FileAction[] = ['download', 'view', 'move', 'info', 'delete']\r\nconst OPTIONS_OFF_MAP: FileAction[] = ['download', 'view', 'info', 'delete']\r\n\r\ninterface ModelsSectionProps {\r\n files: DbFile[]\r\n query?: string\r\n}\r\n\r\nexport function ModelsSection({ files, query = '' }: ModelsSectionProps) {\r\n // Translation\r\n const t = useTranslations('FileItemComponent')\r\n\r\n // Get Map context for models added to map\r\n const { state: bimState, dispatch: bimDispatch } = React.useContext(BimContext)\r\n const { bimModelsAddedToMap } = bimState.bim\r\n\r\n const { state: buildingsState } = React.useContext(BuildingsContext)\r\n const { buildings, building: currentBuilding } = buildingsState.buildings\r\n\r\n const { deleteFile } = useDeleteFile()\r\n\r\n // Use the reusable delete handler\r\n const { handleDeleteFile } = useFileDeleteHandler({\r\n deleteFile,\r\n onDeleteSuccess: () => {\r\n console.log('Model file deleted successfully')\r\n },\r\n })\r\n\r\n // Use the new upload hook with progress\r\n const { handleAddFile, uploadState } = useFileUploadWithProgress({\r\n acceptedFileTypes: '.ifc,.frag',\r\n onUploadSuccess: () => {\r\n console.log('Model uploaded successfully')\r\n mutate(`/api/files`)\r\n },\r\n onUploadError: (error) => {\r\n console.error('Error uploading model:', error)\r\n }\r\n })\r\n\r\n // Filter and sort models: BIM files only, with models added to map at the top\r\n const sortedModels = React.useMemo(() => {\r\n const bimFiles = files.filter(file => file.extension === 'frag')\r\n\r\n return bimFiles\r\n .map(file => {\r\n const isAddedToMap = bimModelsAddedToMap.some(model => model.bimFile.id === file.id)\r\n return { ...file, isAddedToMap, isVisible: isAddedToMap }\r\n })\r\n .sort((a, b) => {\r\n // Models added to map come first\r\n if (a.isAddedToMap && !b.isAddedToMap) return -1\r\n if (!a.isAddedToMap && b.isAddedToMap) return 1\r\n return 0\r\n })\r\n }, [files, bimModelsAddedToMap])\r\n\r\n // Local state for file management\r\n const [loadedModels, setLoadedModels] = React.useState(sortedModels)\r\n\r\n // Keep local list in sync with sorted models\r\n React.useEffect(() => {\r\n setLoadedModels(sortedModels)\r\n }, [sortedModels])\r\n\r\n const handleToggleModelOnMap = React.useCallback((file: DbFile, isVisible: boolean) => {\r\n if (isVisible) {\r\n // Add model to map — reuse the same payload shape as the building popover\r\n const building = buildings.find(b => b.id === file.attachedFilesBuildingId) ?? currentBuilding ?? null\r\n dispatchToggleBimToMap(bimDispatch, file, building)\r\n } else {\r\n // Remove model from map\r\n bimDispatch({\r\n type: 'REMOVE_BIM_FROM_MAP',\r\n payload: { bimModelName: file.name },\r\n })\r\n }\r\n }, [bimDispatch, buildings])\r\n\r\n const handleMoveModel = React.useCallback((file: DbFile) => {\r\n const isOnMap = bimModelsAddedToMap.some(m => m.bimFile.id === file.id)\r\n if (!isOnMap) return\r\n bimDispatch({\r\n type: 'EDIT_BIM_MODEL_BY_NAME',\r\n payload: { editingBimModel: file.name },\r\n })\r\n }, [bimDispatch, bimModelsAddedToMap])\r\n\r\n const resolveBuildingForFile = React.useCallback(async (file: DbFile) => {\r\n const attachedBuildingId = file.attachedFilesBuildingId\r\n\r\n if (attachedBuildingId == null) {\r\n return currentBuilding ?? null\r\n }\r\n\r\n const cachedBuilding = buildings.find(building => building.id === attachedBuildingId) ?? null\r\n if (cachedBuilding?.buildingOsmId != null) {\r\n return cachedBuilding\r\n }\r\n\r\n try {\r\n const response = await fetch(`/api/buildings/${attachedBuildingId}`)\r\n if (!response.ok) {\r\n return cachedBuilding ?? currentBuilding ?? null\r\n }\r\n\r\n const data = await response.json() as { building?: typeof cachedBuilding }\r\n return data.building ?? cachedBuilding ?? currentBuilding ?? null\r\n }\r\n catch {\r\n return cachedBuilding ?? currentBuilding ?? null\r\n }\r\n }, [buildings, currentBuilding])\r\n\r\n const handleToggleModelOnMapAsync = React.useCallback(async (file: DbFile, isVisible: boolean) => {\r\n if (!isVisible) {\r\n bimDispatch({\r\n type: 'REMOVE_BIM_FROM_MAP',\r\n payload: { bimModelName: file.name },\r\n })\r\n return\r\n }\r\n\r\n const building = await resolveBuildingForFile(file)\r\n dispatchToggleBimToMap(bimDispatch, file, building)\r\n }, [bimDispatch, resolveBuildingForFile])\r\n\r\n // Use the common file actions hook\r\n const { handleAction, deleteDialog } = useFileActions({\r\n files: loadedModels,\r\n setFiles: setLoadedModels,\r\n buildingId: null,\r\n handleDeleteFile,\r\n onView: handleToggleModelOnMapAsync,\r\n onMove: handleMoveModel,\r\n })\r\n\r\n // Filter models based on search query — use sortedModels directly so the\r\n // sidebar always reflects the current BimContext state without waiting for\r\n // the loadedModels sync effect (which lags one render behind).\r\n const filteredModels = React.useMemo(() => {\r\n if (!query.trim()) return sortedModels\r\n return sortedModels.filter(file =>\r\n file.name.toLowerCase().includes(query.toLowerCase())\r\n )\r\n }, [sortedModels, query])\r\n\r\n return (\r\n <div className=\"h-full min-h-0\">\r\n <CollapsibleSection\r\n title={t('modelsTitles')}\r\n icon={LR.Box}\r\n className=\"h-full min-h-0 flex flex-col\"\r\n style={{ height: '100%', minHeight: 0 }}\r\n itemCount={filteredModels.length}\r\n onAddItem={uploadState.uploading ? undefined : handleAddFile}\r\n addItemTitle={uploadState.uploading ? `${t('uploadingFile')} ${uploadState.progress}%` : t('addBimTitle')}\r\n >\r\n <div className=\"flex-1 min-h-0 overflow-y-scroll space-y-1\">\r\n {uploadState.uploading && (\r\n <div className=\"flex items-center gap-2 px-2 py-2 text-sm text-muted-foreground\">\r\n <LoadingSpinner className=\"h-4 w-4\" />\r\n <span>{t('uploadingFile')} {uploadState.progress}%</span>\r\n </div>\r\n )}\r\n {filteredModels.map((file) => (\r\n <div key={file.id}>\r\n <FileItemComponent\r\n file={file}\r\n onAction={handleAction}\r\n options={file.isAddedToMap ? OPTIONS_ON_MAP : OPTIONS_OFF_MAP}\r\n confirmDelete={false}\r\n />\r\n </div>\r\n ))}\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <ConfirmDialog\r\n isOpen={deleteDialog.isOpen}\r\n isDeleting={deleteDialog.isDeleting}\r\n onOpenChange={deleteDialog.onOpenChange}\r\n handleConfirm={deleteDialog.onConfirm}\r\n itemName={deleteDialog.itemName}\r\n />\r\n </div>\r\n )\r\n}\r\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/FileTab/src/ModelsSection.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 LR from 'lucide-react'\r\nimport { useTranslations } from 'next-intl'\r\nimport * as React from 'react'\r\nimport { mutate } from 'swr'\r\n\r\nimport { useDeleteFile } from '../../../../../../../../hooks/files/files'\r\nimport { BimContext, BuildingsContext } from '../../../../../../../../store'\r\nimport ConfirmDialog from '../../../../../../../ConfirmDialog'\r\nimport { CollapsibleSection } from '../../../../../../../ui/CollapsibleSection'\r\nimport { useFileDeleteHandler, FileItemComponent, useFileActions, useFileUploadWithProgress } from '../../../../../../../ui/FilesManager'\r\nimport { LoadingSpinner } from '../../../../../../../ui/LoadingSpinner'\r\nimport { toggleBimToMap as dispatchToggleBimToMap } from '../../../../../utils/toggleBimToMap'\r\n\r\nimport type { DbFile as DbFile } from '../../../../../../../../types/dbTypes'\r\n\r\n\r\ntype FileAction = import('../../../../../../../../types/global').FileAction\r\nconst OPTIONS_ON_MAP: FileAction[] = ['download', 'view', 'move', 'info', 'delete']\r\nconst OPTIONS_OFF_MAP: FileAction[] = ['download', 'view', 'info', 'delete']\r\n\r\ninterface ModelsSectionProps {\r\n files: DbFile[]\r\n query?: string\r\n}\r\n\r\nexport function ModelsSection({ files, query = '' }: ModelsSectionProps) {\r\n // Translation\r\n const t = useTranslations('FileItemComponent')\r\n\r\n // Get Map context for models added to map\r\n const { state: bimState, dispatch: bimDispatch } = React.useContext(BimContext)\r\n const { bimModelsAddedToMap } = bimState.bim\r\n\r\n const { state: buildingsState } = React.useContext(BuildingsContext)\r\n const { buildings, building: currentBuilding } = buildingsState.buildings\r\n\r\n const { deleteFile } = useDeleteFile()\r\n\r\n // Use the reusable delete handler\r\n const { handleDeleteFile } = useFileDeleteHandler({\r\n deleteFile,\r\n })\r\n\r\n // Use the new upload hook with progress\r\n const { handleAddFile, uploadState } = useFileUploadWithProgress({\r\n acceptedFileTypes: '.ifc,.frag',\r\n onUploadSuccess: () => {\r\n mutate(`/api/files`)\r\n },\r\n onUploadError: (error) => {\r\n console.error('Error uploading model:', error)\r\n }\r\n })\r\n\r\n // Filter and sort models: BIM files only, with models added to map at the top\r\n const sortedModels = React.useMemo(() => {\r\n const bimFiles = files.filter(file => file.extension === 'frag')\r\n\r\n return bimFiles\r\n .map(file => {\r\n const isAddedToMap = bimModelsAddedToMap.some(model => model.bimFile.id === file.id)\r\n return { ...file, isAddedToMap, isVisible: isAddedToMap }\r\n })\r\n .sort((a, b) => {\r\n // Models added to map come first\r\n if (a.isAddedToMap && !b.isAddedToMap) return -1\r\n if (!a.isAddedToMap && b.isAddedToMap) return 1\r\n return 0\r\n })\r\n }, [files, bimModelsAddedToMap])\r\n\r\n // Local state for file management\r\n const [loadedModels, setLoadedModels] = React.useState(sortedModels)\r\n\r\n // Keep local list in sync with sorted models\r\n React.useEffect(() => {\r\n setLoadedModels(sortedModels)\r\n }, [sortedModels])\r\n\r\n const handleToggleModelOnMap = React.useCallback((file: DbFile, isVisible: boolean) => {\r\n if (isVisible) {\r\n // Add model to map — reuse the same payload shape as the building popover\r\n const building = buildings.find(b => b.id === file.attachedFilesBuildingId) ?? currentBuilding ?? null\r\n dispatchToggleBimToMap(bimDispatch, file, building)\r\n } else {\r\n // Remove model from map\r\n bimDispatch({\r\n type: 'REMOVE_BIM_FROM_MAP',\r\n payload: { bimModelName: file.name },\r\n })\r\n }\r\n }, [bimDispatch, buildings])\r\n\r\n const handleMoveModel = React.useCallback((file: DbFile) => {\r\n const isOnMap = bimModelsAddedToMap.some(m => m.bimFile.id === file.id)\r\n if (!isOnMap) return\r\n bimDispatch({\r\n type: 'EDIT_BIM_MODEL_BY_NAME',\r\n payload: { editingBimModel: file.name },\r\n })\r\n }, [bimDispatch, bimModelsAddedToMap])\r\n\r\n const resolveBuildingForFile = React.useCallback(async (file: DbFile) => {\r\n const attachedBuildingId = file.attachedFilesBuildingId\r\n\r\n if (attachedBuildingId == null) {\r\n return currentBuilding ?? null\r\n }\r\n\r\n const cachedBuilding = buildings.find(building => building.id === attachedBuildingId) ?? null\r\n if (cachedBuilding?.buildingOsmId != null) {\r\n return cachedBuilding\r\n }\r\n\r\n try {\r\n const response = await fetch(`/api/buildings/${attachedBuildingId}`)\r\n if (!response.ok) {\r\n return cachedBuilding ?? currentBuilding ?? null\r\n }\r\n\r\n const data = await response.json() as { building?: typeof cachedBuilding }\r\n return data.building ?? cachedBuilding ?? currentBuilding ?? null\r\n }\r\n catch {\r\n return cachedBuilding ?? currentBuilding ?? null\r\n }\r\n }, [buildings, currentBuilding])\r\n\r\n const handleToggleModelOnMapAsync = React.useCallback(async (file: DbFile, isVisible: boolean) => {\r\n if (!isVisible) {\r\n bimDispatch({\r\n type: 'REMOVE_BIM_FROM_MAP',\r\n payload: { bimModelName: file.name },\r\n })\r\n return\r\n }\r\n\r\n const building = await resolveBuildingForFile(file)\r\n dispatchToggleBimToMap(bimDispatch, file, building)\r\n }, [bimDispatch, resolveBuildingForFile])\r\n\r\n // Use the common file actions hook\r\n const { handleAction, deleteDialog } = useFileActions({\r\n files: loadedModels,\r\n setFiles: setLoadedModels,\r\n buildingId: null,\r\n handleDeleteFile,\r\n onView: handleToggleModelOnMapAsync,\r\n onMove: handleMoveModel,\r\n })\r\n\r\n // Filter models based on search query — use sortedModels directly so the\r\n // sidebar always reflects the current BimContext state without waiting for\r\n // the loadedModels sync effect (which lags one render behind).\r\n const filteredModels = React.useMemo(() => {\r\n if (!query.trim()) return sortedModels\r\n return sortedModels.filter(file =>\r\n file.name.toLowerCase().includes(query.toLowerCase())\r\n )\r\n }, [sortedModels, query])\r\n\r\n return (\r\n <div className=\"h-full min-h-0\">\r\n <CollapsibleSection\r\n title={t('modelsTitles')}\r\n icon={LR.Box}\r\n className=\"h-full min-h-0 flex flex-col\"\r\n style={{ height: '100%', minHeight: 0 }}\r\n itemCount={filteredModels.length}\r\n onAddItem={uploadState.uploading ? undefined : handleAddFile}\r\n addItemTitle={uploadState.uploading ? `${t('uploadingFile')} ${uploadState.progress}%` : t('addBimTitle')}\r\n >\r\n <div className=\"flex-1 min-h-0 overflow-y-scroll space-y-1\">\r\n {uploadState.uploading && (\r\n <div className=\"flex items-center gap-2 px-2 py-2 text-sm text-muted-foreground\">\r\n <LoadingSpinner className=\"h-4 w-4\" />\r\n <span>{t('uploadingFile')} {uploadState.progress}%</span>\r\n </div>\r\n )}\r\n {filteredModels.map((file) => (\r\n <div key={file.id}>\r\n <FileItemComponent\r\n file={file}\r\n onAction={handleAction}\r\n options={file.isAddedToMap ? OPTIONS_ON_MAP : OPTIONS_OFF_MAP}\r\n confirmDelete={false}\r\n />\r\n </div>\r\n ))}\r\n </div>\r\n </CollapsibleSection>\r\n\r\n <ConfirmDialog\r\n isOpen={deleteDialog.isOpen}\r\n isDeleting={deleteDialog.isDeleting}\r\n onOpenChange={deleteDialog.onOpenChange}\r\n handleConfirm={deleteDialog.onConfirm}\r\n itemName={deleteDialog.itemName}\r\n />\r\n </div>\r\n )\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAoLc,cACA,YADA;AA/Kd,YAAY,QAAQ;AACpB,SAAS,uBAAuB;AAChC,YAAY,WAAW;AACvB,SAAS,cAAc;AAEvB,SAAS,qBAAqB;AAC9B,SAAS,YAAY,wBAAwB;AAC7C,OAAO,mBAAmB;AAC1B,SAAS,0BAA0B;AACnC,SAAS,sBAAsB,mBAAmB,gBAAgB,iCAAiC;AACnG,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB,8BAA8B;AAMzD,MAAM,iBAA+B,CAAC,YAAY,QAAQ,QAAQ,QAAQ,QAAQ;AAClF,MAAM,kBAAgC,CAAC,YAAY,QAAQ,QAAQ,QAAQ;AAOpE,SAAS,cAAc,EAAE,OAAO,QAAQ,GAAG,GAAuB;AAEvE,QAAM,IAAI,gBAAgB,mBAAmB;AAG7C,QAAM,EAAE,OAAO,UAAU,UAAU,YAAY,IAAI,MAAM,WAAW,UAAU;AAC9E,QAAM,EAAE,oBAAoB,IAAI,SAAS;AAEzC,QAAM,EAAE,OAAO,eAAe,IAAI,MAAM,WAAW,gBAAgB;AACnE,QAAM,EAAE,WAAW,UAAU,gBAAgB,IAAI,eAAe;AAEhE,QAAM,EAAE,WAAW,IAAI,cAAc;AAGrC,QAAM,EAAE,iBAAiB,IAAI,qBAAqB;AAAA,IAChD;AAAA,EACF,CAAC;AAGD,QAAM,EAAE,eAAe,YAAY,IAAI,0BAA0B;AAAA,IAC/D,mBAAmB;AAAA,IACnB,iBAAiB,MAAM;AACrB,aAAO,YAAY;AAAA,IACrB;AAAA,IACA,eAAe,CAAC,UAAU;AACxB,cAAQ,MAAM,0BAA0B,KAAK;AAAA,IAC/C;AAAA,EACF,CAAC;AAGD,QAAM,eAAe,MAAM,QAAQ,MAAM;AACvC,UAAM,WAAW,MAAM,OAAO,UAAQ,KAAK,cAAc,MAAM;AAE/D,WAAO,SACJ,IAAI,UAAQ;AACX,YAAM,eAAe,oBAAoB,KAAK,WAAS,MAAM,QAAQ,OAAO,KAAK,EAAE;AACnF,aAAO,iCAAK,OAAL,EAAW,cAAc,WAAW,aAAa;AAAA,IAC1D,CAAC,EACA,KAAK,CAAC,GAAG,MAAM;AAEd,UAAI,EAAE,gBAAgB,CAAC,EAAE,aAAc,QAAO;AAC9C,UAAI,CAAC,EAAE,gBAAgB,EAAE,aAAc,QAAO;AAC9C,aAAO;AAAA,IACT,CAAC;AAAA,EACL,GAAG,CAAC,OAAO,mBAAmB,CAAC;AAG/B,QAAM,CAAC,cAAc,eAAe,IAAI,MAAM,SAAS,YAAY;AAGnE,QAAM,UAAU,MAAM;AACpB,oBAAgB,YAAY;AAAA,EAC9B,GAAG,CAAC,YAAY,CAAC;AAEjB,QAAM,yBAAyB,MAAM,YAAY,CAAC,MAAc,cAAuB;AApFzF;AAqFI,QAAI,WAAW;AAEb,YAAM,YAAW,qBAAU,KAAK,OAAK,EAAE,OAAO,KAAK,uBAAuB,MAAzD,YAA8D,oBAA9D,YAAiF;AAClG,6BAAuB,aAAa,MAAM,QAAQ;AAAA,IACpD,OAAO;AAEL,kBAAY;AAAA,QACV,MAAM;AAAA,QACN,SAAS,EAAE,cAAc,KAAK,KAAK;AAAA,MACrC,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,aAAa,SAAS,CAAC;AAE3B,QAAM,kBAAkB,MAAM,YAAY,CAAC,SAAiB;AAC1D,UAAM,UAAU,oBAAoB,KAAK,OAAK,EAAE,QAAQ,OAAO,KAAK,EAAE;AACtE,QAAI,CAAC,QAAS;AACd,gBAAY;AAAA,MACV,MAAM;AAAA,MACN,SAAS,EAAE,iBAAiB,KAAK,KAAK;AAAA,IACxC,CAAC;AAAA,EACH,GAAG,CAAC,aAAa,mBAAmB,CAAC;AAErC,QAAM,yBAAyB,MAAM,YAAY,OAAO,SAAiB;AA3G3E;AA4GI,UAAM,qBAAqB,KAAK;AAEhC,QAAI,sBAAsB,MAAM;AAC9B,aAAO,4CAAmB;AAAA,IAC5B;AAEA,UAAM,kBAAiB,eAAU,KAAK,cAAY,SAAS,OAAO,kBAAkB,MAA7D,YAAkE;AACzF,SAAI,iDAAgB,kBAAiB,MAAM;AACzC,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,kBAAkB,kBAAkB,EAAE;AACnE,UAAI,CAAC,SAAS,IAAI;AAChB,gBAAO,+CAAkB,oBAAlB,YAAqC;AAAA,MAC9C;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,cAAO,sBAAK,aAAL,YAAiB,mBAAjB,YAAmC,oBAAnC,YAAsD;AAAA,IAC/D,SACM;AACJ,cAAO,+CAAkB,oBAAlB,YAAqC;AAAA,IAC9C;AAAA,EACF,GAAG,CAAC,WAAW,eAAe,CAAC;AAE/B,QAAM,8BAA8B,MAAM,YAAY,OAAO,MAAc,cAAuB;AAChG,QAAI,CAAC,WAAW;AACd,kBAAY;AAAA,QACV,MAAM;AAAA,QACN,SAAS,EAAE,cAAc,KAAK,KAAK;AAAA,MACrC,CAAC;AACD;AAAA,IACF;AAEA,UAAM,WAAW,MAAM,uBAAuB,IAAI;AAClD,2BAAuB,aAAa,MAAM,QAAQ;AAAA,EACpD,GAAG,CAAC,aAAa,sBAAsB,CAAC;AAGxC,QAAM,EAAE,cAAc,aAAa,IAAI,eAAe;AAAA,IACpD,OAAO;AAAA,IACP,UAAU;AAAA,IACV,YAAY;AAAA,IACZ;AAAA,IACA,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AAKD,QAAM,iBAAiB,MAAM,QAAQ,MAAM;AACzC,QAAI,CAAC,MAAM,KAAK,EAAG,QAAO;AAC1B,WAAO,aAAa;AAAA,MAAO,UACzB,KAAK,KAAK,YAAY,EAAE,SAAS,MAAM,YAAY,CAAC;AAAA,IACtD;AAAA,EACF,GAAG,CAAC,cAAc,KAAK,CAAC;AAExB,SACE,qBAAC,SAAI,WAAU,kBACb;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,cAAc;AAAA,QACvB,MAAM,GAAG;AAAA,QACT,WAAU;AAAA,QACV,OAAO,EAAE,QAAQ,QAAQ,WAAW,EAAE;AAAA,QACtC,WAAW,eAAe;AAAA,QAC1B,WAAW,YAAY,YAAY,SAAY;AAAA,QAC/C,cAAc,YAAY,YAAY,GAAG,EAAE,eAAe,CAAC,IAAI,YAAY,QAAQ,MAAM,EAAE,aAAa;AAAA,QAExG,+BAAC,SAAI,WAAU,8CACZ;AAAA,sBAAY,aACX,qBAAC,SAAI,WAAU,mEACb;AAAA,gCAAC,kBAAe,WAAU,WAAU;AAAA,YACpC,qBAAC,UAAM;AAAA,gBAAE,eAAe;AAAA,cAAE;AAAA,cAAE,YAAY;AAAA,cAAS;AAAA,eAAC;AAAA,aACpD;AAAA,UAED,eAAe,IAAI,CAAC,SACnB,oBAAC,SACC;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA,UAAU;AAAA,cACV,SAAS,KAAK,eAAe,iBAAiB;AAAA,cAC9C,eAAe;AAAA;AAAA,UACjB,KANQ,KAAK,EAOf,CACD;AAAA,WACH;AAAA;AAAA,IACF;AAAA,IAEA;AAAA,MAAC;AAAA;AAAA,QACC,QAAQ,aAAa;AAAA,QACrB,YAAY,aAAa;AAAA,QACzB,cAAc,aAAa;AAAA,QAC3B,eAAe,aAAa;AAAA,QAC5B,UAAU,aAAa;AAAA;AAAA,IACzB;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -5,7 +5,5 @@ export interface FileItem {
|
|
|
5
5
|
icon: React.ElementType;
|
|
6
6
|
visible: boolean;
|
|
7
7
|
}
|
|
8
|
-
export declare function SensorsTab(
|
|
9
|
-
minioBaseUrl?: string;
|
|
10
|
-
}): React.JSX.Element;
|
|
8
|
+
export declare function SensorsTab(): React.JSX.Element;
|
|
11
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAA;AAChE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,KAAK,CAAC,WAAW,CAAA;IACvB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,UAAU,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAI9B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,oCAAoC,CAAA;AAChE,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,KAAK,CAAC,WAAW,CAAA;IACvB,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,UAAU,sBAMzB"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import { SensorsSection } from "../../../../../../ui/Sensors/SensorsSection";
|
|
4
|
-
function SensorsTab(
|
|
5
|
-
return /* @__PURE__ */ jsx("div", { className: "flex-1 flex flex-col space-y-6 py-4 overflow-hidden", children: /* @__PURE__ */ jsx(SensorsSection, {
|
|
4
|
+
function SensorsTab() {
|
|
5
|
+
return /* @__PURE__ */ jsx("div", { className: "flex-1 flex flex-col space-y-6 py-4 overflow-hidden", children: /* @__PURE__ */ jsx(SensorsSection, {}) });
|
|
6
6
|
}
|
|
7
7
|
export {
|
|
8
8
|
SensorsTab
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\n\r\nimport { SensorsSection } from '../../../../../../ui/Sensors/SensorsSection'\r\n\r\nimport type { DbFile } from '../../../../../../../types/dbTypes'\r\nexport interface FileItem {\r\n task: DbFile\r\n icon: React.ElementType\r\n visible: boolean\r\n}\r\n\r\nexport function SensorsTab(
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../src/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\n\r\nimport { SensorsSection } from '../../../../../../ui/Sensors/SensorsSection'\r\n\r\nimport type { DbFile } from '../../../../../../../types/dbTypes'\r\nexport interface FileItem {\r\n task: DbFile\r\n icon: React.ElementType\r\n visible: boolean\r\n}\r\n\r\nexport function SensorsTab() {\r\n return (\r\n <div className=\"flex-1 flex flex-col space-y-6 py-4 overflow-hidden\">\r\n <SensorsSection />\r\n </div>\r\n )\r\n}\r\n"],"mappings":";AAmBM;AAZN,SAAS,sBAAsB;AASxB,SAAS,aAAa;AAC3B,SACE,oBAAC,SAAI,WAAU,uDACb,8BAAC,kBAAe,GAClB;AAEJ;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uploadToPresignedURLS.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/tools/AddTools/AddFile/utils/uploadToPresignedURLS.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,oBAAoB,GAAU,iBAAY,EAAE,SAAI,sBAmB5D,CAAA;AACD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAInD;AAED,eAAO,MAAM,sBAAsB,GAAU,iBAAY,EAAE,SAAI,EAAE,eAAU,
|
|
1
|
+
{"version":3,"file":"uploadToPresignedURLS.d.ts","sourceRoot":"","sources":["../../../../../../../../../../src/core/components/viewers/map/src/tools/AddTools/AddFile/utils/uploadToPresignedURLS.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,oBAAoB,GAAU,iBAAY,EAAE,SAAI,sBAmB5D,CAAA;AACD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAInD;AAED,eAAO,MAAM,sBAAsB,GAAU,iBAAY,EAAE,SAAI,EAAE,eAAU,qBA8B1E,CAAA"}
|
package/dist/core/components/viewers/map/src/tools/AddTools/AddFile/utils/uploadToPresignedURLS.js
CHANGED
|
@@ -27,9 +27,7 @@ const uploadFileWithProgress = async (presignedUrl, file, onProgress) => {
|
|
|
27
27
|
xhr.upload.addEventListener("progress", (event) => {
|
|
28
28
|
if (event.lengthComputable) {
|
|
29
29
|
const percentComplete = Math.round(event.loaded / event.total * 100);
|
|
30
|
-
onProgress(percentComplete, event.loaded
|
|
31
|
-
console.log(`Upload progress: ${percent}%`);
|
|
32
|
-
});
|
|
30
|
+
onProgress(percentComplete, event.loaded);
|
|
33
31
|
}
|
|
34
32
|
});
|
|
35
33
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/tools/AddTools/AddFile/utils/uploadToPresignedURLS.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nexport const uploadToPresignedUrl = async (presignedUrl, file) => {\r\n try {\r\n const response = await fetch(presignedUrl, {\r\n method: 'PUT',\r\n body: file,\r\n headers: {\r\n 'Content-Type': file.type,\r\n },\r\n })\r\n\r\n if (!response.ok) {\r\n throw new Error(`Upload failed: ${response.status} ${response.statusText}`)\r\n }\r\n\r\n return response\r\n }\r\n catch (error) {\r\n throw new Error(`Upload failed: ${error.message}`)\r\n }\r\n}\r\nexport function getFileExtension(file: File): string {\r\n const parts = file.name.split('.')\r\n if (parts.length <= 1) return ''\r\n return parts.pop()!.toLowerCase()\r\n}\r\n// Progress version\r\nexport const uploadFileWithProgress = async (presignedUrl, file, onProgress) => {\r\n return new Promise((resolve, reject) => {\r\n const xhr = new XMLHttpRequest()\r\n\r\n if (onProgress) {\r\n xhr.upload.addEventListener('progress', (event) => {\r\n if (event.lengthComputable) {\r\n const percentComplete = Math.round((event.loaded / event.total) * 100)\r\n onProgress(percentComplete, event.loaded
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../src/core/components/viewers/map/src/tools/AddTools/AddFile/utils/uploadToPresignedURLS.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nexport const uploadToPresignedUrl = async (presignedUrl, file) => {\r\n try {\r\n const response = await fetch(presignedUrl, {\r\n method: 'PUT',\r\n body: file,\r\n headers: {\r\n 'Content-Type': file.type,\r\n },\r\n })\r\n\r\n if (!response.ok) {\r\n throw new Error(`Upload failed: ${response.status} ${response.statusText}`)\r\n }\r\n\r\n return response\r\n }\r\n catch (error) {\r\n throw new Error(`Upload failed: ${error.message}`)\r\n }\r\n}\r\nexport function getFileExtension(file: File): string {\r\n const parts = file.name.split('.')\r\n if (parts.length <= 1) return ''\r\n return parts.pop()!.toLowerCase()\r\n}\r\n// Progress version\r\nexport const uploadFileWithProgress = async (presignedUrl, file, onProgress) => {\r\n return new Promise((resolve, reject) => {\r\n const xhr = new XMLHttpRequest()\r\n\r\n if (onProgress) {\r\n xhr.upload.addEventListener('progress', (event) => {\r\n if (event.lengthComputable) {\r\n const percentComplete = Math.round((event.loaded / event.total) * 100)\r\n onProgress(percentComplete, event.loaded)\r\n }\r\n })\r\n }\r\n\r\n xhr.addEventListener('load', () => {\r\n if (xhr.status >= 200 && xhr.status < 300) {\r\n resolve(xhr)\r\n }\r\n else {\r\n reject(new Error(`Upload failed: ${xhr.status}`))\r\n }\r\n })\r\n\r\n xhr.addEventListener('error', () => {\r\n reject(new Error('Network error occurred'))\r\n })\r\n\r\n xhr.open('PUT', presignedUrl)\r\n xhr.setRequestHeader('Content-Type', file.type)\r\n xhr.send(file)\r\n })\r\n}\r\n"],"mappings":"AAGO,MAAM,uBAAuB,OAAO,cAAc,SAAS;AAChE,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,cAAc;AAAA,MACzC,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,QACP,gBAAgB,KAAK;AAAA,MACvB;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,MAAM,kBAAkB,SAAS,MAAM,IAAI,SAAS,UAAU,EAAE;AAAA,IAC5E;AAEA,WAAO;AAAA,EACT,SACO,OAAO;AACZ,UAAM,IAAI,MAAM,kBAAkB,MAAM,OAAO,EAAE;AAAA,EACnD;AACF;AACO,SAAS,iBAAiB,MAAoB;AACnD,QAAM,QAAQ,KAAK,KAAK,MAAM,GAAG;AACjC,MAAI,MAAM,UAAU,EAAG,QAAO;AAC9B,SAAO,MAAM,IAAI,EAAG,YAAY;AAClC;AAEO,MAAM,yBAAyB,OAAO,cAAc,MAAM,eAAe;AAC9E,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,MAAM,IAAI,eAAe;AAE/B,QAAI,YAAY;AACd,UAAI,OAAO,iBAAiB,YAAY,CAAC,UAAU;AACjD,YAAI,MAAM,kBAAkB;AAC1B,gBAAM,kBAAkB,KAAK,MAAO,MAAM,SAAS,MAAM,QAAS,GAAG;AACrE,qBAAW,iBAAiB,MAAM,MAAM;AAAA,QAC1C;AAAA,MACF,CAAC;AAAA,IACH;AAEA,QAAI,iBAAiB,QAAQ,MAAM;AACjC,UAAI,IAAI,UAAU,OAAO,IAAI,SAAS,KAAK;AACzC,gBAAQ,GAAG;AAAA,MACb,OACK;AACH,eAAO,IAAI,MAAM,kBAAkB,IAAI,MAAM,EAAE,CAAC;AAAA,MAClD;AAAA,IACF,CAAC;AAED,QAAI,iBAAiB,SAAS,MAAM;AAClC,aAAO,IAAI,MAAM,wBAAwB,CAAC;AAAA,IAC5C,CAAC;AAED,QAAI,KAAK,OAAO,YAAY;AAC5B,QAAI,iBAAiB,gBAAgB,KAAK,IAAI;AAC9C,QAAI,KAAK,IAAI;AAAA,EACf,CAAC;AACH;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MapClickManager.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/utils/MapEventManager/MapClickManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,UAAU,MAAM,aAAa,CAAA;AAEzC;;;;GAIG;AACH,oBAAY,qBAAqB;IAG/B,sBAAsB,KAAK;IAC3B,2BAA2B,MAAM;IACjC,0BAA0B,MAAM;IAChC,wBAAwB,MAAM;IAC9B,0BAA0B,MAAM;IAChC,sBAAsB,MAAM;IAC5B,qBAAqB,MAAM;IAC3B,UAAU,OAAO;CAClB;AACD,MAAM,MAAM,aAAa,GAAG,CAC1B,KAAK,EAAE,UAAU,CAAC,aAAa,EAC/B,QAAQ,EAAE,UAAU,CAAC,iBAAiB,EAAE,KACrC,IAAI,CAAA;AAQT,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAgB;IAC3B,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,mBAAmB,CAAqC;gBAEpD,GAAG,EAAE,UAAU,CAAC,GAAG;IAOxB,QAAQ,CACb,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,qBAAqB,EAC/B,QAAQ,EAAE,aAAa;IAOlB,UAAU,CAAC,OAAO,KAAA;IAKzB,OAAO,CAAC,cAAc;
|
|
1
|
+
{"version":3,"file":"MapClickManager.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/utils/MapEventManager/MapClickManager.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,UAAU,MAAM,aAAa,CAAA;AAEzC;;;;GAIG;AACH,oBAAY,qBAAqB;IAG/B,sBAAsB,KAAK;IAC3B,2BAA2B,MAAM;IACjC,0BAA0B,MAAM;IAChC,wBAAwB,MAAM;IAC9B,0BAA0B,MAAM;IAChC,sBAAsB,MAAM;IAC5B,qBAAqB,MAAM;IAC3B,UAAU,OAAO;CAClB;AACD,MAAM,MAAM,aAAa,GAAG,CAC1B,KAAK,EAAE,UAAU,CAAC,aAAa,EAC/B,QAAQ,EAAE,UAAU,CAAC,iBAAiB,EAAE,KACrC,IAAI,CAAA;AAQT,qBAAa,eAAe;IAC1B,OAAO,CAAC,GAAG,CAAgB;IAC3B,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,mBAAmB,CAAqC;gBAEpD,GAAG,EAAE,UAAU,CAAC,GAAG;IAOxB,QAAQ,CACb,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,qBAAqB,EAC/B,QAAQ,EAAE,aAAa;IAOlB,UAAU,CAAC,OAAO,KAAA;IAKzB,OAAO,CAAC,cAAc;IA2BtB,OAAO;CAIR"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../src/core/components/viewers/map/utils/MapEventManager/MapClickManager.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// MapClickManager.ts\r\nimport type maplibregl from 'maplibre-gl'\r\n\r\n/**\r\n * This is very important. Declare a new priority for your layer in this enum if you need to,\r\n * otherwise, just use the one that has been declared\r\n * Higher priority is clicked first.\r\n */\r\nexport enum MapLayerClickPriority {\r\n // Lowest priority: a site polygon only handles a click when no other\r\n // interactive layer (buildings, comments, sensors, files, ...) was hit.\r\n SiteLayerClickPriority = 50,\r\n BuildingLayersClickPriority = 100,\r\n CommentLayersClickPriority = 200,\r\n MartinLayerClickPriority = 300,\r\n OpenDataLayerClickPriority = 350,\r\n FileLayerCLickPriority = 400,\r\n BimModelLayerPriority = 600,\r\n ActiveTool = 1000, // SPECIAL ONE, MAKE SURE TO DISABLE THE TOOL WHEN YOU ARE FINISH.\r\n}\r\nexport type ClickCallback = (\r\n event: maplibregl.MapMouseEvent,\r\n features: maplibregl.MapGeoJSONFeature[],\r\n) => void\r\n\r\ninterface LayerClickHandler {\r\n layerId: string\r\n priority: number\r\n callback: ClickCallback\r\n}\r\n\r\nexport class MapClickManager {\r\n private map: maplibregl.Map // the instance of the map\r\n private clickHandlers: LayerClickHandler[] // all click handlers for layers that has been registered\r\n private boundedClickHandler: (e: maplibregl.MapMouseEvent) => {} // clickHandler has \"this\" object binded to it, so inside the handleClick private function, we can still access this.map.\r\n\r\n constructor(map: maplibregl.Map) {\r\n this.map = map\r\n this.boundedClickHandler = this.handleMapClick.bind(this)\r\n this.clickHandlers = []\r\n this.map.on('click', this.boundedClickHandler)\r\n }\r\n\r\n public register(\r\n layerId: string,\r\n priority: MapLayerClickPriority,\r\n callback: ClickCallback,\r\n ) {\r\n this.clickHandlers.push({ layerId, priority, callback })\r\n this.clickHandlers.sort((a, b) => b.priority - a.priority)\r\n // console.log(this.clickHandlers)\r\n }\r\n\r\n public unregister(layerId) {\r\n this.clickHandlers = this.clickHandlers.filter(handler => handler.layerId !== layerId)\r\n // console.log(this.clickHandlers)\r\n }\r\n\r\n private handleMapClick(e: maplibregl.MapMouseEvent) {\r\n // for active tools\r\n for (const handler of this.clickHandlers) {\r\n if (handler.priority === MapLayerClickPriority.ActiveTool) {\r\n handler.callback(e, [])\r\n
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/core/components/viewers/map/utils/MapEventManager/MapClickManager.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// MapClickManager.ts\r\nimport type maplibregl from 'maplibre-gl'\r\n\r\n/**\r\n * This is very important. Declare a new priority for your layer in this enum if you need to,\r\n * otherwise, just use the one that has been declared\r\n * Higher priority is clicked first.\r\n */\r\nexport enum MapLayerClickPriority {\r\n // Lowest priority: a site polygon only handles a click when no other\r\n // interactive layer (buildings, comments, sensors, files, ...) was hit.\r\n SiteLayerClickPriority = 50,\r\n BuildingLayersClickPriority = 100,\r\n CommentLayersClickPriority = 200,\r\n MartinLayerClickPriority = 300,\r\n OpenDataLayerClickPriority = 350,\r\n FileLayerCLickPriority = 400,\r\n BimModelLayerPriority = 600,\r\n ActiveTool = 1000, // SPECIAL ONE, MAKE SURE TO DISABLE THE TOOL WHEN YOU ARE FINISH.\r\n}\r\nexport type ClickCallback = (\r\n event: maplibregl.MapMouseEvent,\r\n features: maplibregl.MapGeoJSONFeature[],\r\n) => void\r\n\r\ninterface LayerClickHandler {\r\n layerId: string\r\n priority: number\r\n callback: ClickCallback\r\n}\r\n\r\nexport class MapClickManager {\r\n private map: maplibregl.Map // the instance of the map\r\n private clickHandlers: LayerClickHandler[] // all click handlers for layers that has been registered\r\n private boundedClickHandler: (e: maplibregl.MapMouseEvent) => {} // clickHandler has \"this\" object binded to it, so inside the handleClick private function, we can still access this.map.\r\n\r\n constructor(map: maplibregl.Map) {\r\n this.map = map\r\n this.boundedClickHandler = this.handleMapClick.bind(this)\r\n this.clickHandlers = []\r\n this.map.on('click', this.boundedClickHandler)\r\n }\r\n\r\n public register(\r\n layerId: string,\r\n priority: MapLayerClickPriority,\r\n callback: ClickCallback,\r\n ) {\r\n this.clickHandlers.push({ layerId, priority, callback })\r\n this.clickHandlers.sort((a, b) => b.priority - a.priority)\r\n // console.log(this.clickHandlers)\r\n }\r\n\r\n public unregister(layerId) {\r\n this.clickHandlers = this.clickHandlers.filter(handler => handler.layerId !== layerId)\r\n // console.log(this.clickHandlers)\r\n }\r\n\r\n private handleMapClick(e: maplibregl.MapMouseEvent) {\r\n // for active tools\r\n for (const handler of this.clickHandlers) {\r\n if (handler.priority === MapLayerClickPriority.ActiveTool) {\r\n handler.callback(e, [])\r\n return\r\n }\r\n }\r\n\r\n // console.log(e.point)\r\n const features = this.map.queryRenderedFeatures(e.point)\r\n // console.log(features)\r\n\r\n if (!features) return\r\n\r\n for (let i = 0; i < this.clickHandlers.length; i++) {\r\n const currentHandler = this.clickHandlers[i]\r\n const hits = features.filter(f => f.layer?.id == currentHandler.layerId)\r\n\r\n if (hits.length > 0) {\r\n // console.log(currentHandler)\r\n currentHandler.callback(e, hits)\r\n break\r\n }\r\n }\r\n }\r\n\r\n destroy() {\r\n this.map.off('click', this.boundedClickHandler)\r\n this.clickHandlers = []\r\n }\r\n}\r\n"],"mappings":"AAWO,IAAK,wBAAL,kBAAKA,2BAAL;AAGL,EAAAA,8CAAA,4BAAyB,MAAzB;AACA,EAAAA,8CAAA,iCAA8B,OAA9B;AACA,EAAAA,8CAAA,gCAA6B,OAA7B;AACA,EAAAA,8CAAA,8BAA2B,OAA3B;AACA,EAAAA,8CAAA,gCAA6B,OAA7B;AACA,EAAAA,8CAAA,4BAAyB,OAAzB;AACA,EAAAA,8CAAA,2BAAwB,OAAxB;AACA,EAAAA,8CAAA,gBAAa,OAAb;AAVU,SAAAA;AAAA,GAAA;AAuBL,MAAM,gBAAgB;AAAA;AAAA,EAK3B,YAAY,KAAqB;AAC/B,SAAK,MAAM;AACX,SAAK,sBAAsB,KAAK,eAAe,KAAK,IAAI;AACxD,SAAK,gBAAgB,CAAC;AACtB,SAAK,IAAI,GAAG,SAAS,KAAK,mBAAmB;AAAA,EAC/C;AAAA,EAEO,SACL,SACA,UACA,UACA;AACA,SAAK,cAAc,KAAK,EAAE,SAAS,UAAU,SAAS,CAAC;AACvD,SAAK,cAAc,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,EAAE,QAAQ;AAAA,EAE3D;AAAA,EAEO,WAAW,SAAS;AACzB,SAAK,gBAAgB,KAAK,cAAc,OAAO,aAAW,QAAQ,YAAY,OAAO;AAAA,EAEvF;AAAA,EAEQ,eAAe,GAA6B;AAElD,eAAW,WAAW,KAAK,eAAe;AACxC,UAAI,QAAQ,aAAa,sBAAkC;AACzD,gBAAQ,SAAS,GAAG,CAAC,CAAC;AACtB;AAAA,MACF;AAAA,IACF;AAGA,UAAM,WAAW,KAAK,IAAI,sBAAsB,EAAE,KAAK;AAGvD,QAAI,CAAC,SAAU;AAEf,aAAS,IAAI,GAAG,IAAI,KAAK,cAAc,QAAQ,KAAK;AAClD,YAAM,iBAAiB,KAAK,cAAc,CAAC;AAC3C,YAAM,OAAO,SAAS,OAAO,OAAE;AA9ErC;AA8EwC,wBAAE,UAAF,mBAAS,OAAM,eAAe;AAAA,OAAO;AAEvE,UAAI,KAAK,SAAS,GAAG;AAEnB,uBAAe,SAAS,GAAG,IAAI;AAC/B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,UAAU;AACR,SAAK,IAAI,IAAI,SAAS,KAAK,mBAAmB;AAC9C,SAAK,gBAAgB,CAAC;AAAA,EACxB;AACF;","names":["MapLayerClickPriority"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"flyToEach.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/map/utils/flyToEach.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAEtC,eAAO,MAAM,SAAS,GAAU,KAAK,GAAG,EAAE,WAAW,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"flyToEach.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/map/utils/flyToEach.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AACzD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAEtC,eAAO,MAAM,SAAS,GAAU,KAAK,GAAG,EAAE,WAAW,QAAQ,EAAE,kBAsB9D,CAAA"}
|
|
@@ -8,7 +8,6 @@ const flyToEach = async (map, buildings) => {
|
|
|
8
8
|
if (osmId) {
|
|
9
9
|
building.buildingOsmId = String(osmId);
|
|
10
10
|
}
|
|
11
|
-
console.log("OSM ID for", building.buildingName, ":", osmId);
|
|
12
11
|
if (typeof osmId === "number") {
|
|
13
12
|
await updateBuildingOsmId(building.id, osmId);
|
|
14
13
|
} else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../src/core/components/viewers/map/utils/flyToEach.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport { getOsmIdFromLatLng } from './getOsmIdFromMartin'\r\nimport { updateBuildingOsmId } from './updateBuildingOsmId'\r\n\r\nimport type { Building } from '../../../../types/dbTypes'\r\nimport type { Map } from 'maplibre-gl'\r\n\r\nexport const flyToEach = async (map: Map, buildings: Building[]) => {\r\n // Sequentially process each building and wait for each to finish\r\n for (const building of buildings) {\r\n if (building.buildingOsmId) continue\r\n try {\r\n const osmId = await getOsmIdFromLatLng(map, building.buildingLatitude, building.buildingLongitude)\r\n if (osmId) {\r\n building.buildingOsmId = String(osmId)\r\n }\r\n
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/core/components/viewers/map/utils/flyToEach.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport { getOsmIdFromLatLng } from './getOsmIdFromMartin'\r\nimport { updateBuildingOsmId } from './updateBuildingOsmId'\r\n\r\nimport type { Building } from '../../../../types/dbTypes'\r\nimport type { Map } from 'maplibre-gl'\r\n\r\nexport const flyToEach = async (map: Map, buildings: Building[]) => {\r\n // Sequentially process each building and wait for each to finish\r\n for (const building of buildings) {\r\n if (building.buildingOsmId) continue\r\n try {\r\n const osmId = await getOsmIdFromLatLng(map, building.buildingLatitude, building.buildingLongitude)\r\n if (osmId) {\r\n building.buildingOsmId = String(osmId)\r\n }\r\n if (typeof osmId === 'number') {\r\n await updateBuildingOsmId(building.id, osmId)\r\n }\r\n else {\r\n throw new TypeError(`Failed to fetch OSM ID for ${building.buildingName}`)\r\n }\r\n }\r\n catch (error) {\r\n console.error(error)\r\n // Optionally continue on error, or break if you want to stop\r\n // continue;\r\n }\r\n }\r\n}\r\n"],"mappings":"AAGA,SAAS,0BAA0B;AACnC,SAAS,2BAA2B;AAK7B,MAAM,YAAY,OAAO,KAAU,cAA0B;AAElE,aAAW,YAAY,WAAW;AAChC,QAAI,SAAS,cAAe;AAC5B,QAAI;AACF,YAAM,QAAQ,MAAM,mBAAmB,KAAK,SAAS,kBAAkB,SAAS,iBAAiB;AACjG,UAAI,OAAO;AACT,iBAAS,gBAAgB,OAAO,KAAK;AAAA,MACvC;AACA,UAAI,OAAO,UAAU,UAAU;AAC7B,cAAM,oBAAoB,SAAS,IAAI,KAAK;AAAA,MAC9C,OACK;AACH,cAAM,IAAI,UAAU,8BAA8B,SAAS,YAAY,EAAE;AAAA,MAC3E;AAAA,IACF,SACO,OAAO;AACZ,cAAQ,MAAM,KAAK;AAAA,IAGrB;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getOsmIdbyCoordinates.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/map/utils/getOsmIdbyCoordinates.ts"],"names":[],"mappings":"AAGA,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"getOsmIdbyCoordinates.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/map/utils/getOsmIdbyCoordinates.ts"],"names":[],"mappings":"AAGA,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA6CxB"}
|
|
@@ -7,7 +7,6 @@ async function getOsmId(latitude, longitude) {
|
|
|
7
7
|
const headers = {
|
|
8
8
|
"User-Agent": "CDT-NA/1.0 (narellano@cims.carleton.ca)"
|
|
9
9
|
};
|
|
10
|
-
console.log(url.toString());
|
|
11
10
|
await new Promise((resolve) => setTimeout(resolve, 2e3));
|
|
12
11
|
try {
|
|
13
12
|
const response = await fetch(url.toString(), { headers });
|
|
@@ -16,7 +15,6 @@ async function getOsmId(latitude, longitude) {
|
|
|
16
15
|
return null;
|
|
17
16
|
}
|
|
18
17
|
const data = await response.json();
|
|
19
|
-
console.log("Nominatim response:", data);
|
|
20
18
|
if (data && (typeof data.osm_id === "string" || typeof data.osm_id === "number")) {
|
|
21
19
|
const osmIdNum = Number(data.osm_id);
|
|
22
20
|
if (isNaN(osmIdNum)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../src/core/components/viewers/map/utils/getOsmIdbyCoordinates.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nexport async function getOsmId(\r\n latitude: number,\r\n longitude: number,\r\n): Promise<number | null> {\r\n const nominatimApiUrl = 'https://nominatim.openstreetmap.org/reverse'\r\n\r\n const url = new URL(nominatimApiUrl)\r\n url.searchParams.append('format', 'json')\r\n url.searchParams.append('lat', latitude.toString())\r\n url.searchParams.append('lon', longitude.toString())\r\n\r\n // Set User-Agent and Referer headers\r\n const headers = {\r\n 'User-Agent': 'CDT-NA/1.0 (narellano@cims.carleton.ca)',\r\n }\r\n\r\n
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/core/components/viewers/map/utils/getOsmIdbyCoordinates.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nexport async function getOsmId(\r\n latitude: number,\r\n longitude: number,\r\n): Promise<number | null> {\r\n const nominatimApiUrl = 'https://nominatim.openstreetmap.org/reverse'\r\n\r\n const url = new URL(nominatimApiUrl)\r\n url.searchParams.append('format', 'json')\r\n url.searchParams.append('lat', latitude.toString())\r\n url.searchParams.append('lon', longitude.toString())\r\n\r\n // Set User-Agent and Referer headers\r\n const headers = {\r\n 'User-Agent': 'CDT-NA/1.0 (narellano@cims.carleton.ca)',\r\n }\r\n\r\n // Wait at least 1000ms between requests\r\n await new Promise(resolve => setTimeout(resolve, 2000))\r\n\r\n try {\r\n const response = await fetch(url.toString(), { headers })\r\n\r\n if (!response.ok) {\r\n console.error(`HTTP error! Status: ${response.status}`)\r\n return null\r\n }\r\n\r\n const data = await response.json()\r\n\r\n if (data && (typeof data.osm_id === 'string' || typeof data.osm_id === 'number')) {\r\n const osmIdNum = Number(data.osm_id)\r\n if (isNaN(osmIdNum)) {\r\n console.warn('OSM ID is not a valid number:', data.osm_id)\r\n return null\r\n }\r\n else {\r\n return osmIdNum\r\n }\r\n }\r\n else {\r\n console.warn('No OSM ID found for the given coordinates in the response:', data)\r\n return null\r\n }\r\n }\r\n catch (error) {\r\n console.error('Error fetching OSM ID:', error)\r\n return null\r\n }\r\n}\r\n\r\n// Attribution: Data © OpenStreetMap contributors, ODbL license.\r\n"],"mappings":"AAGA,eAAsB,SACpB,UACA,WACwB;AACxB,QAAM,kBAAkB;AAExB,QAAM,MAAM,IAAI,IAAI,eAAe;AACnC,MAAI,aAAa,OAAO,UAAU,MAAM;AACxC,MAAI,aAAa,OAAO,OAAO,SAAS,SAAS,CAAC;AAClD,MAAI,aAAa,OAAO,OAAO,UAAU,SAAS,CAAC;AAGnD,QAAM,UAAU;AAAA,IACd,cAAc;AAAA,EAChB;AAGA,QAAM,IAAI,QAAQ,aAAW,WAAW,SAAS,GAAI,CAAC;AAEtD,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG,EAAE,QAAQ,CAAC;AAExD,QAAI,CAAC,SAAS,IAAI;AAChB,cAAQ,MAAM,uBAAuB,SAAS,MAAM,EAAE;AACtD,aAAO;AAAA,IACT;AAEA,UAAM,OAAO,MAAM,SAAS,KAAK;AAEjC,QAAI,SAAS,OAAO,KAAK,WAAW,YAAY,OAAO,KAAK,WAAW,WAAW;AAChF,YAAM,WAAW,OAAO,KAAK,MAAM;AACnC,UAAI,MAAM,QAAQ,GAAG;AACnB,gBAAQ,KAAK,iCAAiC,KAAK,MAAM;AACzD,eAAO;AAAA,MACT,OACK;AACH,eAAO;AAAA,MACT;AAAA,IACF,OACK;AACH,cAAQ,KAAK,8DAA8D,IAAI;AAC/E,aAAO;AAAA,IACT;AAAA,EACF,SACO,OAAO;AACZ,YAAQ,MAAM,0BAA0B,KAAK;AAC7C,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { ClusterMember } from './types';
|
|
3
|
+
interface BimMarkerClusterProps {
|
|
4
|
+
members: ClusterMember[];
|
|
5
|
+
highlight?: boolean;
|
|
6
|
+
onSelect?: (id: number) => void;
|
|
7
|
+
onFocus?: (id: number) => void;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Rendered inside a CSS2DObject at a cluster's world center. Shows a numbered circle for
|
|
11
|
+
* overlapping BIM markers; hovering fans the members out (animated) so each can be
|
|
12
|
+
* seen and clicked, and collapses back on mouse-out. A short close delay keeps the fan open
|
|
13
|
+
* while the pointer crosses the gap between the bubble and a member (same trick the map
|
|
14
|
+
* cluster expansion uses), so members stay clickable. Members mount only while expanded, so a
|
|
15
|
+
* collapsed cluster is just the bubble — no leftover container behind it.
|
|
16
|
+
*/
|
|
17
|
+
export declare function BimMarkerCluster({ members, highlight, onSelect, onFocus }: BimMarkerClusterProps): React.ReactElement;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=BimMarkerCluster.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BimMarkerCluster.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/shared/markers/BimMarkerCluster.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAK9B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAE5C,UAAU,qBAAqB;IAC7B,OAAO,EAAE,aAAa,EAAE,CAAA;IACxB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;IAC/B,OAAO,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAC/B;AASD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,OAAO,EAAE,SAAiB,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,qBAAqB,GAAG,KAAK,CAAC,YAAY,CAoG7H"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Avatar } from "../../../ui/Avatar";
|
|
5
|
+
import { UserAvatar } from "../../../ui/UserAvatar";
|
|
6
|
+
function clusterColor(count) {
|
|
7
|
+
if (count >= 750) return "#f28cb1";
|
|
8
|
+
if (count >= 100) return "#f1f075";
|
|
9
|
+
return "#51bbd6";
|
|
10
|
+
}
|
|
11
|
+
function BimMarkerCluster({ members, highlight = false, onSelect, onFocus }) {
|
|
12
|
+
const [expanded, setExpanded] = React.useState(false);
|
|
13
|
+
const [fanned, setFanned] = React.useState(false);
|
|
14
|
+
const closeTimer = React.useRef(null);
|
|
15
|
+
const count = members.length;
|
|
16
|
+
const radius = Math.min(64, 26 + count * 4);
|
|
17
|
+
React.useEffect(() => {
|
|
18
|
+
if (!expanded) {
|
|
19
|
+
setFanned(false);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const raf = requestAnimationFrame(() => setFanned(true));
|
|
23
|
+
return () => cancelAnimationFrame(raf);
|
|
24
|
+
}, [expanded]);
|
|
25
|
+
React.useEffect(() => () => {
|
|
26
|
+
if (closeTimer.current) clearTimeout(closeTimer.current);
|
|
27
|
+
}, []);
|
|
28
|
+
const open = () => {
|
|
29
|
+
if (closeTimer.current) {
|
|
30
|
+
clearTimeout(closeTimer.current);
|
|
31
|
+
closeTimer.current = null;
|
|
32
|
+
}
|
|
33
|
+
setExpanded(true);
|
|
34
|
+
};
|
|
35
|
+
const scheduleClose = () => {
|
|
36
|
+
if (closeTimer.current) clearTimeout(closeTimer.current);
|
|
37
|
+
closeTimer.current = setTimeout(() => setExpanded(false), 150);
|
|
38
|
+
};
|
|
39
|
+
return /* @__PURE__ */ jsxs(
|
|
40
|
+
"div",
|
|
41
|
+
{
|
|
42
|
+
className: "relative -translate-x-1/2 -translate-y-1/2 pointer-events-auto",
|
|
43
|
+
onMouseEnter: open,
|
|
44
|
+
onMouseLeave: scheduleClose,
|
|
45
|
+
children: [
|
|
46
|
+
/* @__PURE__ */ jsx(
|
|
47
|
+
"div",
|
|
48
|
+
{
|
|
49
|
+
className: "relative flex items-center justify-center rounded-full text-sm font-medium select-none cursor-pointer",
|
|
50
|
+
style: {
|
|
51
|
+
width: 36,
|
|
52
|
+
height: 36,
|
|
53
|
+
backgroundColor: clusterColor(count),
|
|
54
|
+
color: "#000",
|
|
55
|
+
textShadow: "0 0 2px #fff, 0 0 2px #fff",
|
|
56
|
+
boxShadow: highlight ? "0 0 0 2px #73cee2, 0 0 8px rgba(115, 206, 226, 0.5)" : "0 0 0 1px white"
|
|
57
|
+
},
|
|
58
|
+
children: count
|
|
59
|
+
}
|
|
60
|
+
),
|
|
61
|
+
expanded && /* @__PURE__ */ jsx("div", { className: "absolute left-1/2 top-1/2", children: members.map((member, i) => {
|
|
62
|
+
var _a;
|
|
63
|
+
const angle = 2 * Math.PI * i / count - Math.PI / 2;
|
|
64
|
+
const x = fanned ? Math.cos(angle) * radius : 0;
|
|
65
|
+
const y = fanned ? Math.sin(angle) * radius : 0;
|
|
66
|
+
return /* @__PURE__ */ jsx(
|
|
67
|
+
"div",
|
|
68
|
+
{
|
|
69
|
+
className: "absolute",
|
|
70
|
+
style: {
|
|
71
|
+
transform: `translate(-50%, -50%) translate(${x}px, ${y}px)`,
|
|
72
|
+
opacity: fanned ? 1 : 0,
|
|
73
|
+
transition: "transform 200ms ease, opacity 200ms ease",
|
|
74
|
+
transitionDelay: `${i * 20}ms`
|
|
75
|
+
},
|
|
76
|
+
onMouseEnter: open,
|
|
77
|
+
onPointerDown: (e) => {
|
|
78
|
+
e.stopPropagation();
|
|
79
|
+
onSelect == null ? void 0 : onSelect(member.id);
|
|
80
|
+
onFocus == null ? void 0 : onFocus(member.id);
|
|
81
|
+
},
|
|
82
|
+
children: /* @__PURE__ */ jsx(
|
|
83
|
+
"div",
|
|
84
|
+
{
|
|
85
|
+
className: "h-9 w-9 rounded-full overflow-hidden cursor-pointer bg-card",
|
|
86
|
+
style: { boxShadow: "0 0 0 1px white" },
|
|
87
|
+
children: /* @__PURE__ */ jsx(Avatar, { className: "h-full w-full", children: /* @__PURE__ */ jsx(
|
|
88
|
+
UserAvatar,
|
|
89
|
+
{
|
|
90
|
+
imageFileId: (_a = member.imageFileId) != null ? _a : null,
|
|
91
|
+
name: member.userName,
|
|
92
|
+
className: "h-full w-full rounded-full object-cover"
|
|
93
|
+
}
|
|
94
|
+
) })
|
|
95
|
+
}
|
|
96
|
+
)
|
|
97
|
+
},
|
|
98
|
+
member.id
|
|
99
|
+
);
|
|
100
|
+
}) })
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
export {
|
|
106
|
+
BimMarkerCluster
|
|
107
|
+
};
|
|
108
|
+
//# sourceMappingURL=BimMarkerCluster.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/core/components/viewers/shared/markers/BimMarkerCluster.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\nimport * as React from 'react'\r\n\r\nimport { Avatar } from '../../../ui/Avatar'\r\nimport { UserAvatar } from '../../../ui/UserAvatar'\r\n\r\nimport type { ClusterMember } from './types'\r\n\r\ninterface BimMarkerClusterProps {\r\n members: ClusterMember[]\r\n highlight?: boolean\r\n onSelect?: (id: number) => void\r\n onFocus?: (id: number) => void\r\n}\r\n\r\n/** Cluster bubble colour, matching the map comment cluster palette (mapLayersUtils). */\r\nfunction clusterColor(count: number): string {\r\n if (count >= 750) return '#f28cb1'\r\n if (count >= 100) return '#f1f075'\r\n return '#51bbd6'\r\n}\r\n\r\n/**\r\n * Rendered inside a CSS2DObject at a cluster's world center. Shows a numbered circle for\r\n * overlapping BIM markers; hovering fans the members out (animated) so each can be\r\n * seen and clicked, and collapses back on mouse-out. A short close delay keeps the fan open\r\n * while the pointer crosses the gap between the bubble and a member (same trick the map\r\n * cluster expansion uses), so members stay clickable. Members mount only while expanded, so a\r\n * collapsed cluster is just the bubble — no leftover container behind it.\r\n */\r\nexport function BimMarkerCluster({ members, highlight = false, onSelect, onFocus }: BimMarkerClusterProps): React.ReactElement {\r\n const [expanded, setExpanded] = React.useState(false)\r\n const [fanned, setFanned] = React.useState(false)\r\n const closeTimer = React.useRef<ReturnType<typeof setTimeout> | null>(null)\r\n const count = members.length\r\n const radius = Math.min(64, 26 + count * 4)\r\n\r\n // Animate the fan: members mount at the centre, then move out to their radius on the next frame.\r\n React.useEffect(() => {\r\n if (!expanded) {\r\n setFanned(false)\r\n return\r\n }\r\n const raf = requestAnimationFrame(() => setFanned(true))\r\n return () => cancelAnimationFrame(raf)\r\n }, [expanded])\r\n\r\n React.useEffect(() => () => {\r\n if (closeTimer.current) clearTimeout(closeTimer.current)\r\n }, [])\r\n\r\n const open = () => {\r\n if (closeTimer.current) {\r\n clearTimeout(closeTimer.current)\r\n closeTimer.current = null\r\n }\r\n setExpanded(true)\r\n }\r\n\r\n const scheduleClose = () => {\r\n if (closeTimer.current) clearTimeout(closeTimer.current)\r\n closeTimer.current = setTimeout(() => setExpanded(false), 150)\r\n }\r\n\r\n return (\r\n <div\r\n className=\"relative -translate-x-1/2 -translate-y-1/2 pointer-events-auto\"\r\n onMouseEnter={open}\r\n onMouseLeave={scheduleClose}\r\n >\r\n <div\r\n className=\"relative flex items-center justify-center rounded-full text-sm font-medium select-none cursor-pointer\"\r\n style={{\r\n width: 36,\r\n height: 36,\r\n backgroundColor: clusterColor(count),\r\n color: '#000',\r\n textShadow: '0 0 2px #fff, 0 0 2px #fff',\r\n boxShadow: highlight\r\n ? '0 0 0 2px #73cee2, 0 0 8px rgba(115, 206, 226, 0.5)'\r\n : '0 0 0 1px white',\r\n }}\r\n >\r\n {count}\r\n </div>\r\n\r\n {expanded && (\r\n <div className=\"absolute left-1/2 top-1/2\">\r\n {members.map((member, i) => {\r\n const angle = (2 * Math.PI * i) / count - Math.PI / 2\r\n const x = fanned ? Math.cos(angle) * radius : 0\r\n const y = fanned ? Math.sin(angle) * radius : 0\r\n return (\r\n <div\r\n key={member.id}\r\n className=\"absolute\"\r\n style={{\r\n transform: `translate(-50%, -50%) translate(${x}px, ${y}px)`,\r\n opacity: fanned ? 1 : 0,\r\n transition: 'transform 200ms ease, opacity 200ms ease',\r\n transitionDelay: `${i * 20}ms`,\r\n }}\r\n onMouseEnter={open}\r\n // pointerdown (not click): the CSS2D renderer re-transforms this element every\r\n // frame and it is still animating out, so a browser click frequently never fires.\r\n onPointerDown={(e) => {\r\n e.stopPropagation()\r\n onSelect?.(member.id)\r\n onFocus?.(member.id)\r\n }}\r\n >\r\n <div\r\n className=\"h-9 w-9 rounded-full overflow-hidden cursor-pointer bg-card\"\r\n style={{ boxShadow: '0 0 0 1px white' }}\r\n >\r\n <Avatar className=\"h-full w-full\">\r\n <UserAvatar\r\n imageFileId={member.imageFileId ?? null}\r\n name={member.userName}\r\n className=\"h-full w-full rounded-full object-cover\"\r\n />\r\n </Avatar>\r\n </div>\r\n </div>\r\n )\r\n })}\r\n </div>\r\n )}\r\n </div>\r\n )\r\n}\r\n"],"mappings":";AAqEI,SAKE,KALF;AAhEJ,YAAY,WAAW;AAEvB,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAY3B,SAAS,aAAa,OAAuB;AAC3C,MAAI,SAAS,IAAK,QAAO;AACzB,MAAI,SAAS,IAAK,QAAO;AACzB,SAAO;AACT;AAUO,SAAS,iBAAiB,EAAE,SAAS,YAAY,OAAO,UAAU,QAAQ,GAA8C;AAC7H,QAAM,CAAC,UAAU,WAAW,IAAI,MAAM,SAAS,KAAK;AACpD,QAAM,CAAC,QAAQ,SAAS,IAAI,MAAM,SAAS,KAAK;AAChD,QAAM,aAAa,MAAM,OAA6C,IAAI;AAC1E,QAAM,QAAQ,QAAQ;AACtB,QAAM,SAAS,KAAK,IAAI,IAAI,KAAK,QAAQ,CAAC;AAG1C,QAAM,UAAU,MAAM;AACpB,QAAI,CAAC,UAAU;AACb,gBAAU,KAAK;AACf;AAAA,IACF;AACA,UAAM,MAAM,sBAAsB,MAAM,UAAU,IAAI,CAAC;AACvD,WAAO,MAAM,qBAAqB,GAAG;AAAA,EACvC,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,UAAU,MAAM,MAAM;AAC1B,QAAI,WAAW,QAAS,cAAa,WAAW,OAAO;AAAA,EACzD,GAAG,CAAC,CAAC;AAEL,QAAM,OAAO,MAAM;AACjB,QAAI,WAAW,SAAS;AACtB,mBAAa,WAAW,OAAO;AAC/B,iBAAW,UAAU;AAAA,IACvB;AACA,gBAAY,IAAI;AAAA,EAClB;AAEA,QAAM,gBAAgB,MAAM;AAC1B,QAAI,WAAW,QAAS,cAAa,WAAW,OAAO;AACvD,eAAW,UAAU,WAAW,MAAM,YAAY,KAAK,GAAG,GAAG;AAAA,EAC/D;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,cAAc;AAAA,MACd,cAAc;AAAA,MAEd;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,WAAU;AAAA,YACV,OAAO;AAAA,cACL,OAAO;AAAA,cACP,QAAQ;AAAA,cACR,iBAAiB,aAAa,KAAK;AAAA,cACnC,OAAO;AAAA,cACP,YAAY;AAAA,cACZ,WAAW,YACP,wDACA;AAAA,YACN;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,QAEC,YACC,oBAAC,SAAI,WAAU,6BACZ,kBAAQ,IAAI,CAAC,QAAQ,MAAM;AA5FtC;AA6FY,gBAAM,QAAS,IAAI,KAAK,KAAK,IAAK,QAAQ,KAAK,KAAK;AACpD,gBAAM,IAAI,SAAS,KAAK,IAAI,KAAK,IAAI,SAAS;AAC9C,gBAAM,IAAI,SAAS,KAAK,IAAI,KAAK,IAAI,SAAS;AAC9C,iBACE;AAAA,YAAC;AAAA;AAAA,cAEC,WAAU;AAAA,cACV,OAAO;AAAA,gBACL,WAAW,mCAAmC,CAAC,OAAO,CAAC;AAAA,gBACvD,SAAS,SAAS,IAAI;AAAA,gBACtB,YAAY;AAAA,gBACZ,iBAAiB,GAAG,IAAI,EAAE;AAAA,cAC5B;AAAA,cACA,cAAc;AAAA,cAGd,eAAe,CAAC,MAAM;AACpB,kBAAE,gBAAgB;AAClB,qDAAW,OAAO;AAClB,mDAAU,OAAO;AAAA,cACnB;AAAA,cAEA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,OAAO,EAAE,WAAW,kBAAkB;AAAA,kBAEtC,8BAAC,UAAO,WAAU,iBAChB;AAAA,oBAAC;AAAA;AAAA,sBACC,cAAa,YAAO,gBAAP,YAAsB;AAAA,sBACnC,MAAM,OAAO;AAAA,sBACb,WAAU;AAAA;AAAA,kBACZ,GACF;AAAA;AAAA,cACF;AAAA;AAAA,YA5BK,OAAO;AAAA,UA6Bd;AAAA,QAEJ,CAAC,GACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;","names":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Minimal 3D vector shape so this helper stays free of a three.js import (easy to unit test). */
|
|
2
|
+
export interface Vec3 {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
z: number;
|
|
6
|
+
}
|
|
7
|
+
/** Camera pose in the shape `camera-controls` `setLookAt` expects. */
|
|
8
|
+
export interface LookAt {
|
|
9
|
+
camX: number;
|
|
10
|
+
camY: number;
|
|
11
|
+
camZ: number;
|
|
12
|
+
tarX: number;
|
|
13
|
+
tarY: number;
|
|
14
|
+
tarZ: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Frame a marker without changing the current view direction: keep looking along
|
|
18
|
+
* the same axis the user already has, but re-target the marker and pull the camera
|
|
19
|
+
* to `distance` away from it. Used for double-click "zoom to marker".
|
|
20
|
+
*
|
|
21
|
+
* Pure and three.js-free so it can be unit tested with plain objects.
|
|
22
|
+
*/
|
|
23
|
+
export declare function computeMarkerLookAt(camPos: Vec3, target: Vec3, markerPoint: Vec3, distance?: number): LookAt;
|
|
24
|
+
//# sourceMappingURL=computeMarkerLookAt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"computeMarkerLookAt.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/shared/markers/computeMarkerLookAt.ts"],"names":[],"mappings":"AAGA,kGAAkG;AAClG,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAED,sEAAsE;AACtE,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAID;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,IAAI,EACZ,MAAM,EAAE,IAAI,EACZ,WAAW,EAAE,IAAI,EACjB,QAAQ,SAAI,GACX,MAAM,CAyBR"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const DEFAULT_DIRECTION = { x: 1, y: 1, z: 1 };
|
|
2
|
+
function computeMarkerLookAt(camPos, target, markerPoint, distance = 8) {
|
|
3
|
+
let dx = camPos.x - target.x;
|
|
4
|
+
let dy = camPos.y - target.y;
|
|
5
|
+
let dz = camPos.z - target.z;
|
|
6
|
+
let length = Math.hypot(dx, dy, dz);
|
|
7
|
+
if (length < 1e-6) {
|
|
8
|
+
dx = DEFAULT_DIRECTION.x;
|
|
9
|
+
dy = DEFAULT_DIRECTION.y;
|
|
10
|
+
dz = DEFAULT_DIRECTION.z;
|
|
11
|
+
length = Math.hypot(dx, dy, dz);
|
|
12
|
+
}
|
|
13
|
+
const safeDistance = distance > 0 ? distance : 8;
|
|
14
|
+
const scale = safeDistance / length;
|
|
15
|
+
return {
|
|
16
|
+
camX: markerPoint.x + dx * scale,
|
|
17
|
+
camY: markerPoint.y + dy * scale,
|
|
18
|
+
camZ: markerPoint.z + dz * scale,
|
|
19
|
+
tarX: markerPoint.x,
|
|
20
|
+
tarY: markerPoint.y,
|
|
21
|
+
tarZ: markerPoint.z
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export {
|
|
25
|
+
computeMarkerLookAt
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=computeMarkerLookAt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/core/components/viewers/shared/markers/computeMarkerLookAt.ts"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n/** Minimal 3D vector shape so this helper stays free of a three.js import (easy to unit test). */\r\nexport interface Vec3 {\r\n x: number\r\n y: number\r\n z: number\r\n}\r\n\r\n/** Camera pose in the shape `camera-controls` `setLookAt` expects. */\r\nexport interface LookAt {\r\n camX: number\r\n camY: number\r\n camZ: number\r\n tarX: number\r\n tarY: number\r\n tarZ: number\r\n}\r\n\r\nconst DEFAULT_DIRECTION: Vec3 = { x: 1, y: 1, z: 1 }\r\n\r\n/**\r\n * Frame a marker without changing the current view direction: keep looking along\r\n * the same axis the user already has, but re-target the marker and pull the camera\r\n * to `distance` away from it. Used for double-click \"zoom to marker\".\r\n *\r\n * Pure and three.js-free so it can be unit tested with plain objects.\r\n */\r\nexport function computeMarkerLookAt(\r\n camPos: Vec3,\r\n target: Vec3,\r\n markerPoint: Vec3,\r\n distance = 8,\r\n): LookAt {\r\n let dx = camPos.x - target.x\r\n let dy = camPos.y - target.y\r\n let dz = camPos.z - target.z\r\n let length = Math.hypot(dx, dy, dz)\r\n\r\n // Degenerate pose (camera sitting on its target): fall back to a sensible angle.\r\n if (length < 1e-6) {\r\n dx = DEFAULT_DIRECTION.x\r\n dy = DEFAULT_DIRECTION.y\r\n dz = DEFAULT_DIRECTION.z\r\n length = Math.hypot(dx, dy, dz)\r\n }\r\n\r\n const safeDistance = distance > 0 ? distance : 8\r\n const scale = safeDistance / length\r\n\r\n return {\r\n camX: markerPoint.x + dx * scale,\r\n camY: markerPoint.y + dy * scale,\r\n camZ: markerPoint.z + dz * scale,\r\n tarX: markerPoint.x,\r\n tarY: markerPoint.y,\r\n tarZ: markerPoint.z,\r\n }\r\n}\r\n"],"mappings":"AAoBA,MAAM,oBAA0B,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAS5C,SAAS,oBACd,QACA,QACA,aACA,WAAW,GACH;AACR,MAAI,KAAK,OAAO,IAAI,OAAO;AAC3B,MAAI,KAAK,OAAO,IAAI,OAAO;AAC3B,MAAI,KAAK,OAAO,IAAI,OAAO;AAC3B,MAAI,SAAS,KAAK,MAAM,IAAI,IAAI,EAAE;AAGlC,MAAI,SAAS,MAAM;AACjB,SAAK,kBAAkB;AACvB,SAAK,kBAAkB;AACvB,SAAK,kBAAkB;AACvB,aAAS,KAAK,MAAM,IAAI,IAAI,EAAE;AAAA,EAChC;AAEA,QAAM,eAAe,WAAW,IAAI,WAAW;AAC/C,QAAM,QAAQ,eAAe;AAE7B,SAAO;AAAA,IACL,MAAM,YAAY,IAAI,KAAK;AAAA,IAC3B,MAAM,YAAY,IAAI,KAAK;AAAA,IAC3B,MAAM,YAAY,IAAI,KAAK;AAAA,IAC3B,MAAM,YAAY;AAAA,IAClB,MAAM,YAAY;AAAA,IAClB,MAAM,YAAY;AAAA,EACpB;AACF;","names":[]}
|