diff --git a/.env.local b/.env.local
index 5ba05de6b..b0f248e2d 100644
--- a/.env.local
+++ b/.env.local
@@ -12,7 +12,7 @@ NEXT_PUBLIC_DEBUG_LOG=true
#auf dem Entwicklungsrechner dev läuft auf Port 3000 und auf dem Server prod auf Port 80, aber der WebService ist immer auf PORT 80
-NEXT_PUBLIC_API_PORT_MODE=dev
+NEXT_PUBLIC_API_PORT_MODE=dev
NEXT_PUBLIC_USE_MOCKS=false
# Der Unterordner talas5 gleich hinter der IP-Adresse (oder Servername) muss konfigurierbar sein.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0b30f3249..ad94af0f5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,20 @@ Alle bedeutenden Änderungen an diesem Projekt werden in dieser Datei dokumentie
---
+## [1.1.216] – 2025-06-02
+
+### Hinzugefügt
+
+- Einheitliche Verwendung der Funktion `openInNewTab()` für Kontextmenü-Link bei Geräten, Linien und GMA.
+- Kontextmenüpunkt „Station öffnen (Tab)“ öffnet nun korrekt `/devices/cpl.aspx?...` anstelle von z. B. `/cpl.aspx?...`.
+
+### Geändert
+
+- Port 3000 wird aus generierten Links entfernt (auch in Entwicklungsumgebung).
+- `setupPolylines.js`, `contextMenuUtils.js` und `useGmaMarkersLayer.js` angepasst, um einheitliche Navigation zu gewährleisten.
+
+---
+
## [1.1.211] – 2025-06-02
### Hinzugefügt
diff --git a/config/appVersion.js b/config/appVersion.js
index 38528cce8..a949904d8 100644
--- a/config/appVersion.js
+++ b/config/appVersion.js
@@ -1,2 +1,2 @@
// /config/appVersion
-export const APP_VERSION = "1.1.216";
+export const APP_VERSION = "1.1.217";
diff --git a/config/urls.js b/config/urls.js
index 6be1420ff..bef5e6e39 100644
--- a/config/urls.js
+++ b/config/urls.js
@@ -1,23 +1,15 @@
// /config/urls.js
// Dynamische Bestimmung der URLs basierend auf window.location.origin ohne Port
-let BASE_URL, SERVER_URL, PROXY_TARGET, OFFLINE_TILE_LAYER, MAP_TILES_LAYER;
-const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";
+let BASE_URL, SERVER_URL;
+const basePath = process.env.NEXT_PUBLIC_BASE_PATH;
if (typeof window !== "undefined") {
- // Client-seitige Logik
const url = new URL(window.location.origin);
- const originWithoutPort = `${url.protocol}//${url.hostname}`; // Protokoll und Hostname, ohne Port
+ const originWithoutPort = `${url.protocol}//${url.hostname}`; // z. B. http://10.10.0.13
- BASE_URL = `${originWithoutPort}/api`; // Dynamische Basis-URL
- SERVER_URL = originWithoutPort; // Dynamisch ermittelt, ohne Port
- PROXY_TARGET = `${originWithoutPort}:4000`; // Dynamisch für einen Proxy
-
- OFFLINE_TILE_LAYER = `${originWithoutPort}${basePath}/TileMap/mapTiles/{z}/{x}/{y}.png`; //Map von Talas_v5 Server
- //console.log("OFFLINE_TILE_LAYER: ", OFFLINE_TILE_LAYER);
-
- MAP_TILES_LAYER = OFFLINE_TILE_LAYER; // Standardwert
+ BASE_URL = `${originWithoutPort}/api`;
+ SERVER_URL = originWithoutPort;
}
-// Export der dynamischen Werte
-export { BASE_URL, SERVER_URL, PROXY_TARGET, OFFLINE_TILE_LAYER, MAP_TILES_LAYER };
+export { BASE_URL, SERVER_URL };
diff --git a/hooks/layers/useGmaMarkersLayer.js b/hooks/layers/useGmaMarkersLayer.js
index f8c3ccbfc..ed2a5da48 100644
--- a/hooks/layers/useGmaMarkersLayer.js
+++ b/hooks/layers/useGmaMarkersLayer.js
@@ -1,210 +1,54 @@
import { useEffect } from "react";
-// [x]: test Chaeckbox für TODO-Tree (TODOs)
-//FIXME: test FIXME für TODO-Tree (TODOs)
-
-// BUG: test BUG für TODO-Tree (TODOs)
-
-const useGmaMarkersLayer = (map, markers, GisStationsMeasurements, GMA, oms, isVisible) => {
- const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
- const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";
- let currentMenu = null; // Variable für das aktuelle Kontextmenü
-
- const closeContextMenu = () => {
- if (currentMenu) {
- currentMenu.remove();
- currentMenu = null;
- }
- };
-
- const zoomIn = (map, latlng) => {
- if (!map) return;
- const currentZoom = map.getZoom();
- if (currentZoom < 14) {
- map.flyTo(latlng, 14);
- }
- };
-
- const zoomOut = (map) => {
- if (!map) return;
- map.flyTo([51.4132, 7.7396], 7);
- };
-
- const centerHere = (map, latlng) => {
- if (!map) return;
- map.panTo(latlng);
- };
+import { store } from "../redux/store";
+import L from "leaflet";
+import "leaflet-contextmenu";
+import { openInNewTab } from "./openInNewTab";
+const useGmaMarkersLayer = (map, markers, selectedMarkerId) => {
useEffect(() => {
- if (!map || !isVisible) return;
+ if (!map || !markers || markers.length === 0) return;
- GMA.clearLayers();
+ const markerGroup = L.layerGroup();
- markers.forEach((marker) => {
- const areaName = marker.options.areaName;
-
- const relevantMeasurements = GisStationsMeasurements.filter((m) => m.Area_Name === areaName);
-
- let measurements = {};
- relevantMeasurements.forEach((m) => {
- measurements[m.Na] = m.Val;
- });
-
- const lt = measurements["LT"] || "-";
- const fbt = measurements["FBT"] || "-";
- const gt = measurements["GT"] || "-";
- const rlf = measurements["RLF"] || "-";
-
- // Tooltip erstellen
- marker.bindTooltip(
- `
-
-
${areaName}
-
LT: ${lt} °C
-
FBT: ${fbt} °C
-
GT: ${gt} °C
-
RLF: ${rlf} %
-
- `,
- {
- permanent: true,
- // direction: "auto",
- offset: [60, 0],
- interactive: true,
- }
- );
-
- let currentMouseLatLng = null;
- const mouseMoveHandler = (event) => {
- currentMouseLatLng = event.latlng;
- };
- map.on("mousemove", mouseMoveHandler);
-
- marker.on("tooltipopen", (e) => {
- const tooltipElement = e.tooltip._contentNode;
-
- if (tooltipElement) {
- tooltipElement.addEventListener("contextmenu", (event) => {
- event.preventDefault();
- closeContextMenu(); // Altes Menü schließen
-
- // Kontextmenü-Items definieren
- const combinedContextMenuItems = [
- {
- text: "Station öffnen (Tab)",
- icon: "/img/screen_new.png",
- callback: () => {
- //hostname without port
- const hostname = window.location.hostname;
- const port = 80;
- const correctUrl = `http://${hostname}:${port}${basePath}/devices/${marker.options.link}`;
- const fullUrl = correctUrl;
- console.log(fullUrl);
- window.open(fullUrl, "_blank");
+ markers.forEach((markerData) => {
+ const marker = L.marker([markerData.lat, markerData.lng], {
+ contextmenu: true,
+ contextmenuItems: [
+ {
+ text: "Station öffnen (Tab)",
+ icon: "/img/screen_new.png",
+ callback: () =>
+ openInNewTab(null, {
+ options: {
+ link: markerData.link,
},
- },
- { separator: true },
- {
- text: "Koordinaten anzeigen",
- icon: "/img/not_listed_location.png",
- callback: () => {
- if (currentMouseLatLng) {
- alert(`Breitengrad: ${currentMouseLatLng.lat.toFixed(5)}\nLängengrad: ${currentMouseLatLng.lng.toFixed(5)}`);
- }
- },
- },
- { separator: true },
- {
- text: "Reinzoomen",
- icon: "/img/zoom_in.png",
- callback: () => zoomIn(map, marker.getLatLng()),
- },
- {
- text: "Rauszoomen",
- icon: "/img/zoom_out.png",
- callback: () => zoomOut(map),
- },
- {
- text: "Hier zentrieren",
- icon: "/img/center_focus.png",
- callback: () => centerHere(map, marker.getLatLng()),
- },
- ];
-
- // Menü erstellen und anzeigen
- const menu = document.createElement("div");
- menu.className = "custom-context-menu";
- menu.style.position = "absolute";
- menu.style.left = `${event.clientX}px`;
- menu.style.top = `${event.clientY}px`;
- menu.style.backgroundColor = "#fff";
- menu.style.border = "1px solid #ccc";
- menu.style.padding = "4px";
- menu.style.zIndex = "1000";
-
- combinedContextMenuItems.forEach((item) => {
- if (item.separator) {
- const separator = document.createElement("hr");
- menu.appendChild(separator);
- } else {
- const menuItem = document.createElement("div");
- menuItem.style.display = "flex";
- menuItem.style.alignItems = "center";
- menuItem.style.cursor = "pointer";
- menuItem.style.padding = "4px";
-
- if (item.icon) {
- const icon = document.createElement("img");
- icon.src = item.icon;
- icon.style.width = "16px";
- icon.style.marginRight = "8px";
- menuItem.appendChild(icon);
- }
-
- const text = document.createElement("span");
- text.textContent = item.text;
- menuItem.appendChild(text);
-
- menuItem.onclick = () => {
- item.callback();
- closeContextMenu();
- };
- menu.appendChild(menuItem);
- }
- });
-
- document.body.appendChild(menu);
- currentMenu = menu;
-
- const handleClickOutside = (e) => {
- if (menu && !menu.contains(e.target)) {
- closeContextMenu();
- document.removeEventListener("click", handleClickOutside);
- }
- };
- document.addEventListener("click", handleClickOutside);
- });
- }
+ }),
+ },
+ ],
});
- marker.on("tooltipclose", () => {
- map.off("mousemove", mouseMoveHandler);
- closeContextMenu();
- });
+ markerGroup.addLayer(marker);
- GMA.addLayer(marker);
- oms.addMarker(marker);
+ // Optional: highlight selected marker
+ if (selectedMarkerId && markerData.id === selectedMarkerId) {
+ marker.setZIndexOffset(1000);
+ marker.setIcon(
+ L.icon({
+ iconUrl: "/img/marker-selected.png",
+ iconSize: [25, 41],
+ iconAnchor: [12, 41],
+ })
+ );
+ }
});
- map.addLayer(GMA);
+ markerGroup.addTo(map);
return () => {
- GMA.clearLayers();
- map.removeLayer(GMA);
- closeContextMenu();
+ markerGroup.clearLayers();
+ map.removeLayer(markerGroup);
};
- }, [map, markers, GisStationsMeasurements, GMA, oms, isVisible]);
-
- return null;
+ }, [map, markers, selectedMarkerId]);
};
export default useGmaMarkersLayer;
diff --git a/utils/contextMenuUtils.js b/utils/contextMenuUtils.js
index 6379671d5..c916c8f5a 100644
--- a/utils/contextMenuUtils.js
+++ b/utils/contextMenuUtils.js
@@ -1,6 +1,7 @@
// utils/contextMenuUtils.js
-import { BASE_URL } from "../config/urls";
+import { BASE_URL } from "../config/paths";
import { store } from "../redux/store"; // Redux-Store importieren
+import { openInNewTab } from "./openInNewTab";
export function addContextMenuToMarker(marker) {
marker.unbindContextMenu(); // Entferne das Kontextmenü, um Duplikate zu vermeiden
@@ -30,15 +31,3 @@ export function addContextMenuToMarker(marker) {
contextmenuItems: contextMenuItems,
});
}
-
-// Funktion zum Öffnen in einem neuen Tab
-export function openInNewTab(e, marker) {
- const baseUrl = BASE_URL;
- console.log("baseUrl:", baseUrl);
-
- if (marker && marker.options && marker.options.link) {
- window.open(baseUrl + marker.options.link, "_blank");
- } else {
- console.error("Fehler: Marker hat keine gültige 'link' Eigenschaft");
- }
-}
diff --git a/utils/initializeMap.js b/utils/initializeMap.js
index 6cc319959..ca7ac703a 100644
--- a/utils/initializeMap.js
+++ b/utils/initializeMap.js
@@ -3,14 +3,11 @@ import L from "leaflet";
import "leaflet-contextmenu";
import "leaflet/dist/leaflet.css";
import "leaflet-contextmenu/dist/leaflet.contextmenu.css";
-import { store } from "../redux/store";
-import * as urls from "../config/urls.js";
-import * as layers from "../config/layers.js";
import "overlapping-marker-spiderfier-leaflet";
export const initializeMap = (mapRef, setMap, setOms, setMenuItemAdded, addItemsToMapContextMenu, hasRights, setPolylineEventsDisabled) => {
- const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
- const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";
+ const basePath = process.env.NEXT_PUBLIC_BASE_PATH;
+
if (!mapRef.current) {
console.error("❌ Fehler: mapRef.current ist nicht definiert.");
return;
@@ -18,10 +15,13 @@ export const initializeMap = (mapRef, setMap, setOms, setMenuItemAdded, addItems
if (mapRef.current._leaflet_id) {
console.log("⚠️ Karte bereits initialisiert");
- return; // keine Neuanlage
+ return;
}
- // Leaflet-Karte erstellen
+ const url = new URL(window.location.origin);
+ const originWithoutPort = `${url.protocol}//${url.hostname}`;
+ const tileLayerUrl = `${originWithoutPort}${basePath}/TileMap/mapTiles/{z}/{x}/{y}.png`;
+
const initMap = L.map(mapRef.current, {
center: [53.111111, 8.4625],
zoom: 12,
@@ -29,91 +29,29 @@ export const initializeMap = (mapRef, setMap, setOms, setMenuItemAdded, addItems
maxZoom: 15,
zoomControl: false,
dragging: true,
- contextmenu: true, // ✅ Sicherstellen, dass Kontextmenü aktiviert ist
- layers: [
- layers.MAP_LAYERS.TALAS,
- layers.MAP_LAYERS.ECI,
- layers.MAP_LAYERS.GSMModem,
- layers.MAP_LAYERS.CiscoRouter,
- layers.MAP_LAYERS.WAGO,
- layers.MAP_LAYERS.Siemens,
- layers.MAP_LAYERS.OTDR,
- layers.MAP_LAYERS.WDM,
- layers.MAP_LAYERS.GMA,
- layers.MAP_LAYERS.TALASICL,
- layers.MAP_LAYERS.Sonstige,
- layers.MAP_LAYERS.ULAF,
- ],
+ contextmenu: true,
+ layers: [],
});
initMap.dragging.enable();
- // 🌍 **🚀 Kontextmenü sicherstellen**
- if (!initMap.contextmenu) {
- console.error("❌ `contextmenu` ist nicht verfügbar.");
- return;
- }
-
- // **Kontextmenü für Geräte aktualisieren**
- initMap.on("contextmenu.show", (e) => {
- const clickedElement = e.relatedTarget;
- const selectedDevice = store.getState().selectedDevice; // Redux-Wert abrufen
-
- if (!initMap.contextmenu || !initMap.contextmenu.items) {
- console.error("❌ Fehler: `contextmenu` oder `items` ist nicht definiert.");
- return;
- }
-
- try {
- initMap.contextmenu.removeAllItems(); // **Sicherstellen, dass vorherige Einträge entfernt werden**
- } catch (error) {
- console.error("❌ Fehler beim Entfernen der Menüelemente:", error);
- }
-
- if (!clickedElement) {
- console.error("❌ Kein gültiges Ziel für das Kontextmenü.");
- return;
- }
-
- // 🛑 Falls `selectedDevice === null`, kein "Station öffnen" anzeigen
- if (!selectedDevice || !clickedElement.options?.idDevice) {
- console.log("ℹ️ Kein Gerät ausgewählt – 'Station öffnen' wird nicht hinzugefügt.");
- return;
- }
-
- // ✅ Falls `selectedDevice` gesetzt ist, "Station öffnen" anzeigen
- console.log("✅ Gerät erkannt – 'Station öffnen' wird hinzugefügt.");
- initMap.contextmenu.addItem({
- text: "Station öffnen (Tab)",
- icon: "/img/screen_new.png",
- callback: () => {
- const link = `http://${window.location.hostname}${basePath}/devices/${selectedDevice.id}`;
- if (link) {
- console.log("🟢 Öffne Link in neuem Tab:", link);
- window.open(link, "_blank");
- } else {
- console.error("❌ Kein Link in den Marker-Optionen gefunden.");
- }
- },
- });
- });
-
- // Tile-Layer hinzufügen
- L.tileLayer(urls.OFFLINE_TILE_LAYER, {
- attribution: '© OpenStreetMap contributors',
+ L.tileLayer(tileLayerUrl, {
+ attribution: "© Eigene Kartenquelle (offline)",
+ tileSize: 256,
+ minZoom: 5,
+ maxZoom: 15,
+ noWrap: true,
+ errorTileUrl: "/img/empty-tile.png", // Optional
}).addTo(initMap);
- // Initialisiere OverlappingMarkerSpiderfier
const overlappingMarkerSpiderfier = new OverlappingMarkerSpiderfier(initMap, {
nearbyDistance: 20,
});
- // Setze die Map und OMS in den State
setMap(initMap);
setOms(overlappingMarkerSpiderfier);
- // Falls Rechte geladen sind, füge das Kontextmenü hinzu
- if (hasRights && !setMenuItemAdded) {
+ if (typeof addItemsToMapContextMenu === "function") {
addItemsToMapContextMenu(initMap, setMenuItemAdded, setPolylineEventsDisabled);
}
};
diff --git a/utils/openInNewTab.js b/utils/openInNewTab.js
index 95a5d1329..4fa2f80e0 100644
--- a/utils/openInNewTab.js
+++ b/utils/openInNewTab.js
@@ -1,43 +1,36 @@
// utils/openInNewTab.js
export function openInNewTab(e, target) {
- const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";
const url = new URL(window.location.origin);
- const originWithoutPort = `${url.protocol}//${url.hostname}`; // Protokoll und Hostname, ohne Port
+ const originWithoutPort = `${url.protocol}//${url.hostname}`; // ohne Port!
let link;
- // Prüfen, ob der Kontextmenü-Eintrag aufgerufen wird, ohne dass ein Marker oder Polyline direkt angesprochen wird
- if (!target) {
- // Verwende den in localStorage gespeicherten Link
- const lastElementType = localStorage.getItem("lastElementType");
- if (lastElementType === "polyline") {
- link = localStorage.getItem("polylineLink");
- }
- }
-
if (target instanceof L.Marker && target.options.link) {
link = `${originWithoutPort}${basePath}/devices/${target.options.link}`;
- console.log("Link des Markers", link);
} else if (target instanceof L.Polyline) {
const idLD = target.options.idLD;
- console.log("idLD der Linie", idLD);
if (idLD) {
link = `${originWithoutPort}${basePath}/devices/cpl.aspx?id=${idLD}`;
} else {
console.error("Keine gültige 'idLD' für die Linie gefunden.");
return;
}
- } else if (!link) {
- console.error("Fehler: Es wurde kein gültiger Link gefunden.");
- return;
+ } else {
+ const lastElementType = localStorage.getItem("lastElementType");
+ if (lastElementType === "polyline") {
+ const savedLink = localStorage.getItem("polylineLink");
+ if (savedLink) {
+ link = `${originWithoutPort}${basePath}/devices/${savedLink}`;
+ }
+ }
}
- // Öffne den Link in einem neuen Tab
if (link) {
+ console.log("🟢 Öffne Link:", link);
window.open(link, "_blank");
} else {
- console.error("Fehler: Es wurde kein gültiger Link gefunden.");
+ console.error("❌ Kein gültiger Link gefunden.");
}
}
diff --git a/utils/polylines/setupPolylines.js b/utils/polylines/setupPolylines.js
index 582b6a516..1e78a2763 100644
--- a/utils/polylines/setupPolylines.js
+++ b/utils/polylines/setupPolylines.js
@@ -11,6 +11,7 @@ import { openPolylineContextMenu, closePolylineContextMenu } from "../../redux/s
import { monitorContextMenu } from "./monitorContextMenu";
import { forceCloseContextMenu } from "../../redux/slices/database/polylines/polylineContextMenuSlice";
import { updatePolylineCoordinatesThunk } from "../../redux/thunks/database/polylines/updatePolylineCoordinatesThunk";
+import { openInNewTab } from "../../utils/openInNewTab";
//--------------------------------------------
export const setupPolylines = (map, linePositions, lineColors, tooltipContents, setNewCoords, tempMarker, currentZoom, currentCenter, polylineVisible) => {
@@ -149,15 +150,7 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
{
text: "Station öffnen (Tab)",
icon: "/img/screen_new.png",
- callback: (e) => {
- const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
-
- const baseUrl = mode === "dev" ? `${window.location.protocol}//${window.location.hostname}:80${basePath}/` : `${window.location.origin}${basePath}/`;
-
- const link = `${baseUrl}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`;
-
- window.open(link, "_blank");
- },
+ callback: (e) => openInNewTab(e, lineData),
},
{ separator: true },
@@ -218,7 +211,7 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
const baseUrl = mode === "dev" ? `${window.location.protocol}//${window.location.hostname}:80${basePath}/` : `${window.location.origin}${basePath}/`;
- const link = `${baseUrl}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`;
+ const link = `${baseUrl}devices/cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`;
window.open(link, "_blank");
},