From 0875e7b1e0cd1772c3a524d9362347d81de9eb85 Mon Sep 17 00:00:00 2001 From: Tony Nguyen Le <111498490+TonyLe02@users.noreply.github.com> Date: Sun, 9 Mar 2025 18:33:46 +0100 Subject: [PATCH] Revert "Merge pull request #55 from kartverket/GEON-1679-vis-flere-dataset" This reverts commit 8f7a5e6eb34380984e77797a65cdf6b79007e67d, reversing changes made to b1e03033d150ab5c8c19ece3c4066d722e5429c8. --- geogpt/geonorge-app/app/components/Demo.tsx | 0 geonorge-app/app/components/GeoNorgeIcon.tsx | 57 --- geonorge-app/app/components/demov3.tsx | 399 +++++-------------- geonorge-app/components/app-sidebar.tsx | 299 +++----------- geonorge-app/i18n/translations.ts | 12 - 5 files changed, 160 insertions(+), 607 deletions(-) create mode 100644 geogpt/geonorge-app/app/components/Demo.tsx delete mode 100644 geonorge-app/app/components/GeoNorgeIcon.tsx diff --git a/geogpt/geonorge-app/app/components/Demo.tsx b/geogpt/geonorge-app/app/components/Demo.tsx new file mode 100644 index 0000000..e69de29 diff --git a/geonorge-app/app/components/GeoNorgeIcon.tsx b/geonorge-app/app/components/GeoNorgeIcon.tsx deleted file mode 100644 index fa819a2..0000000 --- a/geonorge-app/app/components/GeoNorgeIcon.tsx +++ /dev/null @@ -1,57 +0,0 @@ -interface GeoNorgeIconProps { - className?: string; -} - -const GeoNorgeIcon = ({ className = "w-8 h-8" }: GeoNorgeIconProps) => { - return ( - - Geonorge Icon - - - - {/* Diamond shape polygons */} - - - - - - {/* Orange circle/location marker */} - - - ); -}; - -export default GeoNorgeIcon; diff --git a/geonorge-app/app/components/demov3.tsx b/geonorge-app/app/components/demov3.tsx index e9ba411..200152c 100644 --- a/geonorge-app/app/components/demov3.tsx +++ b/geonorge-app/app/components/demov3.tsx @@ -1,14 +1,13 @@ "use client"; import { useEffect, useState, useRef, FormEvent } from "react"; -import { Maximize, MessageSquare, Send } from "lucide-react"; +import { Maximize, MessageSquare } from "lucide-react"; import Image from "next/image"; // Components import { AppSidebar } from "@/components/app-sidebar"; import { KartkatalogTab } from "@/components/kartkatalog-tab"; import FileDownloadModal from "@/app/components/FileDownloadModal/FileDownloadModal"; -import GeoNorgeIcon from "@/app/components/GeoNorgeIcon"; // Leaflet import L from "leaflet"; @@ -23,15 +22,6 @@ import { PopoverTrigger, PopoverContent, } from "@/components/ui/popover"; -import { - AlertDialog, - AlertDialogContent, - AlertDialogHeader, - AlertDialogTitle, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogAction, -} from "@/components/ui/alert-dialog"; // Utils import { @@ -94,14 +84,6 @@ export interface SearchResult { }[]; } -interface TrackedDataset { - id: string; - title: string; - wmsUrl: string; - availableLayers: WMSLayer[]; - selectedLayers: string[]; -} - const DemoV3 = () => { const [map, setMap] = useState(null); const [wmsLayer, setWmsLayer] = useState>({}); @@ -112,7 +94,9 @@ const DemoV3 = () => { const [searchMarker, setSearchMarker] = useState(null); const mapRef = useRef(null); - const [wmsUrl, setWmsUrl] = useState(""); + const [wmsUrl, setWmsUrl] = useState( + "https://nve.geodataonline.no/arcgis/services/SkredKvikkleire2/MapServer/WMSServer?request=GetCapabilities&service=WMS" + ); const [availableLayers, setAvailableLayers] = useState([]); const [selectedLayers, setSelectedLayers] = useState([]); const [currentBaseLayer, setCurrentBaseLayer] = useState( @@ -145,12 +129,6 @@ const DemoV3 = () => { // UUid to find const [uuidToFind, setUuidToFind] = useState(""); - const [trackedDatasets, setTrackedDatasets] = useState([]); - - // Add state for duplicate dataset alert - const [isDuplicateAlertOpen, setIsDuplicateAlertOpen] = useState(false); - const [duplicateDatasetTitle, setDuplicateDatasetTitle] = useState(""); - // Add this near the top of the file, after the imports useEffect(() => { // Fix Leaflet's default icon path issues @@ -234,59 +212,60 @@ const DemoV3 = () => { setCurrentBaseLayer(initialLayer); setMap(mapInstance); + fetchWMSInfo(); return () => { mapInstance.remove(); }; }, []); - const fetchWMSInfo = async ( - urlToFetch?: string, - datasetId?: string, - datasetTitle?: string - ) => { - if (!urlToFetch && !wmsUrl) { - return { available_layers: [] }; - } - + const fetchWMSInfo = async () => { try { const apiUrl = `http://127.0.0.1:5000/wms-info?url=${encodeURIComponent( - urlToFetch || wmsUrl + wmsUrl )}`; const response = await fetch(apiUrl); const data = await response.json(); - - if (datasetId) { - setTrackedDatasets((prevDatasets) => - prevDatasets.map((dataset) => - dataset.id === datasetId - ? { - ...dataset, - availableLayers: data.available_layers, - selectedLayers: - dataset.selectedLayers.length > 0 - ? dataset.selectedLayers - : data.available_layers.length > 0 - ? [data.available_layers[0].name] - : [], - } - : dataset - ) - ); - } else { - setAvailableLayers(data.available_layers); - if (data.available_layers.length > 0 && selectedLayers.length === 0) { - setSelectedLayers([data.available_layers[0].name]); - } + setAvailableLayers(data.available_layers); + if (data.available_layers.length > 0) { + setSelectedLayers([data.available_layers[0].name]); } - - return data; } catch (error) { console.error("Error fetching WMS info:", error); - return { available_layers: [] }; } }; + // Update the layers displayed on the map + const updateLayers = () => { + if (!map) return; + + // Remove layers that are no longer selected + Object.entries(wmsLayer).forEach(([name, layer]) => { + if (!selectedLayers.includes(name)) { + map.removeLayer(layer); + delete wmsLayer[name]; + } + }); + + // Add or update selected layers + selectedLayers.forEach((layerName) => { + if (!wmsLayer[layerName]) { + const baseWmsUrl = wmsUrl.split("?")[0]; + const newWmsLayer = L.tileLayer.wms(baseWmsUrl, { + layers: layerName, + format: "image/png", + transparent: true, + version: "1.3.0", + zIndex: 10, // Ensure WMS layers stay on top + }); + newWmsLayer.addTo(map); + wmsLayer[layerName] = newWmsLayer; + } + }); + + setWmsLayer({ ...wmsLayer }); + }; + const searchAddress = async (query: string) => { // Clear results if query is empty or too short if (!query || query.length < 3) { @@ -545,7 +524,21 @@ const DemoV3 = () => { available_formats: string[]; } - const replaceIframe = async (wmsUrl: any, datasetTitle?: string) => { + // Update the replaceIframe function + const replaceIframe = (wmsUrl: any) => { + // Handle object type WMS URL + if (typeof wmsUrl === "object" && wmsUrl.wms_url) { + setWmsUrl(wmsUrl.wms_url); + if (wmsUrl.available_layers) { + setAvailableLayers(wmsUrl.available_layers); + if (wmsUrl.available_layers.length > 0) { + setSelectedLayers([wmsUrl.available_layers[0].name]); + } + } + return; + } + + // Handle string type WMS URL if ( !wmsUrl || wmsUrl === "NONE" || @@ -555,188 +548,41 @@ const DemoV3 = () => { return; } - let processedWmsUrl: string; - let extractedLayers: WMSLayer[] = []; - - if (typeof wmsUrl === "object" && wmsUrl.wms_url) { - processedWmsUrl = wmsUrl.wms_url; - extractedLayers = wmsUrl.available_layers || []; - } else { - try { - const wmsData = - typeof wmsUrl === "string" && wmsUrl.startsWith("{") - ? JSON.parse(wmsUrl) - : { wms_url: wmsUrl }; - - if (wmsData.wms_url) { - processedWmsUrl = wmsData.wms_url; - extractedLayers = wmsData.available_layers || []; + try { + const wmsData = + typeof wmsUrl === "string" && wmsUrl.startsWith("{") + ? JSON.parse(wmsUrl) + : { wms_url: wmsUrl }; + + if (wmsData.wms_url) { + setWmsUrl(wmsData.wms_url); + if (wmsData.available_layers) { + setAvailableLayers(wmsData.available_layers); + if (wmsData.available_layers.length > 0) { + setSelectedLayers([wmsData.available_layers[0].name]); + } } else { - processedWmsUrl = wmsUrl; + // If no layers provided, fetch them + fetchWMSInfo(); } - } catch (error) { - // If parsing fails, treat it as a simple WMS URL - processedWmsUrl = wmsUrl; - } - } - - const baseWmsUrl = processedWmsUrl.split("?")[0]; - const isDuplicate = trackedDatasets.some((dataset) => { - const existingBaseUrl = dataset.wmsUrl.split("?")[0]; - return existingBaseUrl === baseWmsUrl; - }); - - if (isDuplicate) { - setDuplicateDatasetTitle(datasetTitle || "Dette datasettet"); - setIsDuplicateAlertOpen(true); - return; - } - - const datasetId = `dataset-${Date.now()}`; - const title = datasetTitle || `Dataset ${trackedDatasets.length + 1}`; - - if (extractedLayers.length === 0) { - const layerData = await fetchWMSInfo(processedWmsUrl); - extractedLayers = layerData.available_layers || []; - } - - const newDataset: TrackedDataset = { - id: datasetId, - title: title, - wmsUrl: processedWmsUrl, - availableLayers: extractedLayers, - selectedLayers: - extractedLayers.length > 0 ? [extractedLayers[0].name] : [], - }; - - setTrackedDatasets((prev) => [...prev, newDataset]); - - if (extractedLayers.length > 0 && map) { - const baseWmsUrl = processedWmsUrl.split("?")[0]; - const layerName = extractedLayers[0].name; - const newWmsLayer = L.tileLayer.wms(baseWmsUrl, { - layers: layerName, - format: "image/png", - transparent: true, - version: "1.3.0", - zIndex: 10, - }); - - newWmsLayer.addTo(map); - setWmsLayer((prev) => ({ - ...prev, - [`${datasetId}:${layerName}`]: newWmsLayer, - })); - } - }; - - const removeTrackedDataset = (datasetId: string) => { - if (map) { - trackedDatasets - .find((dataset) => dataset.id === datasetId) - ?.selectedLayers.forEach((layerName) => { - const layerId = `${datasetId}:${layerName}`; - if (wmsLayer[layerId]) { - map.removeLayer(wmsLayer[layerId]); - - // Remove from wmsLayer state - setWmsLayer((prev) => { - const newLayers = { ...prev }; - delete newLayers[layerId]; - return newLayers; - }); - } - }); - } - - setTrackedDatasets((prev) => - prev.filter((dataset) => dataset.id !== datasetId) - ); - }; - - // Updated function to handle layer selection with dataset ID - const handleLayerChangeWithDataset = ( - datasetId: string, - layerName: string, - isChecked: boolean - ) => { - const dataset = trackedDatasets.find((d) => d.id === datasetId); - if (!dataset) return; - - // Update selected layers in the dataset - setTrackedDatasets((prevDatasets) => - prevDatasets.map((dataset) => - dataset.id === datasetId - ? { - ...dataset, - selectedLayers: isChecked - ? [...dataset.selectedLayers, layerName] - : dataset.selectedLayers.filter((name) => name !== layerName), - } - : dataset - ) - ); - - // Add or remove the layer from the map - if (map) { - const layerId = `${datasetId}:${layerName}`; - - if (isChecked && !wmsLayer[layerId]) { - const baseWmsUrl = dataset.wmsUrl.split("?")[0]; - const newWmsLayer = L.tileLayer.wms(baseWmsUrl, { - layers: layerName, - format: "image/png", - transparent: true, - version: "1.3.0", - zIndex: 10, - }); - - newWmsLayer.addTo(map); - setWmsLayer((prev) => ({ - ...prev, - [layerId]: newWmsLayer, - })); - } else if (!isChecked && wmsLayer[layerId]) { - map.removeLayer(wmsLayer[layerId]); - setWmsLayer((prev) => { - const newLayers = { ...prev }; - delete newLayers[layerId]; - return newLayers; - }); } + } catch (error) { + // If parsing fails, treat it as a simple WMS URL + setWmsUrl(wmsUrl); + fetchWMSInfo(); } }; - // Update the layers displayed on the map - const updateLayers = () => { - if (!map) return; - - // Remove layers that are no longer selected - Object.entries(wmsLayer).forEach(([name, layer]) => { - if (!selectedLayers.includes(name)) { - map.removeLayer(layer); - delete wmsLayer[name]; - } - }); - - // Add or update selected layers - selectedLayers.forEach((layerName) => { - if (!wmsLayer[layerName]) { - const baseWmsUrl = wmsUrl.split("?")[0]; - const newWmsLayer = L.tileLayer.wms(baseWmsUrl, { - layers: layerName, - format: "image/png", - transparent: true, - version: "1.3.0", - zIndex: 10, - }); - newWmsLayer.addTo(map); - wmsLayer[layerName] = newWmsLayer; - } - }); - - setWmsLayer({ ...wmsLayer }); - }; + // const onSearchSubmit = (e: FormEvent) => { + // e.preventDefault(); + // if (!ws || ws.readyState !== WebSocket.OPEN) return; + // ws.send( + // JSON.stringify({ + // action: "searchFormSubmit", + // payload: searchInput, + // }) + // ); + // }; // For the non-fullscreen chat submit handler const onChatSubmit = (e: FormEvent) => { @@ -833,7 +679,7 @@ const DemoV3 = () => { handleSendMessage(message.content); }; - // Function to handle direct download + // Replace the old handleDatasetDownload function with this new implementation const handleDatasetDownload = (msg: ChatMessage) => { console.log("Handling dataset download with message:", msg); console.log("msg.downloadUrl", msg.downloadUrl); @@ -1143,13 +989,13 @@ const DemoV3 = () => { onReplaceIframe={replaceIframe} onDatasetDownload={executeDatasetDownload} ws={ws} - trackedDatasets={trackedDatasets} /> { + // Only allow closing if modal is closed if (!open && !blockPopoverClose) { setIsPopoverOpen(false); } else if (open) { @@ -1169,14 +1015,11 @@ const DemoV3 = () => {
-
-
- - GeoGPT -
+
+ GeoGPT Chat
@@ -1265,8 +1108,8 @@ const DemoV3 = () => { }`} >
{isUser ? ( @@ -1288,21 +1131,21 @@ const DemoV3 = () => {
setChatInput(e.target.value)} placeholder="Spør GeoGPT..." - className="flex-1 rounded px-2 py-2 pb-5 text-sm focus:outline-none" + className="flex-1 border border-gray-300 rounded px-2 py-1 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500" />
@@ -1313,17 +1156,14 @@ const DemoV3 = () => { {/* Full Screen Chat UI */} {isFullScreen && ( -
-
-
- Dataset -

GeoGPT

-
+
+
+

GeoGPT Chat

-
+
{ onWmsClick={replaceIframe} onDownloadClick={handleFullScreenDownload} onExitFullScreen={exitFullScreen} - className="max-w-4xl mx-auto w-full flex-1 flex flex-col justify-end" />
)}
{ onAreaChange={handleAreaChange} metadataUuid={specificObject?.uuid || ""} /> - - {/*AlertDialog for duplicate datasets */} - - - - Datasett finnes allerede - - {duplicateDatasetTitle} er - allerede lagt til i kartet. Det er ikke mulig å legge til samme - datasett flere ganger. - - - - setIsDuplicateAlertOpen(false)} - className="text-white" - > - OK - - - -
); diff --git a/geonorge-app/components/app-sidebar.tsx b/geonorge-app/components/app-sidebar.tsx index 41553de..8a4e682 100644 --- a/geonorge-app/components/app-sidebar.tsx +++ b/geonorge-app/components/app-sidebar.tsx @@ -1,7 +1,7 @@ "use client"; import * as React from "react"; -import { useState, useMemo, useRef, useEffect } from "react"; +import { useState } from "react"; import Image from "next/image"; // Logo @@ -19,9 +19,6 @@ import { Shield, Search, ChevronDown, - ChevronUp, - Trash2, - X, Wrench, } from "lucide-react"; @@ -49,26 +46,16 @@ interface LayerChangeFunctions { changeToRasterKart: () => void; } -interface TrackedDataset { - id: string; - title: string; - wmsUrl: string; - availableLayers: WMSLayer[]; - selectedLayers: string[]; -} - export function AppSidebar({ + selectedLayers, + onLayerChange, availableLayers = [], - trackedDatasets = [], - onLayerChangeWithDataset, - onRemoveDataset, onChangeBaseLayer, ...props }: React.ComponentProps & { + selectedLayers: string[]; + onLayerChange: (layerName: string, isChecked: boolean) => void; availableLayers?: WMSLayer[]; - trackedDatasets?: TrackedDataset[]; - onLayerChangeWithDataset?: (datasetId: string, layerName: string, isChecked: boolean) => void; - onRemoveDataset?: (datasetId: string) => void; onChangeBaseLayer?: LayerChangeFunctions; }) { const { language, setLanguage, t } = useLanguage(); @@ -79,60 +66,9 @@ export function AppSidebar({ const [selectedBaseMap, setSelectedBaseMap] = useState("landskart"); const [isBaseMapSectionVisible, setIsBaseMapSectionVisible] = useState(true); const searchInputRef = React.useRef(null); - const [expandedDatasets, setExpandedDatasets] = React.useState>({}); - - // Add refs to track scroll positions - const datasetScrollContainerRef = useRef(null); - const datasetScrollPositionRef = useRef>({}); - const mainScrollPositionRef = useRef(0); // New ref for main container scroll - // Save scroll position before toggling dataset expansion - const handleToggleDatasetExpansion = (datasetId: string) => { - // Save the main container scroll position - if (datasetScrollContainerRef.current) { - mainScrollPositionRef.current = datasetScrollContainerRef.current.scrollTop; - } - - // If dataset is expanded, save its scroll position before collapsing - if (expandedDatasets[datasetId] && datasetScrollContainerRef.current) { - const datasetElement = datasetScrollContainerRef.current.querySelector( - `[data-dataset-id="${datasetId}"]` - ); - - if (datasetElement) { - const scrollContainer = datasetElement.querySelector('.dataset-layer-container') as HTMLElement; - if (scrollContainer) { - datasetScrollPositionRef.current[datasetId] = scrollContainer.scrollTop; - } - } - } - - // Toggle the dataset expansion - setExpandedDatasets(prev => ({ - ...prev, - [datasetId]: !prev[datasetId] - })); - }; - - // Filter layers based on search - const filteredLayers = useMemo(() => - availableLayers.filter((layer) => - layer.title.toLowerCase().includes(layerSearch.toLowerCase()) - ), - [availableLayers, layerSearch] - ); - - // Filter datasets based on search - const filteredDatasets = useMemo(() => - trackedDatasets - .map(dataset => ({ - ...dataset, - availableLayers: dataset.availableLayers.filter(layer => - layer.title.toLowerCase().includes(layerSearch.toLowerCase()) - ), - })) - .filter(dataset => dataset.availableLayers.length > 0), - [trackedDatasets, layerSearch] + const filteredLayers = availableLayers.filter((layer) => + layer.title.toLowerCase().includes(layerSearch.toLowerCase()) ); const cn = (...classes: string[]) => { @@ -272,6 +208,7 @@ export function AppSidebar({ e.preventDefault(); e.stopPropagation(); setLayerSearch(e.target.value); + // Make sure input keeps focus if (searchInputRef.current) { searchInputRef.current.focus(); } @@ -283,83 +220,6 @@ export function AppSidebar({ } }, [layerSearch]); - // Deselect all layers across all datasets - const deselectAllLayersGlobally = () => { - if (!onLayerChangeWithDataset) return; - trackedDatasets.forEach(dataset => { - dataset.selectedLayers.forEach(layerName => { - onLayerChangeWithDataset(dataset.id, layerName, false); - }); - }); - }; - - // Check if any layers are selected in any dataset - const hasSelectedLayers = trackedDatasets.some(dataset => dataset.selectedLayers.length > 0); - - // Handle checkbox change with scroll position preservation - const handleLayerChange = (datasetId: string, layerName: string, checked: boolean) => { - if (datasetScrollContainerRef.current) { - mainScrollPositionRef.current = datasetScrollContainerRef.current.scrollTop; - } - - // Store current scroll position for the specific dataset container - if (datasetScrollContainerRef.current) { - const datasetElement = datasetScrollContainerRef.current.querySelector( - `[data-dataset-id="${datasetId}"]` - ); - if (datasetElement) { - const scrollContainer = datasetElement.querySelector('.dataset-layer-container') as HTMLElement; - if (scrollContainer) { - datasetScrollPositionRef.current[datasetId] = scrollContainer.scrollTop; - } - } - } - if (onLayerChangeWithDataset) { - onLayerChangeWithDataset(datasetId, layerName, checked); - } - }; - - // Restore scroll positions after render - useEffect(() => { - if (datasetScrollContainerRef.current) { - // First restore the main container scroll position - datasetScrollContainerRef.current.scrollTop = mainScrollPositionRef.current; - - // Then restore individual dataset scroll positions - Object.keys(expandedDatasets).forEach(datasetId => { - if (expandedDatasets[datasetId] && datasetScrollPositionRef.current[datasetId] !== undefined) { - const datasetElement = datasetScrollContainerRef.current?.querySelector( - `[data-dataset-id="${datasetId}"]` - ); - if (datasetElement) { - const scrollContainer = datasetElement.querySelector('.dataset-layer-container') as HTMLElement; - if (scrollContainer) { - scrollContainer.scrollTop = datasetScrollPositionRef.current[datasetId]; - } - } - } - }); - } - }, [trackedDatasets, expandedDatasets]); - - // Also save main scroll position when removing datasets - const handleRemoveDataset = (datasetId: string) => { - if (datasetScrollContainerRef.current) { - mainScrollPositionRef.current = datasetScrollContainerRef.current.scrollTop; - } - if (onRemoveDataset) { - onRemoveDataset(datasetId); - } - }; - - // Also save main scroll position when deselecting all layers - const handleDeselectAllLayers = () => { - if (datasetScrollContainerRef.current) { - mainScrollPositionRef.current = datasetScrollContainerRef.current.scrollTop; - } - deselectAllLayersGlobally(); - }; - return ( +
+ + - )} -
- -
- {filteredDatasets.map((dataset) => ( -
+ {filteredLayers.length > 0 ? ( +
+ {filteredLayers.map((layer) => ( +
-
handleToggleDatasetExpansion(dataset.id)} + { + onLayerChange(layer.name, checked as boolean); + }} + className="h-4 w-4 border-gray-300 rounded" + /> +
- - {expandedDatasets[dataset.id] && ( -
- {dataset.availableLayers.map((layer) => ( -
- { - handleLayerChange(dataset.id, layer.name, checked as boolean); - }} - className="h-4 w-4 border-gray-300 rounded" - /> - -
- ))} -
- )} + {layer.title} +
))}
-
- )} - - {/* Show a message when no layers or datasets match the search */} - {filteredLayers.length === 0 && filteredDatasets.length === 0 && layerSearch.trim() !== "" && ( -
-

- {t("no_layers_found")} -

-
- )} + ) : ( +
+

+ {t("no_layers_found")} +

+
+ )} +
))}
+