@collabdt/core 0.0.56 → 0.0.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/components/AppSidebarContent.d.ts +2 -1
- package/dist/core/components/AppSidebarContent.d.ts.map +1 -1
- package/dist/core/components/AppSidebarContent.js +10 -7
- package/dist/core/components/AppSidebarContent.js.map +1 -1
- package/dist/core/components/Toolbar.d.ts +7 -1
- package/dist/core/components/Toolbar.d.ts.map +1 -1
- package/dist/core/components/Toolbar.js +3 -3
- package/dist/core/components/Toolbar.js.map +1 -1
- package/dist/core/components/TopNavigationBar.d.ts +6 -1
- package/dist/core/components/TopNavigationBar.d.ts.map +1 -1
- package/dist/core/components/TopNavigationBar.js +2 -2
- package/dist/core/components/TopNavigationBar.js.map +1 -1
- package/dist/core/components/authentication/AuthPage.d.ts +2 -1
- package/dist/core/components/authentication/AuthPage.d.ts.map +1 -1
- package/dist/core/components/authentication/AuthPage.js +3 -5
- package/dist/core/components/authentication/AuthPage.js.map +1 -1
- package/dist/core/components/authentication/Signin.d.ts +2 -1
- package/dist/core/components/authentication/Signin.d.ts.map +1 -1
- package/dist/core/components/authentication/Signin.js +2 -2
- package/dist/core/components/authentication/Signin.js.map +1 -1
- package/dist/core/components/organizationConfig/src/organizationConfigContent.d.ts.map +1 -1
- package/dist/core/components/organizationConfig/src/organizationConfigContent.js +109 -36
- package/dist/core/components/organizationConfig/src/organizationConfigContent.js.map +1 -1
- package/dist/core/components/settings/index.d.ts +3 -1
- package/dist/core/components/settings/index.d.ts.map +1 -1
- package/dist/core/components/settings/index.js +2 -2
- package/dist/core/components/settings/index.js.map +1 -1
- package/dist/core/components/settings/src/AccountSettingsPanel.d.ts.map +1 -1
- package/dist/core/components/settings/src/AccountSettingsPanel.js +9 -2
- package/dist/core/components/settings/src/AccountSettingsPanel.js.map +1 -1
- package/dist/core/components/settings/src/OrganizationSettingsPanel.d.ts +5 -1
- package/dist/core/components/settings/src/OrganizationSettingsPanel.d.ts.map +1 -1
- package/dist/core/components/settings/src/OrganizationSettingsPanel.js +7 -5
- package/dist/core/components/settings/src/OrganizationSettingsPanel.js.map +1 -1
- package/dist/core/components/settings/src/SettingsContent.d.ts +2 -1
- package/dist/core/components/settings/src/SettingsContent.d.ts.map +1 -1
- package/dist/core/components/settings/src/SettingsContent.js +2 -2
- package/dist/core/components/settings/src/SettingsContent.js.map +1 -1
- package/dist/core/components/support/BugReportDialog.d.ts +3 -2
- package/dist/core/components/support/BugReportDialog.d.ts.map +1 -1
- package/dist/core/components/support/BugReportDialog.js +71 -25
- package/dist/core/components/support/BugReportDialog.js.map +1 -1
- package/dist/core/components/support/FeatureRequestDialog.d.ts +3 -1
- package/dist/core/components/support/FeatureRequestDialog.d.ts.map +1 -1
- package/dist/core/components/support/FeatureRequestDialog.js +7 -4
- package/dist/core/components/support/FeatureRequestDialog.js.map +1 -1
- package/dist/core/components/support/SupportMenu.d.ts.map +1 -1
- package/dist/core/components/support/SupportMenu.js +1 -4
- package/dist/core/components/support/SupportMenu.js.map +1 -1
- package/dist/core/components/ui/AnimatedBackground.d.ts +2 -1
- package/dist/core/components/ui/AnimatedBackground.d.ts.map +1 -1
- package/dist/core/components/ui/AnimatedBackground.js +2 -5
- package/dist/core/components/ui/AnimatedBackground.js.map +1 -1
- package/dist/core/components/ui/InfoSidebar/Container.d.ts +3 -1
- package/dist/core/components/ui/InfoSidebar/Container.d.ts.map +1 -1
- package/dist/core/components/ui/InfoSidebar/Container.js +4 -2
- package/dist/core/components/ui/InfoSidebar/Container.js.map +1 -1
- package/dist/core/components/ui/InfoSidebar/Header.d.ts +3 -2
- package/dist/core/components/ui/InfoSidebar/Header.d.ts.map +1 -1
- package/dist/core/components/ui/InfoSidebar/Header.js +5 -6
- package/dist/core/components/ui/InfoSidebar/Header.js.map +1 -1
- package/dist/core/components/ui/InfoSidebar/index.d.ts +7 -1
- package/dist/core/components/ui/InfoSidebar/index.d.ts.map +1 -1
- package/dist/core/components/ui/InfoSidebar/index.js +4 -4
- package/dist/core/components/ui/InfoSidebar/index.js.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts +2 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js +3 -4
- package/dist/core/components/ui/Sensors/CollapsibleSensorItem.js.map +1 -1
- package/dist/core/components/ui/Sensors/SensorsSection.d.ts +3 -1
- package/dist/core/components/ui/Sensors/SensorsSection.d.ts.map +1 -1
- package/dist/core/components/ui/Sensors/SensorsSection.js +3 -1
- package/dist/core/components/ui/Sensors/SensorsSection.js.map +1 -1
- package/dist/core/components/ui/Sidebar.d.ts +8 -0
- package/dist/core/components/ui/Sidebar.d.ts.map +1 -1
- package/dist/core/components/ui/Sidebar.js +21 -7
- package/dist/core/components/ui/Sidebar.js.map +1 -1
- package/dist/core/components/ui/ToolbarButton.js +18 -1
- package/dist/core/components/ui/ToolbarButton.js.map +1 -1
- package/dist/core/components/viewers/Data/DataMenu.d.ts +5 -1
- package/dist/core/components/viewers/Data/DataMenu.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/DataMenu.js +6 -3
- package/dist/core/components/viewers/Data/DataMenu.js.map +1 -1
- package/dist/core/components/viewers/Data/HeaderButtons.d.ts +3 -1
- package/dist/core/components/viewers/Data/HeaderButtons.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/HeaderButtons.js +6 -2
- package/dist/core/components/viewers/Data/HeaderButtons.js.map +1 -1
- package/dist/core/components/viewers/Data/buildingDetails/AddBuilding.d.ts +3 -1
- package/dist/core/components/viewers/Data/buildingDetails/AddBuilding.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/buildingDetails/AddBuilding.js +4 -2
- package/dist/core/components/viewers/Data/buildingDetails/AddBuilding.js.map +1 -1
- package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.d.ts +3 -1
- package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js +3 -1
- package/dist/core/components/viewers/Data/buildingDetails/GeocoderInput.js.map +1 -1
- package/dist/core/components/viewers/Data/details/DetailHeader.d.ts +2 -1
- package/dist/core/components/viewers/Data/details/DetailHeader.d.ts.map +1 -1
- package/dist/core/components/viewers/Data/details/DetailHeader.js +3 -5
- package/dist/core/components/viewers/Data/details/DetailHeader.js.map +1 -1
- package/dist/core/components/viewers/Viewer.d.ts +7 -1
- package/dist/core/components/viewers/Viewer.d.ts.map +1 -1
- package/dist/core/components/viewers/Viewer.js +6 -6
- package/dist/core/components/viewers/Viewer.js.map +1 -1
- package/dist/core/components/viewers/bim/BimToolbar.d.ts +3 -1
- package/dist/core/components/viewers/bim/BimToolbar.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/BimToolbar.js +2 -2
- package/dist/core/components/viewers/bim/BimToolbar.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.d.ts +3 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.js +2 -2
- package/dist/core/components/viewers/bim/src/BimSidebar/src/SensorsTab/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/index.d.ts +5 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/index.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/BimSidebar/src/index.js +3 -2
- package/dist/core/components/viewers/bim/src/BimSidebar/src/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts +3 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js +2 -2
- package/dist/core/components/viewers/bim/src/tools/AddToBim/index.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.d.ts +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.js +3 -5
- package/dist/core/components/viewers/bim/src/tools/AddToBim/src/useSensorMarkers.js.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/bimToolbar.d.ts +3 -1
- package/dist/core/components/viewers/bim/src/tools/bimToolbar.d.ts.map +1 -1
- package/dist/core/components/viewers/bim/src/tools/bimToolbar.js +4 -2
- package/dist/core/components/viewers/bim/src/tools/bimToolbar.js.map +1 -1
- package/dist/core/components/viewers/map/MapViewer.d.ts +3 -1
- package/dist/core/components/viewers/map/MapViewer.d.ts.map +1 -1
- package/dist/core/components/viewers/map/MapViewer.js +2 -2
- package/dist/core/components/viewers/map/MapViewer.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/RowActions.d.ts +2 -1
- package/dist/core/components/viewers/map/datasets/RowActions.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/RowActions.js +5 -6
- package/dist/core/components/viewers/map/datasets/RowActions.js.map +1 -1
- package/dist/core/components/viewers/map/datasets/index.d.ts +5 -1
- package/dist/core/components/viewers/map/datasets/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/datasets/index.js +15 -16
- package/dist/core/components/viewers/map/datasets/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/Geocoder.d.ts +3 -1
- package/dist/core/components/viewers/map/src/Geocoder.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/Geocoder.js +5 -1
- package/dist/core/components/viewers/map/src/Geocoder.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.d.ts +6 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/index.js +3 -3
- package/dist/core/components/viewers/map/src/MapLayers/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.d.ts +5 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js +6 -10
- package/dist/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.d.ts +3 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.js +4 -6
- package/dist/core/components/viewers/map/src/MapLayers/src/SensorsLayer/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/index.d.ts +6 -1
- package/dist/core/components/viewers/map/src/MapSidebar/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/index.js +5 -4
- package/dist/core/components/viewers/map/src/MapSidebar/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.d.ts +5 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.js +5 -8
- package/dist/core/components/viewers/map/src/MapSidebar/src/LayersTab/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.d.ts +3 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.js +2 -2
- package/dist/core/components/viewers/map/src/MapSidebar/src/SensorsTab/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/index.d.ts +3 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/index.js +2 -2
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/index.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/LocationSettings.d.ts +3 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/LocationSettings.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/LocationSettings.js +4 -7
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/LocationSettings.js.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js +8 -8
- package/dist/core/components/viewers/map/src/MapSidebar/src/SettingsTab/src/TerrainLevel.js.map +1 -1
- package/dist/core/components/viewers/map/src/tools/AddTools/AddToMap.d.ts +8 -1
- package/dist/core/components/viewers/map/src/tools/AddTools/AddToMap.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/tools/AddTools/AddToMap.js +8 -3
- package/dist/core/components/viewers/map/src/tools/AddTools/AddToMap.js.map +1 -1
- package/dist/core/components/viewers/map/src/tools/DatasetMapTool.d.ts +11 -1
- package/dist/core/components/viewers/map/src/tools/DatasetMapTool.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/tools/DatasetMapTool.js +5 -3
- package/dist/core/components/viewers/map/src/tools/DatasetMapTool.js.map +1 -1
- package/dist/core/components/viewers/map/src/tools/mapTools.d.ts +10 -1
- package/dist/core/components/viewers/map/src/tools/mapTools.d.ts.map +1 -1
- package/dist/core/components/viewers/map/src/tools/mapTools.js +5 -3
- package/dist/core/components/viewers/map/src/tools/mapTools.js.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/config.d.ts +14 -5
- package/dist/core/components/viewers/map/utils/geocoding/config.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/config.js +22 -11
- package/dist/core/components/viewers/map/utils/geocoding/config.js.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/index.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/index.js +2 -2
- package/dist/core/components/viewers/map/utils/geocoding/index.js.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/osm.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/osm.js +5 -4
- package/dist/core/components/viewers/map/utils/geocoding/osm.js.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/pelias.d.ts.map +1 -1
- package/dist/core/components/viewers/map/utils/geocoding/pelias.js +7 -5
- package/dist/core/components/viewers/map/utils/geocoding/pelias.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/PointCloudViewer.d.ts +3 -1
- package/dist/core/components/viewers/pointcloud/PointCloudViewer.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/PointCloudViewer.js +11 -14
- package/dist/core/components/viewers/pointcloud/PointCloudViewer.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.d.ts +3 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.js +37 -52
- package/dist/core/components/viewers/pointcloud/src/PointCloudLoadingState/index.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.d.ts +3 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.js +5 -3
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudManagementTable.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.d.ts +2 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.js +5 -6
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudTable.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.d.ts +2 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.js +15 -9
- package/dist/core/components/viewers/pointcloud/src/PointCloudManagement/PointCloudUploadPanel.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/index.d.ts +5 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/index.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/index.js +3 -2
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/index.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.d.ts +3 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js +2 -2
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/index.js.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.d.ts +2 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.d.ts.map +1 -1
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.js +12 -23
- package/dist/core/components/viewers/pointcloud/src/PointCloudSidebar/src/FileTab/src/PointCloudSection.js.map +1 -1
- package/dist/core/hooks/useCaptureScreenshot.d.ts +2 -0
- package/dist/core/hooks/useCaptureScreenshot.d.ts.map +1 -0
- package/dist/core/hooks/useCaptureScreenshot.js +63 -0
- package/dist/core/hooks/useCaptureScreenshot.js.map +1 -0
- package/dist/core/hooks/useGeocodingRuntimeConfig.d.ts +3 -0
- package/dist/core/hooks/useGeocodingRuntimeConfig.d.ts.map +1 -0
- package/dist/core/hooks/useGeocodingRuntimeConfig.js +17 -0
- package/dist/core/hooks/useGeocodingRuntimeConfig.js.map +1 -0
- package/dist/core/store/AppConfig/context.d.ts +5 -0
- package/dist/core/store/AppConfig/context.d.ts.map +1 -1
- package/dist/core/store/AppConfig/context.js.map +1 -1
- package/dist/core/store/CombineProviders.d.ts +6 -1
- package/dist/core/store/CombineProviders.d.ts.map +1 -1
- package/dist/core/store/CombineProviders.js +4 -3
- package/dist/core/store/CombineProviders.js.map +1 -1
- package/dist/core/types/tools.d.ts +2 -1
- package/dist/core/types/tools.d.ts.map +1 -1
- package/dist/core/utils/imageUtils.d.ts.map +1 -1
- package/dist/core/utils/imageUtils.js +2 -1
- package/dist/core/utils/imageUtils.js.map +1 -1
- package/package.json +1 -1
|
@@ -26,7 +26,6 @@ import { usePermissions } from "../../../../store";
|
|
|
26
26
|
import { usePathname } from "next/navigation";
|
|
27
27
|
import { useOpenDataPortalsByCountrySubdivision, useOpenDataPortalsByGroup, useOpenDataPortalsByMunicipality } from "../../../../hooks/openDataPortals/openDataPortals";
|
|
28
28
|
import { DatasetsContext, MenusContext, useMapContext } from "../../../../store";
|
|
29
|
-
import { useAppConfigContext } from "../../../../store/AppConfig/context";
|
|
30
29
|
import { Badge } from "../../../../components/ui/Badge";
|
|
31
30
|
import {
|
|
32
31
|
Breadcrumb,
|
|
@@ -102,18 +101,17 @@ function datasetVisibleForOrg(dataset, visibility) {
|
|
|
102
101
|
if (orgId === void 0) return false;
|
|
103
102
|
return visibility.allowedOrgIds.includes(orgId);
|
|
104
103
|
}
|
|
105
|
-
function Datasets({ isOpen, setIsOpenAction }) {
|
|
106
|
-
var _a, _b, _c, _d
|
|
104
|
+
function Datasets({ isOpen, setIsOpenAction, organization, minioBaseUrl, martinBaseUrl }) {
|
|
105
|
+
var _a, _b, _c, _d;
|
|
107
106
|
const t = useTranslations("Datasets");
|
|
108
107
|
const { ability } = usePermissions();
|
|
109
108
|
const datasetColumns = useColumns();
|
|
110
109
|
const { state: mapState } = useMapContext();
|
|
111
110
|
const { currentLocation } = mapState.map;
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
const
|
|
115
|
-
const
|
|
116
|
-
const countrySubdivision = (_e = (_d = currentLocation == null ? void 0 : currentLocation.countrySubdivision) != null ? _d : org == null ? void 0 : org.countrySubdivision) != null ? _e : null;
|
|
111
|
+
const orgCountry = ((organization == null ? void 0 : organization.country) || "").toUpperCase();
|
|
112
|
+
const org = organization;
|
|
113
|
+
const municipality = (_b = (_a = currentLocation == null ? void 0 : currentLocation.municipality) != null ? _a : org == null ? void 0 : org.municipality) != null ? _b : null;
|
|
114
|
+
const countrySubdivision = (_d = (_c = currentLocation == null ? void 0 : currentLocation.countrySubdivision) != null ? _c : org == null ? void 0 : org.countrySubdivision) != null ? _d : null;
|
|
117
115
|
const { state: datasetState, dispatch: datasetDispatch } = React.useContext(DatasetsContext);
|
|
118
116
|
const { addedDatasets } = datasetState.datasets;
|
|
119
117
|
const { state: menusState } = React.useContext(MenusContext);
|
|
@@ -159,7 +157,7 @@ function Datasets({ isOpen, setIsOpenAction }) {
|
|
|
159
157
|
const national = useDatasetsForPortals(filteredNationalPortals, { rowsPerPage });
|
|
160
158
|
React.useEffect(() => {
|
|
161
159
|
const loadOrganizationalDatasets = async () => {
|
|
162
|
-
var _a2
|
|
160
|
+
var _a2;
|
|
163
161
|
try {
|
|
164
162
|
const filesRes = await fetch("/api/files");
|
|
165
163
|
if (filesRes.ok) {
|
|
@@ -170,9 +168,9 @@ function Datasets({ isOpen, setIsOpenAction }) {
|
|
|
170
168
|
} catch (err) {
|
|
171
169
|
console.warn("Failed to refresh published-catalog map:", err);
|
|
172
170
|
}
|
|
173
|
-
const
|
|
174
|
-
const martinPromise =
|
|
175
|
-
const datasetsUrl =
|
|
171
|
+
const martinBaseUrlClean = (martinBaseUrl != null ? martinBaseUrl : "").replace(/\/+$/, "");
|
|
172
|
+
const martinPromise = martinBaseUrlClean ? (async () => {
|
|
173
|
+
const datasetsUrl = martinBaseUrlClean.includes("/tiles/index.json") ? martinBaseUrlClean : `${martinBaseUrlClean}/tiles/index.json`;
|
|
176
174
|
const localPortal = {
|
|
177
175
|
id: -1,
|
|
178
176
|
name: "Organizational Datasets",
|
|
@@ -189,15 +187,15 @@ function Datasets({ isOpen, setIsOpenAction }) {
|
|
|
189
187
|
return [];
|
|
190
188
|
}
|
|
191
189
|
})() : Promise.resolve([]);
|
|
192
|
-
if (!
|
|
190
|
+
if (!martinBaseUrlClean) {
|
|
193
191
|
console.warn("NEXT_PUBLIC_MARTIN_SERVER_URL not configured \u2014 skipping Martin pre-load");
|
|
194
192
|
}
|
|
195
|
-
const sessionOrgId = typeof (org == null ? void 0 : org.id) === "number" ? org.id : Number.parseInt(String((
|
|
193
|
+
const sessionOrgId = typeof (org == null ? void 0 : org.id) === "number" ? org.id : Number.parseInt(String((_a2 = org == null ? void 0 : org.id) != null ? _a2 : ""), 10);
|
|
196
194
|
const martinDatasets = await martinPromise;
|
|
197
195
|
const publishedTilesInCatalog = new Set(
|
|
198
196
|
martinDatasets.map((d) => typeof d.id === "string" ? d.id : "").filter(Boolean)
|
|
199
197
|
);
|
|
200
|
-
const minioDatasets = Number.isFinite(sessionOrgId) ? await fetchOrganizationalMinioDatasets(sessionOrgId, publishedTilesInCatalog,
|
|
198
|
+
const minioDatasets = Number.isFinite(sessionOrgId) ? await fetchOrganizationalMinioDatasets(sessionOrgId, publishedTilesInCatalog, minioBaseUrl).catch((err) => {
|
|
201
199
|
console.error("Failed to load MinIO organizational datasets:", err);
|
|
202
200
|
return [];
|
|
203
201
|
}) : [];
|
|
@@ -460,7 +458,8 @@ function Datasets({ isOpen, setIsOpenAction }) {
|
|
|
460
458
|
RowActions,
|
|
461
459
|
__spreadProps(__spreadValues({}, props), {
|
|
462
460
|
favouriteDatasets,
|
|
463
|
-
setFavouriteDatasets
|
|
461
|
+
setFavouriteDatasets,
|
|
462
|
+
martinBaseUrl
|
|
464
463
|
})
|
|
465
464
|
),
|
|
466
465
|
trailingCell: ({ row, index }) => /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../src/core/components/viewers/map/datasets/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\n// Icons\r\nimport * as LR from 'lucide-react'\r\n// Dependencies\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\nimport { usePermissions } from '../../../../store'\r\nimport { usePathname } from 'next/navigation'\r\n\r\nimport type { Dataset } from '../../../../types/datasetTypes'\r\nimport { useOpenDataPortalsByCountrySubdivision, useOpenDataPortalsByGroup, useOpenDataPortalsByMunicipality } from '../../../../hooks/openDataPortals/openDataPortals'\r\nimport { DatasetsContext, MenusContext, useMapContext } from '../../../../store'\r\nimport { useAppConfigContext } from '../../../../store/AppConfig/context'\r\nimport { Badge } from '../../../../components/ui/Badge'\r\nimport {\r\n Breadcrumb,\r\n BreadcrumbItem,\r\n BreadcrumbLink,\r\n BreadcrumbList,\r\n BreadcrumbPage,\r\n BreadcrumbSeparator,\r\n} from '../../../../components/ui/Breadcrumb'\r\nimport { Button } from '../../../../components/ui/Button'\r\nimport { DataTable } from '../../../../components/ui/DataTable'\r\nimport {\r\n Dialog,\r\n DialogClose,\r\n DialogContent,\r\n DialogDescription,\r\n DialogHeader,\r\n DialogTitle,\r\n} from '../../../../components/ui/Dialog'\r\nimport { Input } from '../../../../components/ui/Input'\r\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '../../../../components/ui/Tabs'\r\n// Data\r\nimport { useColumns } from './data'\r\nimport DatasetDetails from './DatasetDetails'\r\n// Custom components\r\nimport { AddPortalDialog } from './AddPortalDialog'\r\nimport DatasetSkeleton from './DatasetSkeleton'\r\nimport Filters from './Filters'\r\nimport RowActions from './RowActions'\r\nimport { useDatasetsForPortals } from './src/useDatasetsForPortals'\r\nimport { handleFavouriteDataset } from './utils'\r\nimport { fetchLocalDatasets } from './src/localDatasets'\r\nimport { fetchOrganizationalMinioDatasets } from './src/minioDatasets'\r\nimport { buildPublishedCatalogMap, stampPublished, type PublishedCatalogEntry } from './src/publishedTiles'\r\nimport { builtinLiveDatasets } from './src/builtinLiveDatasets'\r\nimport { useFastDatasetCache } from './src/useFastDatasetCache'\r\nimport { DatasetGroup } from '../../../../types/dbTypes'\r\n\r\ntype OrgVisibility = {\r\n isAdmin: boolean\r\n currentOrgId: number\r\n allowedOrgIds: number[]\r\n}\r\n\r\nconst ADMIN_ALLOWED_ORGS = [1, 2, 3, 4, 5, 6]\r\nconst ORG_BY_PATH_PREFIX: Record<string, number> = {\r\n '/envirocentre': 1,\r\n '/dnd': 3,\r\n '/canada': 4,\r\n '/gac': 5,\r\n '/carleton': 6,\r\n}\r\n\r\nfunction normalizeOrgId(org?: number | string | null) {\r\n if (org === null || org === undefined) return undefined\r\n const parsed = typeof org === 'number' ? org : Number.parseInt(String(org), 10)\r\n return Number.isFinite(parsed) ? parsed : undefined\r\n}\r\n\r\nfunction getOrgVisibilityFromPath(pathname?: string | null): OrgVisibility {\r\n const normalizedPath = (pathname || '').toLowerCase()\r\n const firstSegment = normalizedPath.split('/').filter(Boolean)[0]\r\n const prefix = firstSegment ? `/${firstSegment}` : ''\r\n\r\n if (prefix === '/cdt') {\r\n return {\r\n isAdmin: true,\r\n currentOrgId: 1,\r\n allowedOrgIds: ADMIN_ALLOWED_ORGS,\r\n }\r\n }\r\n\r\n const currentOrgId = ORG_BY_PATH_PREFIX[prefix] ?? 2\r\n const allowedOrgIds = Array.from(new Set([2, currentOrgId]))\r\n\r\n return {\r\n isAdmin: false,\r\n currentOrgId,\r\n allowedOrgIds,\r\n }\r\n}\r\n\r\nfunction datasetVisibleForOrg(dataset: Dataset, visibility: OrgVisibility) {\r\n if (visibility.isAdmin) return true\r\n if (dataset.group !== DatasetGroup.Organizational) return true\r\n\r\n const orgId = normalizeOrgId(dataset.organization)\r\n if (orgId === undefined) return false\r\n\r\n return visibility.allowedOrgIds.includes(orgId)\r\n}\r\n\r\n\r\ntype DatasetsProps = {\r\n isOpen: boolean\r\n setIsOpenAction: (open: boolean) => void\r\n}\r\n\r\nexport default function Datasets({ isOpen, setIsOpenAction }: DatasetsProps) {\r\n // Translation\r\n const t = useTranslations('Datasets')\r\n\r\n // Permissions\r\n const { ability } = usePermissions()\r\n\r\n const datasetColumns = useColumns()\r\n\r\n // Contexts\r\n const { state: mapState } = useMapContext()\r\n const { currentLocation } = mapState.map\r\n const { state: appConfigState } = useAppConfigContext()\r\n const orgCountry = (appConfigState.appConfig.organization?.country || '').toUpperCase()\r\n const org = appConfigState.appConfig.organization\r\n // Fall back to org fixed location when currentLocation hasn't been set yet (e.g. before map hover)\r\n const municipality = currentLocation?.municipality ?? org?.municipality ?? null\r\n const countrySubdivision = currentLocation?.countrySubdivision ?? org?.countrySubdivision ?? null\r\n const { state: datasetState, dispatch: datasetDispatch } = React.useContext(DatasetsContext)\r\n const { addedDatasets } = datasetState.datasets\r\n const { state: menusState } = React.useContext(MenusContext)\r\n const { rowsPerPage } = menusState.menus\r\n\r\n const pathname = usePathname()\r\n const orgVisibility = React.useMemo(() => getOrgVisibilityFromPath(pathname), [pathname])\r\n\r\n // UI State\r\n const [view, setView] = React.useState<'table' | 'detail'>('table')\r\n const [selectedDataset, setSelectedDataset] = React.useState<Dataset | null>(null)\r\n const [favouriteDatasets, setFavouriteDatasets] = React.useState<Dataset[]>([])\r\n const [searchTerm, setSearchTerm] = React.useState('')\r\n const [appliedFilters, setAppliedFilters] = React.useState<{ countrySubdivisions: string[], municipalities: string[], types: string[], sources: string[] }>({ countrySubdivisions: [], municipalities: [], types: [], sources: [] })\r\n const [currentTab, setCurrentTab] = React.useState('all')\r\n const [isAddPortalOpen, setIsAddPortalOpen] = React.useState(false)\r\n // Open-data datasets already published to Martin tiles, keyed by\r\n // \"{portalId}:{datasetId}\". Lets the original portal entry (National/Applied/\r\n // All tabs) show as converted, not just the organizational-list copy.\r\n const [publishedCatalog, setPublishedCatalog] = React.useState<Map<string, PublishedCatalogEntry>>(new Map())\r\n const showMunicipalTab = React.useMemo(() => Boolean(municipality), [municipality])\r\n\r\n const { openDataPortals: municipalPortals } = useOpenDataPortalsByMunicipality(municipality)\r\n const { openDataPortals: subdivisionPortals } = useOpenDataPortalsByCountrySubdivision(countrySubdivision)\r\n const { openDataPortals: nationalPortals } = useOpenDataPortalsByGroup(DatasetGroup.National)\r\n\r\n // Belt-and-suspenders country guard: portal.country must match org, or be unset (legacy/global)\r\n const matchesOrgCountry = React.useCallback(\r\n (portalCountry: string | null | undefined) => {\r\n if (!orgCountry) return true // org country unknown — show everything\r\n if (!portalCountry) return true // portal has no country set — treat as global\r\n return portalCountry.toUpperCase() === orgCountry\r\n },\r\n [orgCountry],\r\n )\r\n\r\n const filteredMunicipalPortals = React.useMemo(() => {\r\n if (!Array.isArray(municipalPortals)) return []\r\n const filtered = municipalPortals.filter(p => matchesOrgCountry(p.country))\r\n return filtered\r\n }, [municipalPortals, matchesOrgCountry, municipality])\r\n const filteredSubdivisionPortals = React.useMemo(\r\n () => (Array.isArray(subdivisionPortals)\r\n ? subdivisionPortals.filter(p => p.municipality == null && matchesOrgCountry(p.country))\r\n : []),\r\n [subdivisionPortals, matchesOrgCountry],\r\n )\r\n const filteredNationalPortals = React.useMemo(() => {\r\n if (!Array.isArray(nationalPortals)) return []\r\n const filtered = nationalPortals.filter(p => matchesOrgCountry(p.country))\r\n return filtered\r\n }, [nationalPortals, orgCountry, matchesOrgCountry])\r\n\r\n const municipal = useDatasetsForPortals(filteredMunicipalPortals, { rowsPerPage })\r\n const subdivision = useDatasetsForPortals(filteredSubdivisionPortals, { rowsPerPage })\r\n const national = useDatasetsForPortals(filteredNationalPortals, { rowsPerPage })\r\n React.useEffect(() => {\r\n const loadOrganizationalDatasets = async () => {\r\n // First, refresh the published-catalog lookup (a fast /api/files read) so\r\n // converted open-data datasets flip promptly across every tab — ahead of\r\n // the slower Martin tile-sampling below. Non-fatal on failure.\r\n try {\r\n const filesRes = await fetch('/api/files')\r\n if (filesRes.ok) {\r\n const body = await filesRes.json()\r\n const rows = Array.isArray(body?.files) ? body.files : []\r\n setPublishedCatalog(buildPublishedCatalogMap(rows))\r\n }\r\n }\r\n catch (err) {\r\n console.warn('Failed to refresh published-catalog map:', err)\r\n }\r\n\r\n // Two parallel sources: Martin vector tiles (if configured) and MinIO-\r\n // backed GeoJSON uploads (the \"Add Dataset\" path). Errors from either\r\n // are isolated so a failure on one side does not block the other.\r\n const martinBaseUrl = appConfigState.runtimeConfig.martinUrl?.replace(/\\/+$/, '')\r\n\r\n const martinPromise: Promise<Dataset[]> = martinBaseUrl\r\n ? (async () => {\r\n const datasetsUrl = martinBaseUrl.includes('/tiles/index.json')\r\n ? martinBaseUrl\r\n : `${martinBaseUrl}/tiles/index.json`\r\n\r\n const localPortal = {\r\n id: -1,\r\n name: 'Organizational Datasets',\r\n apiUrl: datasetsUrl,\r\n dataManagementSystem: 'Other' as const,\r\n countrySubdivision: null,\r\n municipality: null,\r\n group: 'Organizational' as const,\r\n }\r\n\r\n try {\r\n return await fetchLocalDatasets(localPortal as any)\r\n }\r\n catch (err) {\r\n console.error('Failed to load Martin organizational datasets:', err)\r\n return []\r\n }\r\n })()\r\n : Promise.resolve([])\r\n\r\n if (!martinBaseUrl) {\r\n console.warn('NEXT_PUBLIC_MARTIN_SERVER_URL not configured — skipping Martin pre-load')\r\n }\r\n\r\n // The MinIO key prefix is the *session* organization (set server-side\r\n // by the upload route), not orgVisibility.currentOrgId (which is\r\n // path-derived and hardcoded for admin routes like /cdt).\r\n const sessionOrgId = typeof org?.id === 'number'\r\n ? org.id\r\n : Number.parseInt(String(org?.id ?? ''), 10)\r\n\r\n // Martin must resolve first so MinIO suppression can check live catalog\r\n // membership — prevents \"file disappeared\" during the publish→restart gap.\r\n const martinDatasets = await martinPromise\r\n const publishedTilesInCatalog = new Set<string>(\r\n martinDatasets.map(d => typeof d.id === 'string' ? d.id : '').filter(Boolean),\r\n )\r\n\r\n const minioDatasets: Dataset[] = Number.isFinite(sessionOrgId)\r\n ? await fetchOrganizationalMinioDatasets(sessionOrgId, publishedTilesInCatalog, appConfigState.runtimeConfig.minioUrl).catch((err) => {\r\n console.error('Failed to load MinIO organizational datasets:', err)\r\n return []\r\n })\r\n : []\r\n\r\n const combined = [...martinDatasets, ...minioDatasets]\r\n const visibleOrgDatasets = combined.filter(ds => datasetVisibleForOrg(ds, orgVisibility))\r\n\r\n if (visibleOrgDatasets.length === 0) {\r\n console.warn('No organizational datasets found')\r\n }\r\n datasetDispatch({\r\n type: 'SET_DATASETS',\r\n payload: { datasets: visibleOrgDatasets },\r\n })\r\n }\r\n\r\n loadOrganizationalDatasets()\r\n }, [datasetDispatch, orgVisibility, org?.id, datasetState.datasets.orgRefreshNonce])\r\n\r\n // Stamp each portal list with published-tile identity so a converted open-data\r\n // dataset shows as converted on its own tab (National/Subdivision/Municipal),\r\n // not only on the organizational tab. No-op for unpublished datasets.\r\n const nationalDatasets = React.useMemo(() => stampPublished(national.datasets, publishedCatalog), [national.datasets, publishedCatalog])\r\n const subdivisionDatasets = React.useMemo(() => stampPublished(subdivision.datasets, publishedCatalog), [subdivision.datasets, publishedCatalog])\r\n const municipalDatasets = React.useMemo(() => stampPublished(municipal.datasets, publishedCatalog), [municipal.datasets, publishedCatalog])\r\n\r\n const isLoadingNational = national.isLoading && nationalDatasets.length === 0\r\n const isLoadingSubdivision = subdivision.isLoading && subdivisionDatasets.length === 0\r\n const isLoadingMunicipal = municipal.isLoading && municipalDatasets.length === 0\r\n\r\n const datasetsError = React.useMemo(() => {\r\n if (currentTab === 'municipal' && municipal.isError && municipalDatasets.length === 0) return t('failedFetchError')\r\n if (currentTab === 'countrySubdivision' && subdivision.isError && subdivisionDatasets.length === 0) return t('failedFetchError')\r\n if (currentTab === 'national' && national.isError && nationalDatasets.length === 0) return t('failedFetchError')\r\n return null\r\n }, [currentTab, municipal.isError, municipalDatasets.length, subdivision.isError, subdivisionDatasets.length, national.isError, nationalDatasets.length, t])\r\n\r\n const allDatasets = React.useMemo(() => {\r\n const unfiltered = [\r\n ...builtinLiveDatasets, // curated live feeds (e.g. GeoMet weather radar) → Live Data tab\r\n ...nationalDatasets,\r\n ...subdivisionDatasets,\r\n ...municipalDatasets,\r\n ...addedDatasets,\r\n ...(datasetState.datasets.datasets || []),\r\n ]\r\n\r\n const filtered = unfiltered.filter(ds => datasetVisibleForOrg(ds, orgVisibility))\r\n\r\n // Also stamp here so the addedDatasets snapshot (applied at add-time, before\r\n // conversion) and any org-list entries pick up published identity on the\r\n // Applied/All tabs. Already-stamped portal entries are unchanged.\r\n return stampPublished(filtered, publishedCatalog)\r\n }, [nationalDatasets, subdivisionDatasets, municipalDatasets, datasetState.datasets.datasets, addedDatasets, orgVisibility, publishedCatalog])\r\n\r\n const currentTabLoading = React.useMemo(() => {\r\n switch (currentTab) {\r\n case 'national':\r\n return isLoadingNational\r\n case 'countrySubdivision':\r\n return isLoadingSubdivision\r\n case 'municipal':\r\n return isLoadingMunicipal\r\n case 'all':\r\n // Show loading for \"all\" if any datasets are loading and we have no data yet\r\n return (isLoadingNational || isLoadingSubdivision || isLoadingMunicipal) && \r\n allDatasets.length === 0\r\n case 'organizational':\r\n // Show loading for \"organizational\" if any datasets are loading and we have no organizational data yet\r\n return (isLoadingNational || isLoadingSubdivision || isLoadingMunicipal) && \r\n allDatasets.filter(ds => ds.group === 'Organizational').length === 0\r\n default:\r\n return false\r\n }\r\n }, [currentTab, isLoadingNational, isLoadingSubdivision, isLoadingMunicipal, allDatasets])\r\n\r\n React.useEffect(() => {\r\n if (!showMunicipalTab && currentTab === 'municipal') {\r\n setCurrentTab('all')\r\n }\r\n }, [showMunicipalTab, currentTab])\r\n\r\n // Memoized datasets for current tab\r\n const currentTabDatasets = React.useMemo(() => {\r\n switch (currentTab) {\r\n case 'applied':\r\n return allDatasets.filter(ds => addedDatasets.some(d => d.name === ds.name))\r\n case 'favourites':\r\n return allDatasets.filter(ds => favouriteDatasets.some(fav => fav.name === ds.name))\r\n case 'organizational':\r\n return allDatasets.filter(ds => ds.group === 'Organizational')\r\n case 'liveData':\r\n return allDatasets.filter(ds => ds.portal?.live === true)\r\n case 'national':\r\n return nationalDatasets\r\n case 'countrySubdivision':\r\n return subdivisionDatasets\r\n case 'municipal':\r\n return municipalDatasets\r\n case 'all':\r\n default:\r\n return allDatasets\r\n }\r\n }, [currentTab, allDatasets, addedDatasets, favouriteDatasets, nationalDatasets, subdivisionDatasets, municipalDatasets])\r\n\r\n // Memoized filtered data\r\n const filteredData = React.useMemo(() => {\r\n return currentTabDatasets.filter((dataset) => {\r\n // Search filter\r\n const matchesSearch = Object.values(dataset).some(value =>\r\n String(value).toLowerCase().includes(searchTerm.toLowerCase()),\r\n )\r\n if (!matchesSearch)\r\n return false\r\n\r\n // Country subdivision filter\r\n const matchesSubdivision\r\n = appliedFilters.countrySubdivisions.length === 0\r\n || !dataset.countrySubdivision\r\n || appliedFilters.countrySubdivisions.includes(dataset.countrySubdivision)\r\n\r\n // Municipality filter\r\n const matchesMunicipality\r\n = appliedFilters.municipalities.length === 0\r\n || !dataset.municipality\r\n || appliedFilters.municipalities.includes(dataset.municipality)\r\n\r\n // Type filter\r\n const matchesType\r\n = appliedFilters.types.length === 0\r\n || appliedFilters.types.includes(dataset.type)\r\n\r\n // Source filter (dataset.portal?.name, falling back to publisher)\r\n const datasetSource = dataset.portal?.name ?? dataset.publisher\r\n const matchesSource\r\n = appliedFilters.sources.length === 0\r\n || (datasetSource ? appliedFilters.sources.includes(datasetSource) : false)\r\n\r\n return matchesSubdivision && matchesMunicipality && matchesType && matchesSource\r\n })\r\n }, [currentTabDatasets, searchTerm, appliedFilters])\r\n\r\n const sortedFilteredData = React.useMemo(() => {\r\n // Remove duplicates by name\r\n const uniqueByName = new Map<string, Dataset>()\r\n for (const ds of filteredData) {\r\n const name = ds.name?.toLowerCase() || ''\r\n if (!uniqueByName.has(name)) {\r\n uniqueByName.set(name, ds)\r\n }\r\n }\r\n\r\n // Filter out unwanted names/types\r\n const filtered = [...uniqueByName.values()].filter((ds) => {\r\n const name = ds.name?.toLowerCase() || ''\r\n const type = ds.type?.toLowerCase() || ''\r\n return !name.includes('basemap') && !type.includes('geocoding')\r\n })\r\n\r\n // HARD CODE BLOCK LIST\r\n const blocklisted = (ds: Dataset) => {\r\n const url = (ds.url || '').toLowerCase()\r\n const name = (ds.name || '').toLowerCase()\r\n return (\r\n url.includes('/2021_statistics_canada_boundaries/featureserver')\r\n || name.includes('2021 statistics canada boundaries')\r\n || url.includes('/limites_du_recensement_de_statistique_canada_(2021)/featureserver')\r\n || name.includes('limites du recensement de statistique canada (2021)')\r\n )\r\n }\r\n\r\n const safe = filtered.filter(ds => !blocklisted(ds))\r\n\r\n // Sort by name\r\n return safe.sort((a, b) =>\r\n (a.name || '').localeCompare(b.name || ''),\r\n )\r\n }, [filteredData])\r\n\r\n const { prefetch } = useFastDatasetCache()\r\n\r\n React.useEffect(() => {\r\n if (isOpen && sortedFilteredData.length > 0) {\r\n const datasetsToPreload = sortedFilteredData.slice(0, 10)\r\n datasetsToPreload.forEach((dataset, index) => {\r\n setTimeout(() => {\r\n prefetch(dataset)\r\n }, index * 200)\r\n })\r\n }\r\n }, [isOpen, sortedFilteredData, prefetch])\r\n\r\n // Handlers\r\n const handleTabChange = React.useCallback((value: string) => setCurrentTab(value), [])\r\n const handleRowClick = React.useCallback((dataset: Dataset) => {\r\n setSelectedDataset(dataset)\r\n setView('detail')\r\n }, [])\r\n const handleRowHover = React.useCallback((dataset: Dataset) => {\r\n prefetch(dataset)\r\n \r\n const currentIndex = sortedFilteredData.indexOf(dataset)\r\n if (currentIndex >= 0 && currentIndex < sortedFilteredData.length - 2) {\r\n setTimeout(() => {\r\n if (sortedFilteredData[currentIndex + 1]) {\r\n prefetch(sortedFilteredData[currentIndex + 1])\r\n }\r\n }, 100)\r\n }\r\n }, [prefetch, sortedFilteredData])\r\n const handleBackToTable = React.useCallback(() => {\r\n setView('table')\r\n setSelectedDataset(null)\r\n }, [])\r\n const handleAddDatasetToMap = React.useCallback(() => {\r\n if (selectedDataset) {\r\n datasetDispatch({ type: 'ADD_DATASET_TO_MAP', payload: { dataset: selectedDataset } })\r\n }\r\n }, [selectedDataset, datasetDispatch])\r\n const handleRemoveDatasetFromMap = React.useCallback(() => {\r\n if (selectedDataset) {\r\n datasetDispatch({ type: 'REMOVE_DATASET_FROM_MAP', payload: { datasetId: selectedDataset.id } })\r\n }\r\n }, [selectedDataset, datasetDispatch])\r\n const handleFavourite = handleFavouriteDataset(selectedDataset, favouriteDatasets, setFavouriteDatasets)\r\n\r\n const handleAddDataset = () => {\r\n // Logic to add a new dataset\r\n }\r\n\r\n // UI\r\n return (\r\n <Dialog open={isOpen} onOpenChange={setIsOpenAction}>\r\n <DialogContent className=\"h-screen sm:h-[90vh] sm:max-h-[90vh] w-full max-w-full sm:w-[88vw] sm:max-w-[88vw] p-0 gap-0 overflow-hidden flex flex-col\">\r\n {view === 'table' ? (\r\n <>\r\n <DialogHeader className=\"bg-background z-50 sticky top-0 p-6 flex flex-row flex-wrap justify-between items-end gap-2 text-left\">\r\n <div className=\"flex flex-col justify-end p-0\">\r\n <DialogTitle className=\"text-2xl\">{t('dialogTitle')}</DialogTitle>\r\n <DialogDescription className=\"text-sm\">\r\n {t('dialogDescription')}\r\n </DialogDescription>\r\n </div>\r\n <div className=\"flex flex-row flex-wrap justify-between items-center\">\r\n <div className=\"flex flex-wrap gap-2 font-medium\">\r\n <div className=\"relative\">\r\n <LR.Search className=\"absolute left-3 top-2.5 h-4 w-4 text-muted-foreground\" />\r\n <Input\r\n placeholder=\"Search\"\r\n className=\"pl-8 w-[250px]\"\r\n value={searchTerm}\r\n onChange={e => setSearchTerm(e.target.value)}\r\n disabled={!ability.can('read', 'File')}\r\n />\r\n </div>\r\n <div className=\"flex gap-2\">\r\n <Filters\r\n datasets={currentTabDatasets}\r\n appliedFilters={appliedFilters}\r\n onFiltersChange={setAppliedFilters}\r\n />\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n onClick={() => setIsAddPortalOpen(true)}\r\n title=\"Register a new open data portal\"\r\n >\r\n <LR.Plus className=\"h-4 w-4 mr-1\" />\r\n Add Portal\r\n </Button>\r\n </div>\r\n </div>\r\n </div>\r\n <DialogClose className=\"absolute right-2 top-2 h-5 w-5 rounded-xl text-muted-foreground hover:bg-transparent focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-background focus:ring-primary\">\r\n <LR.X className=\"!h-4 !w-4\" />\r\n </DialogClose>\r\n </DialogHeader>\r\n <div className=\"relative flex flex-col flex-1 min-h-0\">\r\n <Tabs value={currentTab} className=\"flex flex-col gap-0 h-full\" onValueChange={handleTabChange}>\r\n <div className=\"hidden md:!flex justify-between px-3 flex-shrink-0\">\r\n {' '}\r\n {/* Prevent tabs from shrinking */}\r\n <TabsList className=\"pointer-events-auto sticky flex z-40 top-[100px] bg-transparent\">\r\n <TabsTrigger className=\"hover:text-foreground gap-2\" value=\"applied\">\r\n <Badge variant=\"outline\">{addedDatasets.length}</Badge>\r\n {t('appliedTab')}\r\n </TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground gap-2\" value=\"favourites\">\r\n {t('favoritesTab')}\r\n </TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"organizational\">{t('organizationalTab')}</TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"all\">{t('allDataTab')}</TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"national\">{t('nationalTab')}</TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"countrySubdivision\">{t('countrySubdivisionTab')}</TabsTrigger>\r\n {showMunicipalTab && (\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"municipal\">{t('municipalTab')}</TabsTrigger>\r\n )}\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"liveData\">{t('liveDataTab')}</TabsTrigger>\r\n </TabsList>\r\n </div>\r\n <TabsContent\r\n value={currentTab}\r\n className=\"flex-1 pointer-events-auto mt-0 min-h-0\" // min-h-0 is crucial for flex children\r\n >\r\n {currentTabLoading ? (\r\n <DatasetSkeleton />\r\n ) : (datasetsError ? (\r\n <div className=\"flex flex-col justify-center items-center h-32 text-muted-foreground\">\r\n <LR.AlertCircle className=\"h-6 w-6 mb-2\" />\r\n <span>{datasetsError}</span>\r\n <Button variant=\"outline\" size=\"sm\" onClick={() => window.location.reload()} className=\"mt-2\">\r\n <LR.RefreshCw className=\"h-4 w-4 mr-2\" />\r\n {t('refreshButton')}\r\n </Button>\r\n </div>\r\n ) : (\r\n <DataTable\r\n showPagination={true}\r\n columns={datasetColumns}\r\n data={sortedFilteredData}\r\n tab={currentTab}\r\n onRowClick={handleRowClick}\r\n onRowHover={handleRowHover}\r\n className=\"rounded-none w-auto h-full\" \r\n paginationClasses=\"bg-background z-20 w-full border-t\" \r\n isLoading={currentTabLoading}\r\n leadingCell={props => (\r\n <RowActions\r\n {...props}\r\n favouriteDatasets={favouriteDatasets}\r\n setFavouriteDatasets={setFavouriteDatasets}\r\n />\r\n )}\r\n trailingCell={({ row, index }) => (\r\n <div>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"pointer-events-none\"\r\n >\r\n <LR.ChevronRight />\r\n </Button>\r\n </div>\r\n )}\r\n />\r\n ))}\r\n </TabsContent>\r\n </Tabs>\r\n </div>\r\n </>\r\n ) : (\r\n // Detail View Content\r\n <>\r\n <DialogHeader className=\"px-6 pt-6\">\r\n <div>\r\n <Breadcrumb>\r\n <BreadcrumbList>\r\n <BreadcrumbItem>\r\n <BreadcrumbLink\r\n href=\"#\"\r\n onClick={() => {\r\n handleBackToTable()\r\n setCurrentTab('all')\r\n }}\r\n >\r\n {t('breadcrumbTitle')}\r\n </BreadcrumbLink>\r\n </BreadcrumbItem>\r\n <BreadcrumbSeparator />\r\n <BreadcrumbItem>\r\n <BreadcrumbLink\r\n href=\"#\"\r\n onClick={() => {\r\n setCurrentTab(currentTab)\r\n handleBackToTable()\r\n }}\r\n >\r\n {currentTab.charAt(0).toUpperCase() + currentTab.slice(1)}\r\n </BreadcrumbLink>\r\n </BreadcrumbItem>\r\n <BreadcrumbSeparator />\r\n <BreadcrumbItem>\r\n <BreadcrumbPage>{selectedDataset?.name}</BreadcrumbPage>\r\n </BreadcrumbItem>\r\n </BreadcrumbList>\r\n </Breadcrumb>\r\n </div>\r\n <div className=\"flex flex-row justify-between\">\r\n <div className=\"flex items-center\">\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className={`opacity-70 hover:opacity-100 transition-opacity duration-200 hover:bg-transparent ${selectedDataset && favouriteDatasets.includes(selectedDataset) ? 'opacity-100' : ''}`}\r\n onClick={handleFavourite}\r\n >\r\n <LR.Star\r\n className=\"!h-5 !w-5\"\r\n size={24}\r\n color={`${selectedDataset && favouriteDatasets.includes(selectedDataset) ? 'hsl(var(--chart-5))' : 'black'} `}\r\n fill={`${selectedDataset && favouriteDatasets.includes(selectedDataset) ? 'hsl(var(--chart-5))' : 'none'} `}\r\n />\r\n </Button>\r\n <DialogTitle>{selectedDataset?.name}</DialogTitle>\r\n </div>\r\n <div className=\"flex gap-2\">\r\n <Button\r\n variant=\"secondary\"\r\n onClick={handleBackToTable}\r\n >\r\n <LR.ArrowLeft />\r\n {t('backToDataButton')}\r\n </Button>\r\n {selectedDataset && addedDatasets.some(d => d.name === selectedDataset.name)\r\n ? (\r\n <Button onClick={handleRemoveDatasetFromMap} disabled={!ability.can('read', 'File')}>\r\n <LR.Minus />\r\n {t('removeButton')}\r\n </Button>\r\n )\r\n : (\r\n <Button onClick={handleAddDatasetToMap} disabled={!ability.can('read', 'File')}>\r\n <LR.Plus />\r\n {t('applyButton')}\r\n </Button>\r\n )}\r\n </div>\r\n </div>\r\n </DialogHeader>\r\n <DatasetDetails selectedDataset={selectedDataset} />\r\n </>\r\n )}\r\n </DialogContent>\r\n <AddPortalDialog open={isAddPortalOpen} onOpenChange={setIsAddPortalOpen} />\r\n </Dialog>\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","_b"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/core/components/viewers/map/datasets/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\n// Icons\r\nimport * as LR from 'lucide-react'\r\n// Dependencies\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\nimport { usePermissions } from '../../../../store'\r\nimport { usePathname } from 'next/navigation'\r\n\r\nimport type { Dataset } from '../../../../types/datasetTypes'\r\nimport { useOpenDataPortalsByCountrySubdivision, useOpenDataPortalsByGroup, useOpenDataPortalsByMunicipality } from '../../../../hooks/openDataPortals/openDataPortals'\r\nimport { DatasetsContext, MenusContext, useMapContext } from '../../../../store'\r\n// import { useAppConfigContext } from '../../../../store/AppConfig/context'\r\nimport { Badge } from '../../../../components/ui/Badge'\r\nimport {\r\n Breadcrumb,\r\n BreadcrumbItem,\r\n BreadcrumbLink,\r\n BreadcrumbList,\r\n BreadcrumbPage,\r\n BreadcrumbSeparator,\r\n} from '../../../../components/ui/Breadcrumb'\r\nimport { Button } from '../../../../components/ui/Button'\r\nimport { DataTable } from '../../../../components/ui/DataTable'\r\nimport {\r\n Dialog,\r\n DialogClose,\r\n DialogContent,\r\n DialogDescription,\r\n DialogHeader,\r\n DialogTitle,\r\n} from '../../../../components/ui/Dialog'\r\nimport { Input } from '../../../../components/ui/Input'\r\nimport { Tabs, TabsContent, TabsList, TabsTrigger } from '../../../../components/ui/Tabs'\r\n// Data\r\nimport { useColumns } from './data'\r\nimport DatasetDetails from './DatasetDetails'\r\n// Custom components\r\nimport { AddPortalDialog } from './AddPortalDialog'\r\nimport DatasetSkeleton from './DatasetSkeleton'\r\nimport Filters from './Filters'\r\nimport RowActions from './RowActions'\r\nimport { useDatasetsForPortals } from './src/useDatasetsForPortals'\r\nimport { handleFavouriteDataset } from './utils'\r\nimport { fetchLocalDatasets } from './src/localDatasets'\r\nimport { fetchOrganizationalMinioDatasets } from './src/minioDatasets'\r\nimport { buildPublishedCatalogMap, stampPublished, type PublishedCatalogEntry } from './src/publishedTiles'\r\nimport { builtinLiveDatasets } from './src/builtinLiveDatasets'\r\nimport { useFastDatasetCache } from './src/useFastDatasetCache'\r\nimport { DatasetGroup, Organization } from '../../../../types/dbTypes'\r\n\r\ntype OrgVisibility = {\r\n isAdmin: boolean\r\n currentOrgId: number\r\n allowedOrgIds: number[]\r\n}\r\n\r\nconst ADMIN_ALLOWED_ORGS = [1, 2, 3, 4, 5, 6]\r\nconst ORG_BY_PATH_PREFIX: Record<string, number> = {\r\n '/envirocentre': 1,\r\n '/dnd': 3,\r\n '/canada': 4,\r\n '/gac': 5,\r\n '/carleton': 6,\r\n}\r\n\r\nfunction normalizeOrgId(org?: number | string | null) {\r\n if (org === null || org === undefined) return undefined\r\n const parsed = typeof org === 'number' ? org : Number.parseInt(String(org), 10)\r\n return Number.isFinite(parsed) ? parsed : undefined\r\n}\r\n\r\nfunction getOrgVisibilityFromPath(pathname?: string | null): OrgVisibility {\r\n const normalizedPath = (pathname || '').toLowerCase()\r\n const firstSegment = normalizedPath.split('/').filter(Boolean)[0]\r\n const prefix = firstSegment ? `/${firstSegment}` : ''\r\n\r\n if (prefix === '/cdt') {\r\n return {\r\n isAdmin: true,\r\n currentOrgId: 1,\r\n allowedOrgIds: ADMIN_ALLOWED_ORGS,\r\n }\r\n }\r\n\r\n const currentOrgId = ORG_BY_PATH_PREFIX[prefix] ?? 2\r\n const allowedOrgIds = Array.from(new Set([2, currentOrgId]))\r\n\r\n return {\r\n isAdmin: false,\r\n currentOrgId,\r\n allowedOrgIds,\r\n }\r\n}\r\n\r\nfunction datasetVisibleForOrg(dataset: Dataset, visibility: OrgVisibility) {\r\n if (visibility.isAdmin) return true\r\n if (dataset.group !== DatasetGroup.Organizational) return true\r\n\r\n const orgId = normalizeOrgId(dataset.organization)\r\n if (orgId === undefined) return false\r\n\r\n return visibility.allowedOrgIds.includes(orgId)\r\n}\r\n\r\n\r\ntype DatasetsProps = {\r\n isOpen: boolean\r\n setIsOpenAction: (open: boolean) => void\r\n organization?: Organization\r\n minioBaseUrl?: string\r\n martinBaseUrl?: string\r\n}\r\n\r\nexport default function Datasets({ isOpen, setIsOpenAction, organization, minioBaseUrl, martinBaseUrl }: DatasetsProps) {\r\n // Translation\r\n const t = useTranslations('Datasets')\r\n\r\n // Permissions\r\n const { ability } = usePermissions()\r\n\r\n const datasetColumns = useColumns()\r\n\r\n // Contexts\r\n const { state: mapState } = useMapContext()\r\n const { currentLocation } = mapState.map\r\n const orgCountry = (organization?.country || '').toUpperCase()\r\n const org = organization\r\n // Fall back to org fixed location when currentLocation hasn't been set yet (e.g. before map hover)\r\n const municipality = currentLocation?.municipality ?? org?.municipality ?? null\r\n const countrySubdivision = currentLocation?.countrySubdivision ?? org?.countrySubdivision ?? null\r\n const { state: datasetState, dispatch: datasetDispatch } = React.useContext(DatasetsContext)\r\n const { addedDatasets } = datasetState.datasets\r\n const { state: menusState } = React.useContext(MenusContext)\r\n const { rowsPerPage } = menusState.menus\r\n\r\n const pathname = usePathname()\r\n const orgVisibility = React.useMemo(() => getOrgVisibilityFromPath(pathname), [pathname])\r\n\r\n // UI State\r\n const [view, setView] = React.useState<'table' | 'detail'>('table')\r\n const [selectedDataset, setSelectedDataset] = React.useState<Dataset | null>(null)\r\n const [favouriteDatasets, setFavouriteDatasets] = React.useState<Dataset[]>([])\r\n const [searchTerm, setSearchTerm] = React.useState('')\r\n const [appliedFilters, setAppliedFilters] = React.useState<{ countrySubdivisions: string[], municipalities: string[], types: string[], sources: string[] }>({ countrySubdivisions: [], municipalities: [], types: [], sources: [] })\r\n const [currentTab, setCurrentTab] = React.useState('all')\r\n const [isAddPortalOpen, setIsAddPortalOpen] = React.useState(false)\r\n // Open-data datasets already published to Martin tiles, keyed by\r\n // \"{portalId}:{datasetId}\". Lets the original portal entry (National/Applied/\r\n // All tabs) show as converted, not just the organizational-list copy.\r\n const [publishedCatalog, setPublishedCatalog] = React.useState<Map<string, PublishedCatalogEntry>>(new Map())\r\n const showMunicipalTab = React.useMemo(() => Boolean(municipality), [municipality])\r\n\r\n const { openDataPortals: municipalPortals } = useOpenDataPortalsByMunicipality(municipality)\r\n const { openDataPortals: subdivisionPortals } = useOpenDataPortalsByCountrySubdivision(countrySubdivision)\r\n const { openDataPortals: nationalPortals } = useOpenDataPortalsByGroup(DatasetGroup.National)\r\n\r\n // Belt-and-suspenders country guard: portal.country must match org, or be unset (legacy/global)\r\n const matchesOrgCountry = React.useCallback(\r\n (portalCountry: string | null | undefined) => {\r\n if (!orgCountry) return true // org country unknown — show everything\r\n if (!portalCountry) return true // portal has no country set — treat as global\r\n return portalCountry.toUpperCase() === orgCountry\r\n },\r\n [orgCountry],\r\n )\r\n\r\n const filteredMunicipalPortals = React.useMemo(() => {\r\n if (!Array.isArray(municipalPortals)) return []\r\n const filtered = municipalPortals.filter(p => matchesOrgCountry(p.country))\r\n return filtered\r\n }, [municipalPortals, matchesOrgCountry, municipality])\r\n const filteredSubdivisionPortals = React.useMemo(\r\n () => (Array.isArray(subdivisionPortals)\r\n ? subdivisionPortals.filter(p => p.municipality == null && matchesOrgCountry(p.country))\r\n : []),\r\n [subdivisionPortals, matchesOrgCountry],\r\n )\r\n const filteredNationalPortals = React.useMemo(() => {\r\n if (!Array.isArray(nationalPortals)) return []\r\n const filtered = nationalPortals.filter(p => matchesOrgCountry(p.country))\r\n return filtered\r\n }, [nationalPortals, orgCountry, matchesOrgCountry])\r\n\r\n const municipal = useDatasetsForPortals(filteredMunicipalPortals, { rowsPerPage })\r\n const subdivision = useDatasetsForPortals(filteredSubdivisionPortals, { rowsPerPage })\r\n const national = useDatasetsForPortals(filteredNationalPortals, { rowsPerPage })\r\n React.useEffect(() => {\r\n const loadOrganizationalDatasets = async () => {\r\n // First, refresh the published-catalog lookup (a fast /api/files read) so\r\n // converted open-data datasets flip promptly across every tab — ahead of\r\n // the slower Martin tile-sampling below. Non-fatal on failure.\r\n try {\r\n const filesRes = await fetch('/api/files')\r\n if (filesRes.ok) {\r\n const body = await filesRes.json()\r\n const rows = Array.isArray(body?.files) ? body.files : []\r\n setPublishedCatalog(buildPublishedCatalogMap(rows))\r\n }\r\n }\r\n catch (err) {\r\n console.warn('Failed to refresh published-catalog map:', err)\r\n }\r\n\r\n // Two parallel sources: Martin vector tiles (if configured) and MinIO-\r\n // backed GeoJSON uploads (the \"Add Dataset\" path). Errors from either\r\n // are isolated so a failure on one side does not block the other.\r\n const martinBaseUrlClean = (martinBaseUrl ?? '').replace(/\\/+$/, '')\r\n\r\n const martinPromise: Promise<Dataset[]> = martinBaseUrlClean\r\n ? (async () => {\r\n const datasetsUrl = martinBaseUrlClean.includes('/tiles/index.json')\r\n ? martinBaseUrlClean\r\n : `${martinBaseUrlClean}/tiles/index.json`\r\n\r\n const localPortal = {\r\n id: -1,\r\n name: 'Organizational Datasets',\r\n apiUrl: datasetsUrl,\r\n dataManagementSystem: 'Other' as const,\r\n countrySubdivision: null,\r\n municipality: null,\r\n group: 'Organizational' as const,\r\n }\r\n\r\n try {\r\n return await fetchLocalDatasets(localPortal as any)\r\n }\r\n catch (err) {\r\n console.error('Failed to load Martin organizational datasets:', err)\r\n return []\r\n }\r\n })()\r\n : Promise.resolve([])\r\n\r\n if (!martinBaseUrlClean) {\r\n console.warn('NEXT_PUBLIC_MARTIN_SERVER_URL not configured — skipping Martin pre-load')\r\n }\r\n\r\n // The MinIO key prefix is the *session* organization (set server-side\r\n // by the upload route), not orgVisibility.currentOrgId (which is\r\n // path-derived and hardcoded for admin routes like /cdt).\r\n const sessionOrgId = typeof org?.id === 'number'\r\n ? org.id\r\n : Number.parseInt(String(org?.id ?? ''), 10)\r\n\r\n // Martin must resolve first so MinIO suppression can check live catalog\r\n // membership — prevents \"file disappeared\" during the publish→restart gap.\r\n const martinDatasets = await martinPromise\r\n const publishedTilesInCatalog = new Set<string>(\r\n martinDatasets.map(d => typeof d.id === 'string' ? d.id : '').filter(Boolean),\r\n )\r\n\r\n const minioDatasets: Dataset[] = Number.isFinite(sessionOrgId)\r\n ? await fetchOrganizationalMinioDatasets(sessionOrgId, publishedTilesInCatalog, minioBaseUrl).catch((err) => {\r\n console.error('Failed to load MinIO organizational datasets:', err)\r\n return []\r\n })\r\n : []\r\n\r\n const combined = [...martinDatasets, ...minioDatasets]\r\n const visibleOrgDatasets = combined.filter(ds => datasetVisibleForOrg(ds, orgVisibility))\r\n\r\n if (visibleOrgDatasets.length === 0) {\r\n console.warn('No organizational datasets found')\r\n }\r\n datasetDispatch({\r\n type: 'SET_DATASETS',\r\n payload: { datasets: visibleOrgDatasets },\r\n })\r\n }\r\n\r\n loadOrganizationalDatasets()\r\n }, [datasetDispatch, orgVisibility, org?.id, datasetState.datasets.orgRefreshNonce])\r\n\r\n // Stamp each portal list with published-tile identity so a converted open-data\r\n // dataset shows as converted on its own tab (National/Subdivision/Municipal),\r\n // not only on the organizational tab. No-op for unpublished datasets.\r\n const nationalDatasets = React.useMemo(() => stampPublished(national.datasets, publishedCatalog), [national.datasets, publishedCatalog])\r\n const subdivisionDatasets = React.useMemo(() => stampPublished(subdivision.datasets, publishedCatalog), [subdivision.datasets, publishedCatalog])\r\n const municipalDatasets = React.useMemo(() => stampPublished(municipal.datasets, publishedCatalog), [municipal.datasets, publishedCatalog])\r\n\r\n const isLoadingNational = national.isLoading && nationalDatasets.length === 0\r\n const isLoadingSubdivision = subdivision.isLoading && subdivisionDatasets.length === 0\r\n const isLoadingMunicipal = municipal.isLoading && municipalDatasets.length === 0\r\n\r\n const datasetsError = React.useMemo(() => {\r\n if (currentTab === 'municipal' && municipal.isError && municipalDatasets.length === 0) return t('failedFetchError')\r\n if (currentTab === 'countrySubdivision' && subdivision.isError && subdivisionDatasets.length === 0) return t('failedFetchError')\r\n if (currentTab === 'national' && national.isError && nationalDatasets.length === 0) return t('failedFetchError')\r\n return null\r\n }, [currentTab, municipal.isError, municipalDatasets.length, subdivision.isError, subdivisionDatasets.length, national.isError, nationalDatasets.length, t])\r\n\r\n const allDatasets = React.useMemo(() => {\r\n const unfiltered = [\r\n ...builtinLiveDatasets, // curated live feeds (e.g. GeoMet weather radar) → Live Data tab\r\n ...nationalDatasets,\r\n ...subdivisionDatasets,\r\n ...municipalDatasets,\r\n ...addedDatasets,\r\n ...(datasetState.datasets.datasets || []),\r\n ]\r\n\r\n const filtered = unfiltered.filter(ds => datasetVisibleForOrg(ds, orgVisibility))\r\n\r\n // Also stamp here so the addedDatasets snapshot (applied at add-time, before\r\n // conversion) and any org-list entries pick up published identity on the\r\n // Applied/All tabs. Already-stamped portal entries are unchanged.\r\n return stampPublished(filtered, publishedCatalog)\r\n }, [nationalDatasets, subdivisionDatasets, municipalDatasets, datasetState.datasets.datasets, addedDatasets, orgVisibility, publishedCatalog])\r\n\r\n const currentTabLoading = React.useMemo(() => {\r\n switch (currentTab) {\r\n case 'national':\r\n return isLoadingNational\r\n case 'countrySubdivision':\r\n return isLoadingSubdivision\r\n case 'municipal':\r\n return isLoadingMunicipal\r\n case 'all':\r\n // Show loading for \"all\" if any datasets are loading and we have no data yet\r\n return (isLoadingNational || isLoadingSubdivision || isLoadingMunicipal) && \r\n allDatasets.length === 0\r\n case 'organizational':\r\n // Show loading for \"organizational\" if any datasets are loading and we have no organizational data yet\r\n return (isLoadingNational || isLoadingSubdivision || isLoadingMunicipal) && \r\n allDatasets.filter(ds => ds.group === 'Organizational').length === 0\r\n default:\r\n return false\r\n }\r\n }, [currentTab, isLoadingNational, isLoadingSubdivision, isLoadingMunicipal, allDatasets])\r\n\r\n React.useEffect(() => {\r\n if (!showMunicipalTab && currentTab === 'municipal') {\r\n setCurrentTab('all')\r\n }\r\n }, [showMunicipalTab, currentTab])\r\n\r\n // Memoized datasets for current tab\r\n const currentTabDatasets = React.useMemo(() => {\r\n switch (currentTab) {\r\n case 'applied':\r\n return allDatasets.filter(ds => addedDatasets.some(d => d.name === ds.name))\r\n case 'favourites':\r\n return allDatasets.filter(ds => favouriteDatasets.some(fav => fav.name === ds.name))\r\n case 'organizational':\r\n return allDatasets.filter(ds => ds.group === 'Organizational')\r\n case 'liveData':\r\n return allDatasets.filter(ds => ds.portal?.live === true)\r\n case 'national':\r\n return nationalDatasets\r\n case 'countrySubdivision':\r\n return subdivisionDatasets\r\n case 'municipal':\r\n return municipalDatasets\r\n case 'all':\r\n default:\r\n return allDatasets\r\n }\r\n }, [currentTab, allDatasets, addedDatasets, favouriteDatasets, nationalDatasets, subdivisionDatasets, municipalDatasets])\r\n\r\n // Memoized filtered data\r\n const filteredData = React.useMemo(() => {\r\n return currentTabDatasets.filter((dataset) => {\r\n // Search filter\r\n const matchesSearch = Object.values(dataset).some(value =>\r\n String(value).toLowerCase().includes(searchTerm.toLowerCase()),\r\n )\r\n if (!matchesSearch)\r\n return false\r\n\r\n // Country subdivision filter\r\n const matchesSubdivision\r\n = appliedFilters.countrySubdivisions.length === 0\r\n || !dataset.countrySubdivision\r\n || appliedFilters.countrySubdivisions.includes(dataset.countrySubdivision)\r\n\r\n // Municipality filter\r\n const matchesMunicipality\r\n = appliedFilters.municipalities.length === 0\r\n || !dataset.municipality\r\n || appliedFilters.municipalities.includes(dataset.municipality)\r\n\r\n // Type filter\r\n const matchesType\r\n = appliedFilters.types.length === 0\r\n || appliedFilters.types.includes(dataset.type)\r\n\r\n // Source filter (dataset.portal?.name, falling back to publisher)\r\n const datasetSource = dataset.portal?.name ?? dataset.publisher\r\n const matchesSource\r\n = appliedFilters.sources.length === 0\r\n || (datasetSource ? appliedFilters.sources.includes(datasetSource) : false)\r\n\r\n return matchesSubdivision && matchesMunicipality && matchesType && matchesSource\r\n })\r\n }, [currentTabDatasets, searchTerm, appliedFilters])\r\n\r\n const sortedFilteredData = React.useMemo(() => {\r\n // Remove duplicates by name\r\n const uniqueByName = new Map<string, Dataset>()\r\n for (const ds of filteredData) {\r\n const name = ds.name?.toLowerCase() || ''\r\n if (!uniqueByName.has(name)) {\r\n uniqueByName.set(name, ds)\r\n }\r\n }\r\n\r\n // Filter out unwanted names/types\r\n const filtered = [...uniqueByName.values()].filter((ds) => {\r\n const name = ds.name?.toLowerCase() || ''\r\n const type = ds.type?.toLowerCase() || ''\r\n return !name.includes('basemap') && !type.includes('geocoding')\r\n })\r\n\r\n // HARD CODE BLOCK LIST\r\n const blocklisted = (ds: Dataset) => {\r\n const url = (ds.url || '').toLowerCase()\r\n const name = (ds.name || '').toLowerCase()\r\n return (\r\n url.includes('/2021_statistics_canada_boundaries/featureserver')\r\n || name.includes('2021 statistics canada boundaries')\r\n || url.includes('/limites_du_recensement_de_statistique_canada_(2021)/featureserver')\r\n || name.includes('limites du recensement de statistique canada (2021)')\r\n )\r\n }\r\n\r\n const safe = filtered.filter(ds => !blocklisted(ds))\r\n\r\n // Sort by name\r\n return safe.sort((a, b) =>\r\n (a.name || '').localeCompare(b.name || ''),\r\n )\r\n }, [filteredData])\r\n\r\n const { prefetch } = useFastDatasetCache()\r\n\r\n React.useEffect(() => {\r\n if (isOpen && sortedFilteredData.length > 0) {\r\n const datasetsToPreload = sortedFilteredData.slice(0, 10)\r\n datasetsToPreload.forEach((dataset, index) => {\r\n setTimeout(() => {\r\n prefetch(dataset)\r\n }, index * 200)\r\n })\r\n }\r\n }, [isOpen, sortedFilteredData, prefetch])\r\n\r\n // Handlers\r\n const handleTabChange = React.useCallback((value: string) => setCurrentTab(value), [])\r\n const handleRowClick = React.useCallback((dataset: Dataset) => {\r\n setSelectedDataset(dataset)\r\n setView('detail')\r\n }, [])\r\n const handleRowHover = React.useCallback((dataset: Dataset) => {\r\n prefetch(dataset)\r\n \r\n const currentIndex = sortedFilteredData.indexOf(dataset)\r\n if (currentIndex >= 0 && currentIndex < sortedFilteredData.length - 2) {\r\n setTimeout(() => {\r\n if (sortedFilteredData[currentIndex + 1]) {\r\n prefetch(sortedFilteredData[currentIndex + 1])\r\n }\r\n }, 100)\r\n }\r\n }, [prefetch, sortedFilteredData])\r\n const handleBackToTable = React.useCallback(() => {\r\n setView('table')\r\n setSelectedDataset(null)\r\n }, [])\r\n const handleAddDatasetToMap = React.useCallback(() => {\r\n if (selectedDataset) {\r\n datasetDispatch({ type: 'ADD_DATASET_TO_MAP', payload: { dataset: selectedDataset } })\r\n }\r\n }, [selectedDataset, datasetDispatch])\r\n const handleRemoveDatasetFromMap = React.useCallback(() => {\r\n if (selectedDataset) {\r\n datasetDispatch({ type: 'REMOVE_DATASET_FROM_MAP', payload: { datasetId: selectedDataset.id } })\r\n }\r\n }, [selectedDataset, datasetDispatch])\r\n const handleFavourite = handleFavouriteDataset(selectedDataset, favouriteDatasets, setFavouriteDatasets)\r\n\r\n const handleAddDataset = () => {\r\n // Logic to add a new dataset\r\n }\r\n\r\n // UI\r\n return (\r\n <Dialog open={isOpen} onOpenChange={setIsOpenAction}>\r\n <DialogContent className=\"h-screen sm:h-[90vh] sm:max-h-[90vh] w-full max-w-full sm:w-[88vw] sm:max-w-[88vw] p-0 gap-0 overflow-hidden flex flex-col\">\r\n {view === 'table' ? (\r\n <>\r\n <DialogHeader className=\"bg-background z-50 sticky top-0 p-6 flex flex-row flex-wrap justify-between items-end gap-2 text-left\">\r\n <div className=\"flex flex-col justify-end p-0\">\r\n <DialogTitle className=\"text-2xl\">{t('dialogTitle')}</DialogTitle>\r\n <DialogDescription className=\"text-sm\">\r\n {t('dialogDescription')}\r\n </DialogDescription>\r\n </div>\r\n <div className=\"flex flex-row flex-wrap justify-between items-center\">\r\n <div className=\"flex flex-wrap gap-2 font-medium\">\r\n <div className=\"relative\">\r\n <LR.Search className=\"absolute left-3 top-2.5 h-4 w-4 text-muted-foreground\" />\r\n <Input\r\n placeholder=\"Search\"\r\n className=\"pl-8 w-[250px]\"\r\n value={searchTerm}\r\n onChange={e => setSearchTerm(e.target.value)}\r\n disabled={!ability.can('read', 'File')}\r\n />\r\n </div>\r\n <div className=\"flex gap-2\">\r\n <Filters\r\n datasets={currentTabDatasets}\r\n appliedFilters={appliedFilters}\r\n onFiltersChange={setAppliedFilters}\r\n />\r\n <Button\r\n variant=\"outline\"\r\n size=\"sm\"\r\n onClick={() => setIsAddPortalOpen(true)}\r\n title=\"Register a new open data portal\"\r\n >\r\n <LR.Plus className=\"h-4 w-4 mr-1\" />\r\n Add Portal\r\n </Button>\r\n </div>\r\n </div>\r\n </div>\r\n <DialogClose className=\"absolute right-2 top-2 h-5 w-5 rounded-xl text-muted-foreground hover:bg-transparent focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-background focus:ring-primary\">\r\n <LR.X className=\"!h-4 !w-4\" />\r\n </DialogClose>\r\n </DialogHeader>\r\n <div className=\"relative flex flex-col flex-1 min-h-0\">\r\n <Tabs value={currentTab} className=\"flex flex-col gap-0 h-full\" onValueChange={handleTabChange}>\r\n <div className=\"hidden md:!flex justify-between px-3 flex-shrink-0\">\r\n {' '}\r\n {/* Prevent tabs from shrinking */}\r\n <TabsList className=\"pointer-events-auto sticky flex z-40 top-[100px] bg-transparent\">\r\n <TabsTrigger className=\"hover:text-foreground gap-2\" value=\"applied\">\r\n <Badge variant=\"outline\">{addedDatasets.length}</Badge>\r\n {t('appliedTab')}\r\n </TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground gap-2\" value=\"favourites\">\r\n {t('favoritesTab')}\r\n </TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"organizational\">{t('organizationalTab')}</TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"all\">{t('allDataTab')}</TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"national\">{t('nationalTab')}</TabsTrigger>\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"countrySubdivision\">{t('countrySubdivisionTab')}</TabsTrigger>\r\n {showMunicipalTab && (\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"municipal\">{t('municipalTab')}</TabsTrigger>\r\n )}\r\n <TabsTrigger className=\"hover:text-foreground\" value=\"liveData\">{t('liveDataTab')}</TabsTrigger>\r\n </TabsList>\r\n </div>\r\n <TabsContent\r\n value={currentTab}\r\n className=\"flex-1 pointer-events-auto mt-0 min-h-0\" // min-h-0 is crucial for flex children\r\n >\r\n {currentTabLoading ? (\r\n <DatasetSkeleton />\r\n ) : (datasetsError ? (\r\n <div className=\"flex flex-col justify-center items-center h-32 text-muted-foreground\">\r\n <LR.AlertCircle className=\"h-6 w-6 mb-2\" />\r\n <span>{datasetsError}</span>\r\n <Button variant=\"outline\" size=\"sm\" onClick={() => window.location.reload()} className=\"mt-2\">\r\n <LR.RefreshCw className=\"h-4 w-4 mr-2\" />\r\n {t('refreshButton')}\r\n </Button>\r\n </div>\r\n ) : (\r\n <DataTable\r\n showPagination={true}\r\n columns={datasetColumns}\r\n data={sortedFilteredData}\r\n tab={currentTab}\r\n onRowClick={handleRowClick}\r\n onRowHover={handleRowHover}\r\n className=\"rounded-none w-auto h-full\" \r\n paginationClasses=\"bg-background z-20 w-full border-t\" \r\n isLoading={currentTabLoading}\r\n leadingCell={props => (\r\n <RowActions\r\n {...props}\r\n favouriteDatasets={favouriteDatasets}\r\n setFavouriteDatasets={setFavouriteDatasets}\r\n martinBaseUrl={martinBaseUrl}\r\n />\r\n )}\r\n trailingCell={({ row, index }) => (\r\n <div>\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className=\"pointer-events-none\"\r\n >\r\n <LR.ChevronRight />\r\n </Button>\r\n </div>\r\n )}\r\n />\r\n ))}\r\n </TabsContent>\r\n </Tabs>\r\n </div>\r\n </>\r\n ) : (\r\n // Detail View Content\r\n <>\r\n <DialogHeader className=\"px-6 pt-6\">\r\n <div>\r\n <Breadcrumb>\r\n <BreadcrumbList>\r\n <BreadcrumbItem>\r\n <BreadcrumbLink\r\n href=\"#\"\r\n onClick={() => {\r\n handleBackToTable()\r\n setCurrentTab('all')\r\n }}\r\n >\r\n {t('breadcrumbTitle')}\r\n </BreadcrumbLink>\r\n </BreadcrumbItem>\r\n <BreadcrumbSeparator />\r\n <BreadcrumbItem>\r\n <BreadcrumbLink\r\n href=\"#\"\r\n onClick={() => {\r\n setCurrentTab(currentTab)\r\n handleBackToTable()\r\n }}\r\n >\r\n {currentTab.charAt(0).toUpperCase() + currentTab.slice(1)}\r\n </BreadcrumbLink>\r\n </BreadcrumbItem>\r\n <BreadcrumbSeparator />\r\n <BreadcrumbItem>\r\n <BreadcrumbPage>{selectedDataset?.name}</BreadcrumbPage>\r\n </BreadcrumbItem>\r\n </BreadcrumbList>\r\n </Breadcrumb>\r\n </div>\r\n <div className=\"flex flex-row justify-between\">\r\n <div className=\"flex items-center\">\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n className={`opacity-70 hover:opacity-100 transition-opacity duration-200 hover:bg-transparent ${selectedDataset && favouriteDatasets.includes(selectedDataset) ? 'opacity-100' : ''}`}\r\n onClick={handleFavourite}\r\n >\r\n <LR.Star\r\n className=\"!h-5 !w-5\"\r\n size={24}\r\n color={`${selectedDataset && favouriteDatasets.includes(selectedDataset) ? 'hsl(var(--chart-5))' : 'black'} `}\r\n fill={`${selectedDataset && favouriteDatasets.includes(selectedDataset) ? 'hsl(var(--chart-5))' : 'none'} `}\r\n />\r\n </Button>\r\n <DialogTitle>{selectedDataset?.name}</DialogTitle>\r\n </div>\r\n <div className=\"flex gap-2\">\r\n <Button\r\n variant=\"secondary\"\r\n onClick={handleBackToTable}\r\n >\r\n <LR.ArrowLeft />\r\n {t('backToDataButton')}\r\n </Button>\r\n {selectedDataset && addedDatasets.some(d => d.name === selectedDataset.name)\r\n ? (\r\n <Button onClick={handleRemoveDatasetFromMap} disabled={!ability.can('read', 'File')}>\r\n <LR.Minus />\r\n {t('removeButton')}\r\n </Button>\r\n )\r\n : (\r\n <Button onClick={handleAddDatasetToMap} disabled={!ability.can('read', 'File')}>\r\n <LR.Plus />\r\n {t('applyButton')}\r\n </Button>\r\n )}\r\n </div>\r\n </div>\r\n </DialogHeader>\r\n <DatasetDetails selectedDataset={selectedDataset} />\r\n </>\r\n )}\r\n </DialogContent>\r\n <AddPortalDialog open={isAddPortalOpen} onOpenChange={setIsAddPortalOpen} />\r\n </Dialog>\r\n )\r\n}\r\n"],"mappings":"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","names":["_a","_b"]}
|
|
@@ -3,7 +3,9 @@ interface GeocoderProps {
|
|
|
3
3
|
onSelect?: (addressData: any) => void;
|
|
4
4
|
showDatabaseBuildings?: boolean;
|
|
5
5
|
alwaysExpanded?: boolean;
|
|
6
|
+
geocodeEarthApiKey?: string;
|
|
7
|
+
geocoderUrl?: string;
|
|
6
8
|
}
|
|
7
|
-
export default function Geocoder({ onSelect, showDatabaseBuildings, alwaysExpanded, }: GeocoderProps): React.JSX.Element;
|
|
9
|
+
export default function Geocoder({ onSelect, showDatabaseBuildings, alwaysExpanded, geocodeEarthApiKey, geocoderUrl, }: GeocoderProps): React.JSX.Element;
|
|
8
10
|
export {};
|
|
9
11
|
//# sourceMappingURL=Geocoder.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Geocoder.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/map/src/Geocoder.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"Geocoder.d.ts","sourceRoot":"","sources":["../../../../../../src/core/components/viewers/map/src/Geocoder.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AA0B9B,UAAU,aAAa;IACrB,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,KAAK,IAAI,CAAA;IACrC,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,CAAC,OAAO,UAAU,QAAQ,CAAC,EAC/B,QAAQ,EACR,qBAA4B,EAC5B,cAAsB,EACtB,kBAAkB,EAClB,WAAW,GACZ,EAAE,aAAa,qBA4Rf"}
|
|
@@ -31,11 +31,15 @@ import { Search } from "lucide-react";
|
|
|
31
31
|
import { useBuildings } from "../../../../hooks/buildings/buildings";
|
|
32
32
|
import { usePathname } from "next/navigation";
|
|
33
33
|
import { LoadingSpinner } from "../../../ui/LoadingSpinner";
|
|
34
|
+
import { useGeocodingRuntimeConfig } from "../../../../hooks/useGeocodingRuntimeConfig";
|
|
34
35
|
function Geocoder({
|
|
35
36
|
onSelect,
|
|
36
37
|
showDatabaseBuildings = true,
|
|
37
|
-
alwaysExpanded = false
|
|
38
|
+
alwaysExpanded = false,
|
|
39
|
+
geocodeEarthApiKey,
|
|
40
|
+
geocoderUrl
|
|
38
41
|
}) {
|
|
42
|
+
useGeocodingRuntimeConfig({ geocodeEarthApiKey, geocoderUrl });
|
|
39
43
|
const t = useTranslations("Geocoder");
|
|
40
44
|
const [address, setAddress] = React.useState("");
|
|
41
45
|
const [query, setQuery] = React.useState("");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../src/core/components/viewers/map/src/Geocoder.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Dependencies\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\n\r\n// Context\r\nimport { MapContext } from '../../../../store'\r\n\r\n// Utility functions\r\nimport { fetchSuggestions, parseLocation, handleLocationSelect, buildingToFeature } from '../utils/geocoder'\r\n\r\n// Import the shadcn components\r\nimport { Command, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator } from '../../../ui/Command'\r\nimport { Button } from '../../../ui/Button'\r\nimport { Input } from '../../../ui/Input'\r\nimport { Separator } from '../../../ui/Separator'\r\n\r\n// Icons\r\nimport { Search } from 'lucide-react'\r\n\r\n// Building data hook\r\nimport { useBuildings } from '../../../../hooks/buildings/buildings'\r\n\r\nimport { usePathname } from 'next/navigation'\r\nimport type { CurrentLocation } from '../../../../types/map'\r\nimport { LoadingSpinner } from '../../../ui/LoadingSpinner'\r\n\r\ninterface GeocoderProps {\r\n onSelect?: (addressData: any) => void\r\n showDatabaseBuildings?: boolean\r\n alwaysExpanded?: boolean\r\n}\r\n\r\nexport default function Geocoder({\r\n onSelect,\r\n showDatabaseBuildings = true,\r\n alwaysExpanded = false,\r\n}: GeocoderProps) {\r\n // Translation\r\n const t = useTranslations('Geocoder')\r\n\r\n const [address, setAddress] = React.useState<string>('')\r\n const [query, setQuery] = React.useState('')\r\n const [suggestions, setSuggestions] = React.useState([])\r\n const [buildingResults, setBuildingResults] = React.useState([])\r\n const [focused, setFocused] = React.useState(alwaysExpanded)\r\n const [selectedAddress, setSelectedAddress] = React.useState(null)\r\n const [isExpanded, setIsExpanded] = React.useState(alwaysExpanded)\r\n const [loading, setLoading] = React.useState(false)\r\n\r\n const pathname = usePathname()\r\n\r\n const suggestionsRef = React.useRef(null)\r\n const inputRef = React.useRef(null)\r\n const debounceRef = React.useRef(null)\r\n\r\n const { dispatch: mapDispatch, state: mapState } = React.useContext(MapContext)\r\n const { map, currentLocation, organizationCountry } = mapState.map\r\n\r\n // Fetch buildings data from API only if showDatabaseBuildings is true\r\n const { buildings, isLoading: isBuildingsLoading } = useBuildings()\r\n\r\n // Filter buildings based on search query\r\n const filterBuildings = React.useCallback((searchQuery) => {\r\n if (!showDatabaseBuildings || !buildings || !searchQuery || searchQuery.length < 3) return []\r\n\r\n const lowerQuery = searchQuery.toLowerCase()\r\n\r\n if (Array.isArray(buildings) && buildings.length > 0) {\r\n return buildings.filter((building) => {\r\n return (\r\n (building.buildingName && building.buildingName.toLowerCase().includes(lowerQuery))\r\n || (building.buildingAddress && building.buildingAddress.toLowerCase().includes(lowerQuery))\r\n || (building.buildingMunicipality && building.buildingMunicipality.toLowerCase().includes(lowerQuery))\r\n || (building.buildingCountrySubdivision && building.buildingCountrySubdivision.toLowerCase().includes(lowerQuery))\r\n )\r\n }).slice(0, 3) // Limit to 3 results\r\n }\r\n return []\r\n }, [buildings, showDatabaseBuildings])\r\n\r\n // Debounce the API request to avoid rate limiting and excessive requests\r\n React.useEffect(() => {\r\n if (debounceRef.current) {\r\n clearTimeout(debounceRef.current)\r\n }\r\n\r\n debounceRef.current = setTimeout(async () => {\r\n if (!query || query.length < 3) {\r\n setSuggestions([])\r\n setBuildingResults([])\r\n setLoading(false)\r\n return\r\n }\r\n\r\n setLoading(true)\r\n try {\r\n // Filter buildings from our database only if enabled\r\n if (showDatabaseBuildings) {\r\n const filteredBuildings = filterBuildings(query)\r\n setBuildingResults(filteredBuildings)\r\n }\r\n\r\n // Fetch geocoding suggestions\r\n const geocodeResults = await fetchSuggestions(query, organizationCountry)\r\n \r\n // Deduplicate geocode results based on name and region\r\n const deduplicatedResults = geocodeResults.reduce((acc, feature) => {\r\n const location = parseLocation(feature)\r\n // Create a unique key based on name and region (case-insensitive)\r\n const key = `${location.name?.toLowerCase() || ''}_${location.region?.toLowerCase() || ''}`\r\n \r\n // Only add if we haven't seen this combination before\r\n if (!acc.seen.has(key)) {\r\n acc.seen.add(key)\r\n acc.features.push(feature)\r\n }\r\n \r\n return acc\r\n }, { seen: new Set(), features: [] })\r\n \r\n setSuggestions(deduplicatedResults.features)\r\n }\r\n catch (error) {\r\n console.error('Error fetching suggestions:', error)\r\n setSuggestions([])\r\n }\r\n finally {\r\n setLoading(false)\r\n }\r\n }, 300) // Increased debounce time for better API rate limiting\r\n\r\n return () => {\r\n if (debounceRef.current) clearTimeout(debounceRef.current)\r\n }\r\n }, [query, filterBuildings, showDatabaseBuildings])\r\n\r\n // Handle click outside to close suggestions\r\n React.useEffect(() => {\r\n const handleClickOutside = (event) => {\r\n if (suggestionsRef.current && !suggestionsRef.current.contains(event.target)\r\n && inputRef.current && !inputRef.current.contains(event.target) // Don't close if alwaysExpanded is true\r\n && !alwaysExpanded) {\r\n setFocused(false)\r\n }\r\n }\r\n\r\n document.addEventListener('mousedown', handleClickOutside)\r\n return () => {\r\n document.removeEventListener('mousedown', handleClickOutside)\r\n }\r\n }, [alwaysExpanded])\r\n\r\n // Handle suggestion selection\r\n const handleSelectSuggestion = (feature, type = '') => {\r\n setQuery('') // Clear the input field\r\n setSuggestions([])\r\n setBuildingResults([])\r\n if (!alwaysExpanded) {\r\n setFocused(false)\r\n }\r\n\r\n // handleLocationSelect will automatically remove any existing marker and add a new one\r\n const addressData = handleLocationSelect(feature, map, type)\r\n\r\n const address = addressData.formatted_address || feature.properties?.label || ''\r\n setAddress(address)\r\n setSelectedAddress(addressData)\r\n\r\n if (onSelect) onSelect(addressData)\r\n\r\n if (mapDispatch && currentLocation) {\r\n const [lng, lat] = addressData.coordinates\r\n const props = addressData.properties || {}\r\n const parts = address.split(',').map(p => p.trim())\r\n // Read structured properties (provider-agnostic) instead of parsing label tokens,\r\n // which only matched Geocode Earth's \"…, ON, Canada\" abbreviation format and broke\r\n // on the Photon/Nominatim fallback.\r\n const countrySubdivision: string = props.region_a || props.region || ''\r\n const municipality: string = props.locality || props.neighbourhood || props.county || ''\r\n\r\n const newCurrentLocation: CurrentLocation = { ...currentLocation, municipality, countrySubdivision, longitude: lng, latitude: lat, address: parts[0] }\r\n mapDispatch({ type: 'UPDATE_LOCATION', payload: { currentLocation: newCurrentLocation } })\r\n if (municipality || countrySubdivision) {\r\n const url = new URL(window.location.href)\r\n // Write each field only when present, so an empty param doesn't shadow the\r\n // organization fallback MapViewer applies on reload.\r\n if (municipality) url.searchParams.set('municipality', municipality)\r\n else url.searchParams.delete('municipality')\r\n if (countrySubdivision) url.searchParams.set('countrySubdivision', countrySubdivision)\r\n else url.searchParams.delete('countrySubdivision')\r\n url.searchParams.set('address', parts[0])\r\n url.searchParams.set('lng', lng.toString())\r\n url.searchParams.set('lat', lat.toString())\r\n url.searchParams.set('zoom', '18')\r\n window.history.replaceState({}, '', url.toString())\r\n }\r\n }\r\n }\r\n\r\n // Handle expand of menubar to display search input\r\n const handleExpand = () => {\r\n if (alwaysExpanded) return // Don't allow toggling if always expanded\r\n\r\n setIsExpanded(!isExpanded)\r\n if (isExpanded) {\r\n setFocused(false)\r\n setQuery('') // clear input and suggestions when collapsed\r\n setSuggestions([])\r\n setBuildingResults([])\r\n }\r\n else {\r\n setFocused(true)\r\n setTimeout(() => {\r\n inputRef.current?.focus()\r\n }, 100) // Small delay to ensure the input is rendered\r\n }\r\n }\r\n\r\n return (\r\n <Command>\r\n {/* Search input + button */}\r\n <div className={`flex flex-row justify-start items-center w-full h-auto `}>\r\n {!alwaysExpanded && (\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n onClick={handleExpand}\r\n className=\"opacity-70 w-6 justify-end hover:opacity-100 transition-opacity duration-200 hover:bg-transparent\"\r\n >\r\n <Search />\r\n </Button>\r\n )}\r\n {alwaysExpanded && (\r\n <Search className=\"h-4 w-4 opacity-50\" />\r\n )}\r\n <Input\r\n ref={inputRef}\r\n type=\"text\"\r\n value={query}\r\n onChange={e => setQuery(e.target.value)}\r\n onFocus={() => setFocused(true)}\r\n onKeyDown={(e) => {\r\n if (e.key === 'Enter') {\r\n inputRef.current?.blur()\r\n }\r\n }}\r\n placeholder={alwaysExpanded ? t('placeholder1') : t('placeholder2')}\r\n className={`border-none focus-visible:ring-transparent text-sm transition-all ease-in-out duration-200 ${\r\n alwaysExpanded || isExpanded ? 'w-full' : 'w-0 p-0'\r\n }`}\r\n />\r\n </div>\r\n\r\n {focused && (loading || buildingResults.length > 0 || suggestions.length > 0) && (\r\n <div ref={suggestionsRef}>\r\n <Separator />\r\n <CommandList>\r\n {!loading && buildingResults.length === 0 && suggestions.length === 0 && query.length >= 3 && (\r\n <CommandEmpty>{showDatabaseBuildings ? t('noResults') : t('noAddresses')}</CommandEmpty>\r\n )}\r\n\r\n {loading && (\r\n <CommandEmpty><LoadingSpinner /></CommandEmpty>\r\n )}\r\n\r\n {/* Database Buildings section - only show if enabled */}\r\n {showDatabaseBuildings && !loading && buildingResults.length > 0 && (\r\n <CommandGroup heading={t('buildingHeader')}>\r\n {buildingResults.map((building) => {\r\n const buildingFeature = buildingToFeature(building)\r\n\r\n return (\r\n <CommandItem\r\n key={`building-${building.id}`}\r\n onSelect={() => handleSelectSuggestion(buildingFeature, 'dbBuilding')}\r\n className=\"cursor-pointer\"\r\n >\r\n <div className=\"font-medium\">{building.buildingName}</div>\r\n <div className=\"text-sm text-muted-foreground\">\r\n {building.buildingAddress}\r\n </div>\r\n </CommandItem>\r\n )\r\n })}\r\n </CommandGroup>\r\n )}\r\n\r\n {/* Separator between sections if both have results */}\r\n {showDatabaseBuildings && buildingResults.length > 0 && suggestions.length > 0 && (\r\n <CommandSeparator />\r\n )}\r\n\r\n {/* Geocoder suggestions section */}\r\n {!loading && suggestions.length > 0 && (\r\n <CommandGroup heading={showDatabaseBuildings ? t('suggestionsHeader') : undefined}>\r\n {suggestions.map((feature) => {\r\n const location = parseLocation(feature)\r\n const uniqueKey = feature.properties?.gid\r\n || `${feature.properties?.name}-${feature.geometry?.coordinates?.[0]}-${feature.geometry?.coordinates?.[1]}`\r\n\r\n return (\r\n <CommandItem\r\n key={uniqueKey}\r\n onSelect={() => handleSelectSuggestion(feature)}\r\n className=\"cursor-pointer\"\r\n >\r\n <div className=\"font-medium\">{location.name}</div>\r\n <div className=\"text-sm text-muted-foreground\">{location.region}</div>\r\n </CommandItem>\r\n )\r\n })}\r\n </CommandGroup>\r\n )}\r\n </CommandList>\r\n </div>\r\n )}\r\n </Command>\r\n )\r\n}"],"mappings":"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","names":["address"]}
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/core/components/viewers/map/src/Geocoder.tsx"],"sourcesContent":["'use client'\r\n\r\n// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n// Dependencies\r\nimport * as React from 'react'\r\nimport { useTranslations } from 'next-intl'\r\n\r\n// Context\r\nimport { MapContext } from '../../../../store'\r\n\r\n// Utility functions\r\nimport { fetchSuggestions, parseLocation, handleLocationSelect, buildingToFeature } from '../utils/geocoder'\r\n\r\n// Import the shadcn components\r\nimport { Command, CommandList, CommandEmpty, CommandGroup, CommandItem, CommandSeparator } from '../../../ui/Command'\r\nimport { Button } from '../../../ui/Button'\r\nimport { Input } from '../../../ui/Input'\r\nimport { Separator } from '../../../ui/Separator'\r\n\r\n// Icons\r\nimport { Search } from 'lucide-react'\r\n\r\n// Building data hook\r\nimport { useBuildings } from '../../../../hooks/buildings/buildings'\r\n\r\nimport { usePathname } from 'next/navigation'\r\nimport type { CurrentLocation } from '../../../../types/map'\r\nimport { LoadingSpinner } from '../../../ui/LoadingSpinner'\r\nimport { useGeocodingRuntimeConfig } from '../../../../hooks/useGeocodingRuntimeConfig'\r\n\r\ninterface GeocoderProps {\r\n onSelect?: (addressData: any) => void\r\n showDatabaseBuildings?: boolean\r\n alwaysExpanded?: boolean\r\n geocodeEarthApiKey?: string\r\n geocoderUrl?: string\r\n}\r\n\r\nexport default function Geocoder({\r\n onSelect,\r\n showDatabaseBuildings = true,\r\n alwaysExpanded = false,\r\n geocodeEarthApiKey,\r\n geocoderUrl,\r\n}: GeocoderProps) {\r\n useGeocodingRuntimeConfig({ geocodeEarthApiKey, geocoderUrl })\r\n\r\n // Translation\r\n const t = useTranslations('Geocoder')\r\n\r\n const [address, setAddress] = React.useState<string>('')\r\n const [query, setQuery] = React.useState('')\r\n const [suggestions, setSuggestions] = React.useState([])\r\n const [buildingResults, setBuildingResults] = React.useState([])\r\n const [focused, setFocused] = React.useState(alwaysExpanded)\r\n const [selectedAddress, setSelectedAddress] = React.useState(null)\r\n const [isExpanded, setIsExpanded] = React.useState(alwaysExpanded)\r\n const [loading, setLoading] = React.useState(false)\r\n\r\n const pathname = usePathname()\r\n\r\n const suggestionsRef = React.useRef(null)\r\n const inputRef = React.useRef(null)\r\n const debounceRef = React.useRef(null)\r\n\r\n const { dispatch: mapDispatch, state: mapState } = React.useContext(MapContext)\r\n const { map, currentLocation, organizationCountry } = mapState.map\r\n\r\n // Fetch buildings data from API only if showDatabaseBuildings is true\r\n const { buildings, isLoading: isBuildingsLoading } = useBuildings()\r\n\r\n // Filter buildings based on search query\r\n const filterBuildings = React.useCallback((searchQuery) => {\r\n if (!showDatabaseBuildings || !buildings || !searchQuery || searchQuery.length < 3) return []\r\n\r\n const lowerQuery = searchQuery.toLowerCase()\r\n\r\n if (Array.isArray(buildings) && buildings.length > 0) {\r\n return buildings.filter((building) => {\r\n return (\r\n (building.buildingName && building.buildingName.toLowerCase().includes(lowerQuery))\r\n || (building.buildingAddress && building.buildingAddress.toLowerCase().includes(lowerQuery))\r\n || (building.buildingMunicipality && building.buildingMunicipality.toLowerCase().includes(lowerQuery))\r\n || (building.buildingCountrySubdivision && building.buildingCountrySubdivision.toLowerCase().includes(lowerQuery))\r\n )\r\n }).slice(0, 3) // Limit to 3 results\r\n }\r\n return []\r\n }, [buildings, showDatabaseBuildings])\r\n\r\n // Debounce the API request to avoid rate limiting and excessive requests\r\n React.useEffect(() => {\r\n if (debounceRef.current) {\r\n clearTimeout(debounceRef.current)\r\n }\r\n\r\n debounceRef.current = setTimeout(async () => {\r\n if (!query || query.length < 3) {\r\n setSuggestions([])\r\n setBuildingResults([])\r\n setLoading(false)\r\n return\r\n }\r\n\r\n setLoading(true)\r\n try {\r\n // Filter buildings from our database only if enabled\r\n if (showDatabaseBuildings) {\r\n const filteredBuildings = filterBuildings(query)\r\n setBuildingResults(filteredBuildings)\r\n }\r\n\r\n // Fetch geocoding suggestions\r\n const geocodeResults = await fetchSuggestions(query, organizationCountry)\r\n \r\n // Deduplicate geocode results based on name and region\r\n const deduplicatedResults = geocodeResults.reduce((acc, feature) => {\r\n const location = parseLocation(feature)\r\n // Create a unique key based on name and region (case-insensitive)\r\n const key = `${location.name?.toLowerCase() || ''}_${location.region?.toLowerCase() || ''}`\r\n \r\n // Only add if we haven't seen this combination before\r\n if (!acc.seen.has(key)) {\r\n acc.seen.add(key)\r\n acc.features.push(feature)\r\n }\r\n \r\n return acc\r\n }, { seen: new Set(), features: [] })\r\n \r\n setSuggestions(deduplicatedResults.features)\r\n }\r\n catch (error) {\r\n console.error('Error fetching suggestions:', error)\r\n setSuggestions([])\r\n }\r\n finally {\r\n setLoading(false)\r\n }\r\n }, 300) // Increased debounce time for better API rate limiting\r\n\r\n return () => {\r\n if (debounceRef.current) clearTimeout(debounceRef.current)\r\n }\r\n }, [query, filterBuildings, showDatabaseBuildings])\r\n\r\n // Handle click outside to close suggestions\r\n React.useEffect(() => {\r\n const handleClickOutside = (event) => {\r\n if (suggestionsRef.current && !suggestionsRef.current.contains(event.target)\r\n && inputRef.current && !inputRef.current.contains(event.target) // Don't close if alwaysExpanded is true\r\n && !alwaysExpanded) {\r\n setFocused(false)\r\n }\r\n }\r\n\r\n document.addEventListener('mousedown', handleClickOutside)\r\n return () => {\r\n document.removeEventListener('mousedown', handleClickOutside)\r\n }\r\n }, [alwaysExpanded])\r\n\r\n // Handle suggestion selection\r\n const handleSelectSuggestion = (feature, type = '') => {\r\n setQuery('') // Clear the input field\r\n setSuggestions([])\r\n setBuildingResults([])\r\n if (!alwaysExpanded) {\r\n setFocused(false)\r\n }\r\n\r\n // handleLocationSelect will automatically remove any existing marker and add a new one\r\n const addressData = handleLocationSelect(feature, map, type)\r\n\r\n const address = addressData.formatted_address || feature.properties?.label || ''\r\n setAddress(address)\r\n setSelectedAddress(addressData)\r\n\r\n if (onSelect) onSelect(addressData)\r\n\r\n if (mapDispatch && currentLocation) {\r\n const [lng, lat] = addressData.coordinates\r\n const props = addressData.properties || {}\r\n const parts = address.split(',').map(p => p.trim())\r\n // Read structured properties (provider-agnostic) instead of parsing label tokens,\r\n // which only matched Geocode Earth's \"…, ON, Canada\" abbreviation format and broke\r\n // on the Photon/Nominatim fallback.\r\n const countrySubdivision: string = props.region_a || props.region || ''\r\n const municipality: string = props.locality || props.neighbourhood || props.county || ''\r\n\r\n const newCurrentLocation: CurrentLocation = { ...currentLocation, municipality, countrySubdivision, longitude: lng, latitude: lat, address: parts[0] }\r\n mapDispatch({ type: 'UPDATE_LOCATION', payload: { currentLocation: newCurrentLocation } })\r\n if (municipality || countrySubdivision) {\r\n const url = new URL(window.location.href)\r\n // Write each field only when present, so an empty param doesn't shadow the\r\n // organization fallback MapViewer applies on reload.\r\n if (municipality) url.searchParams.set('municipality', municipality)\r\n else url.searchParams.delete('municipality')\r\n if (countrySubdivision) url.searchParams.set('countrySubdivision', countrySubdivision)\r\n else url.searchParams.delete('countrySubdivision')\r\n url.searchParams.set('address', parts[0])\r\n url.searchParams.set('lng', lng.toString())\r\n url.searchParams.set('lat', lat.toString())\r\n url.searchParams.set('zoom', '18')\r\n window.history.replaceState({}, '', url.toString())\r\n }\r\n }\r\n }\r\n\r\n // Handle expand of menubar to display search input\r\n const handleExpand = () => {\r\n if (alwaysExpanded) return // Don't allow toggling if always expanded\r\n\r\n setIsExpanded(!isExpanded)\r\n if (isExpanded) {\r\n setFocused(false)\r\n setQuery('') // clear input and suggestions when collapsed\r\n setSuggestions([])\r\n setBuildingResults([])\r\n }\r\n else {\r\n setFocused(true)\r\n setTimeout(() => {\r\n inputRef.current?.focus()\r\n }, 100) // Small delay to ensure the input is rendered\r\n }\r\n }\r\n\r\n return (\r\n <Command>\r\n {/* Search input + button */}\r\n <div className={`flex flex-row justify-start items-center w-full h-auto `}>\r\n {!alwaysExpanded && (\r\n <Button\r\n variant=\"ghost\"\r\n size=\"icon\"\r\n onClick={handleExpand}\r\n className=\"opacity-70 w-6 justify-end hover:opacity-100 transition-opacity duration-200 hover:bg-transparent\"\r\n >\r\n <Search />\r\n </Button>\r\n )}\r\n {alwaysExpanded && (\r\n <Search className=\"h-4 w-4 opacity-50\" />\r\n )}\r\n <Input\r\n ref={inputRef}\r\n type=\"text\"\r\n value={query}\r\n onChange={e => setQuery(e.target.value)}\r\n onFocus={() => setFocused(true)}\r\n onKeyDown={(e) => {\r\n if (e.key === 'Enter') {\r\n inputRef.current?.blur()\r\n }\r\n }}\r\n placeholder={alwaysExpanded ? t('placeholder1') : t('placeholder2')}\r\n className={`border-none focus-visible:ring-transparent text-sm transition-all ease-in-out duration-200 ${\r\n alwaysExpanded || isExpanded ? 'w-full' : 'w-0 p-0'\r\n }`}\r\n />\r\n </div>\r\n\r\n {focused && (loading || buildingResults.length > 0 || suggestions.length > 0) && (\r\n <div ref={suggestionsRef}>\r\n <Separator />\r\n <CommandList>\r\n {!loading && buildingResults.length === 0 && suggestions.length === 0 && query.length >= 3 && (\r\n <CommandEmpty>{showDatabaseBuildings ? t('noResults') : t('noAddresses')}</CommandEmpty>\r\n )}\r\n\r\n {loading && (\r\n <CommandEmpty><LoadingSpinner /></CommandEmpty>\r\n )}\r\n\r\n {/* Database Buildings section - only show if enabled */}\r\n {showDatabaseBuildings && !loading && buildingResults.length > 0 && (\r\n <CommandGroup heading={t('buildingHeader')}>\r\n {buildingResults.map((building) => {\r\n const buildingFeature = buildingToFeature(building)\r\n\r\n return (\r\n <CommandItem\r\n key={`building-${building.id}`}\r\n onSelect={() => handleSelectSuggestion(buildingFeature, 'dbBuilding')}\r\n className=\"cursor-pointer\"\r\n >\r\n <div className=\"font-medium\">{building.buildingName}</div>\r\n <div className=\"text-sm text-muted-foreground\">\r\n {building.buildingAddress}\r\n </div>\r\n </CommandItem>\r\n )\r\n })}\r\n </CommandGroup>\r\n )}\r\n\r\n {/* Separator between sections if both have results */}\r\n {showDatabaseBuildings && buildingResults.length > 0 && suggestions.length > 0 && (\r\n <CommandSeparator />\r\n )}\r\n\r\n {/* Geocoder suggestions section */}\r\n {!loading && suggestions.length > 0 && (\r\n <CommandGroup heading={showDatabaseBuildings ? t('suggestionsHeader') : undefined}>\r\n {suggestions.map((feature) => {\r\n const location = parseLocation(feature)\r\n const uniqueKey = feature.properties?.gid\r\n || `${feature.properties?.name}-${feature.geometry?.coordinates?.[0]}-${feature.geometry?.coordinates?.[1]}`\r\n\r\n return (\r\n <CommandItem\r\n key={uniqueKey}\r\n onSelect={() => handleSelectSuggestion(feature)}\r\n className=\"cursor-pointer\"\r\n >\r\n <div className=\"font-medium\">{location.name}</div>\r\n <div className=\"text-sm text-muted-foreground\">{location.region}</div>\r\n </CommandItem>\r\n )\r\n })}\r\n </CommandGroup>\r\n )}\r\n </CommandList>\r\n </div>\r\n )}\r\n </Command>\r\n )\r\n}"],"mappings":"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","names":["address"]}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
|
|
2
|
+
import type { Organization } from '../../../../../types/dbTypes';
|
|
3
|
+
export declare const MapLayers: ({ minioBaseUrl, organization, maptilerKey }: {
|
|
4
|
+
minioBaseUrl?: string;
|
|
5
|
+
organization?: Organization;
|
|
6
|
+
maptilerKey?: string;
|
|
7
|
+
}) => React.JSX.Element;
|
|
3
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/src/MapLayers/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../src/core/components/viewers/map/src/MapLayers/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAU9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAahE,eAAO,MAAM,SAAS,GAAI,6CAA6C;IAAE,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,YAAY,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,sBAYlJ,CAAA"}
|
|
@@ -17,13 +17,13 @@ function BimLayerGate() {
|
|
|
17
17
|
if (bimState.bim.bimModelsAddedToMap.length === 0) return null;
|
|
18
18
|
return /* @__PURE__ */ jsx(LazyBimLayer, {});
|
|
19
19
|
}
|
|
20
|
-
const MapLayers = () => {
|
|
20
|
+
const MapLayers = ({ minioBaseUrl, organization, maptilerKey }) => {
|
|
21
21
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
22
|
-
/* @__PURE__ */ jsx(CountryLayer, {}),
|
|
22
|
+
/* @__PURE__ */ jsx(CountryLayer, { organization, maptilerKey }),
|
|
23
23
|
/* @__PURE__ */ jsx(OpenDataLayers, {}),
|
|
24
24
|
/* @__PURE__ */ jsx(BuildingLayer, {}),
|
|
25
25
|
/* @__PURE__ */ jsx(CommentLayer, {}),
|
|
26
|
-
/* @__PURE__ */ jsx(SensorLayers, {}),
|
|
26
|
+
/* @__PURE__ */ jsx(SensorLayers, { minioBaseUrl }),
|
|
27
27
|
/* @__PURE__ */ jsx(FileLayers, {}),
|
|
28
28
|
/* @__PURE__ */ jsx(BimLayerGate, {})
|
|
29
29
|
] });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../src/core/components/viewers/map/src/MapLayers/index.tsx"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n'use client'\r\n\r\nimport * as React from 'react'\r\nimport dynamic from 'next/dynamic'\r\n\r\nimport { CountryLayer } from './src/CountryLayer'\r\nimport { CommentLayer } from './src/CommentLayer'\r\nimport { SensorLayers } from './src/SensorsLayer'\r\nimport { FileLayers } from './src/FileLayer'\r\nimport { OpenDataLayers } from './src/OpenDataLayer/src'\r\nimport { BuildingLayer } from './src/BuildingLayers'\r\nimport { useBimContext } from '../../../../../store'\r\n\r\nconst LazyBimLayer = dynamic(\r\n () => import('./src/BimLayer').then(m => ({ default: m.BimLayer })),\r\n { ssr: false },\r\n)\r\n\r\nfunction BimLayerGate() {\r\n const { state: bimState } = useBimContext()\r\n if (bimState.bim.bimModelsAddedToMap.length === 0) return null\r\n return <LazyBimLayer />\r\n}\r\n\r\nexport const MapLayers = () => {\r\n return (\r\n <>\r\n <CountryLayer />\r\n <OpenDataLayers />\r\n <BuildingLayer />\r\n <CommentLayer />\r\n <SensorLayers />\r\n <FileLayers />\r\n <BimLayerGate />\r\n </>\r\n )\r\n}\r\n"],"mappings":";
|
|
1
|
+
{"version":3,"sources":["../../../../../../../src/core/components/viewers/map/src/MapLayers/index.tsx"],"sourcesContent":["// SPDX-License-Identifier: AGPL-3.0-or-later\r\n// Copyright (C) 2025 Collab Digital Twins\r\n\r\n'use client'\r\n\r\nimport * as React from 'react'\r\nimport dynamic from 'next/dynamic'\r\n\r\nimport { CountryLayer } from './src/CountryLayer'\r\nimport { CommentLayer } from './src/CommentLayer'\r\nimport { SensorLayers } from './src/SensorsLayer'\r\nimport { FileLayers } from './src/FileLayer'\r\nimport { OpenDataLayers } from './src/OpenDataLayer/src'\r\nimport { BuildingLayer } from './src/BuildingLayers'\r\nimport { useBimContext } from '../../../../../store'\r\nimport type { Organization } from '../../../../../types/dbTypes'\r\n\r\nconst LazyBimLayer = dynamic(\r\n () => import('./src/BimLayer').then(m => ({ default: m.BimLayer })),\r\n { ssr: false },\r\n)\r\n\r\nfunction BimLayerGate() {\r\n const { state: bimState } = useBimContext()\r\n if (bimState.bim.bimModelsAddedToMap.length === 0) return null\r\n return <LazyBimLayer />\r\n}\r\n\r\nexport const MapLayers = ({ minioBaseUrl, organization, maptilerKey }: { minioBaseUrl?: string; organization?: Organization; maptilerKey?: string }) => {\r\n return (\r\n <>\r\n <CountryLayer organization={organization} maptilerKey={maptilerKey} />\r\n <OpenDataLayers />\r\n <BuildingLayer />\r\n <CommentLayer />\r\n <SensorLayers minioBaseUrl={minioBaseUrl} />\r\n <FileLayers />\r\n <BimLayerGate />\r\n </>\r\n )\r\n}\r\n"],"mappings":";AAyBS,SAKL,UALK,KAKL,YALK;AAnBT,OAAO,aAAa;AAEpB,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,kBAAkB;AAC3B,SAAS,sBAAsB;AAC/B,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAG9B,MAAM,eAAe;AAAA,EACnB,MAAM,OAAO,gBAAgB,EAAE,KAAK,QAAM,EAAE,SAAS,EAAE,SAAS,EAAE;AAAA,EAClE,EAAE,KAAK,MAAM;AACf;AAEA,SAAS,eAAe;AACtB,QAAM,EAAE,OAAO,SAAS,IAAI,cAAc;AAC1C,MAAI,SAAS,IAAI,oBAAoB,WAAW,EAAG,QAAO;AAC1D,SAAO,oBAAC,gBAAa;AACvB;AAEO,MAAM,YAAY,CAAC,EAAE,cAAc,cAAc,YAAY,MAAoF;AACtJ,SACE,iCACE;AAAA,wBAAC,gBAAa,cAA4B,aAA0B;AAAA,IACpE,oBAAC,kBAAe;AAAA,IAChB,oBAAC,iBAAc;AAAA,IACf,oBAAC,gBAAa;AAAA,IACd,oBAAC,gBAAa,cAA4B;AAAA,IAC1C,oBAAC,cAAW;AAAA,IACZ,oBAAC,gBAAa;AAAA,KAChB;AAEJ;","names":[]}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
|
|
2
|
+
import type { Organization } from '../../../../../../../types/dbTypes';
|
|
3
|
+
export declare const CountryLayer: ({ organization, maptilerKey }: {
|
|
4
|
+
organization?: Organization;
|
|
5
|
+
maptilerKey?: string;
|
|
6
|
+
}) => React.JSX.Element;
|
|
3
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../../../../src/core/components/viewers/map/src/MapLayers/src/CountryLayer/index.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAM9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAA;AAyItE,eAAO,MAAM,YAAY,GAAI,+BAA+B;IAAE,YAAY,CAAC,EAAE,YAAY,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,sBA0IhH,CAAA"}
|
|
@@ -22,13 +22,10 @@ import { jsx } from "react/jsx-runtime";
|
|
|
22
22
|
import * as React from "react";
|
|
23
23
|
import { Source, Layer } from "react-map-gl/maplibre";
|
|
24
24
|
import { MapContext } from "../../../../../../../store/Map/context";
|
|
25
|
-
import { useAppConfigContext } from "../../../../../../../store/AppConfig/context";
|
|
26
25
|
import { useSearchParams, useRouter } from "next/navigation";
|
|
27
26
|
import { hexToRgba, buildSubdivisionUrl } from "./countryLayerUtils";
|
|
28
27
|
const DEFAULT_BORDER_COLOR = "#73cee2";
|
|
29
28
|
const BOUNDARIES_SOURCE_ID = "openmaptiles-boundaries";
|
|
30
|
-
const MAPTILER_KEY = process.env.NEXT_PUBLIC_MAPTILER_KEY;
|
|
31
|
-
const BOUNDARIES_TILESET_URL = `https://api.maptiler.com/tiles/v3/tiles.json?key=${MAPTILER_KEY}`;
|
|
32
29
|
const GLOBAL_LAYER_IDS = [
|
|
33
30
|
"global-borders-country",
|
|
34
31
|
"global-borders-region",
|
|
@@ -36,12 +33,13 @@ const GLOBAL_LAYER_IDS = [
|
|
|
36
33
|
"global-labels-state",
|
|
37
34
|
"global-labels-city"
|
|
38
35
|
];
|
|
39
|
-
function addGlobalBorderLayer(map, color) {
|
|
36
|
+
function addGlobalBorderLayer(map, color, maptilerKey) {
|
|
37
|
+
if (!maptilerKey) return;
|
|
40
38
|
try {
|
|
41
39
|
if (!map.getSource(BOUNDARIES_SOURCE_ID)) {
|
|
42
40
|
map.addSource(BOUNDARIES_SOURCE_ID, {
|
|
43
41
|
type: "vector",
|
|
44
|
-
url:
|
|
42
|
+
url: `https://api.maptiler.com/tiles/v3/tiles.json?key=${maptilerKey}`
|
|
45
43
|
});
|
|
46
44
|
}
|
|
47
45
|
if (!map.getLayer("global-borders-country")) {
|
|
@@ -148,11 +146,9 @@ function addGlobalBorderLayer(map, color) {
|
|
|
148
146
|
} catch (e) {
|
|
149
147
|
}
|
|
150
148
|
}
|
|
151
|
-
const CountryLayer = () => {
|
|
149
|
+
const CountryLayer = ({ organization, maptilerKey }) => {
|
|
152
150
|
const { state: mapState, dispatch: mapDispatch } = React.useContext(MapContext);
|
|
153
151
|
const { map, currentLocation } = mapState.map;
|
|
154
|
-
const { state: appConfigState } = useAppConfigContext();
|
|
155
|
-
const organization = appConfigState.appConfig.organization;
|
|
156
152
|
const searchParams = useSearchParams();
|
|
157
153
|
const router = useRouter();
|
|
158
154
|
const debounceRef = React.useRef(null);
|
|
@@ -161,7 +157,7 @@ const CountryLayer = () => {
|
|
|
161
157
|
const subdivisionUrl = buildSubdivisionUrl(countryCode);
|
|
162
158
|
React.useEffect(() => {
|
|
163
159
|
if (!map) return;
|
|
164
|
-
const addNow = () => addGlobalBorderLayer(map, borderColor);
|
|
160
|
+
const addNow = () => addGlobalBorderLayer(map, borderColor, maptilerKey);
|
|
165
161
|
if (map.isStyleLoaded()) addNow();
|
|
166
162
|
map.on("styledata", addNow);
|
|
167
163
|
return () => {
|
|
@@ -173,7 +169,7 @@ const CountryLayer = () => {
|
|
|
173
169
|
} catch (e) {
|
|
174
170
|
}
|
|
175
171
|
};
|
|
176
|
-
}, [map, borderColor]);
|
|
172
|
+
}, [map, borderColor, maptilerKey]);
|
|
177
173
|
const orgHasLocation = !!((organization == null ? void 0 : organization.countrySubdivision) || (organization == null ? void 0 : organization.municipality));
|
|
178
174
|
React.useEffect(() => {
|
|
179
175
|
var _a, _b;
|