feat: Healthcheck um Webservices, API-Routen und .env-Prüfungen erweitert

- Externe Webservices von TALAS V5 integriert und geprüft (Statuscode + Antwortstruktur)
- Eigene API-Endpunkte wie /api/talas_v5_DB/getDevices hinzugefügt und validiert
- Prüfung von NEXT_PUBLIC_USE_MOCKS zur Vermeidung von Mockdaten in Produktion
- Validierung der Umgebungsvariablen wie DB_HOST, DB_NAME und NODE_ENV ergänzt
- Response-Status 200 bei vollständigem Erfolg, 207 bei Teilfehlern
- Verbesserung der JSON-Antwortstruktur zur einfacheren Analyse
This commit is contained in:
ISA
2025-06-05 15:23:59 +02:00
parent 9273195d8f
commit ec31b36b3d
31 changed files with 397 additions and 163 deletions

View File

@@ -7,13 +7,13 @@ DB_NAME=talas_v5
DB_PORT=3306
# Public Settings (Client braucht IP/Domain) , Variablen mit dem Präfix "NEXT_PUBLIC" ist in Browser sichtbar
NEXT_PUBLIC_DEBUG_LOG=true
NEXT_PUBLIC_DEBUG_LOG=false
#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=prod
NEXT_PUBLIC_USE_MOCKS=false
NEXT_PUBLIC_USE_MOCKS=true
# Der Unterordner talas5 gleich hinter der IP-Adresse (oder Servername) muss konfigurierbar sein.
# Es muss auch möglich sein kein Unterorder anzugeben (z.B. nur http://talasserver/).

View File

@@ -1,37 +0,0 @@
// components/TestScript.js
import { useEffect } from "react";
import setupPolylinesCode from "!!raw-loader!../utils/polylines/setupPolylines.js"; // Lädt die gesamte setupPolylines.js als Text
export default function TestScript() {
useEffect(() => {
// Regulärer Ausdruck für "Stützpunkt entfernen" im Kontextmenü
const removeRegex = /marker\.on\("mouseover", function \(\) {\s*this\.bindContextMenu\({\s*contextmenuItems: \[\s*\{\s*text: "Stützpunkt entfernen"/;
// Regulärer Ausdruck für "Stützpunkt hinzufügen" im Kontextmenü
const addRegex = /contextmenuItems: \[\s*\{\s*text: "Stützpunkt hinzufügen"/;
// Stilvorlagen für das Konsolen-Logging
const successStyle = "color: #fff; background-color: #28a745; padding: 4px 8px; font-size: 14px; border-radius: 4px;";
const failStyle = "color: #fff; background-color: #dc3545; padding: 4px 8px; font-size: 14px; border-radius: 4px;";
const neutralStyle = "color: #006400; font-size: 14px; background-color: #f0f0f0; padding: 4px 8px; border-radius: 4px;";
// Überprüfung für "Stützpunkt entfernen"
if (removeRegex.test(setupPolylinesCode)) {
console.log("%c✔ Test bestanden: Der Text für 'Stützpunkt entfernen' wurde gefunden.", successStyle);
} else {
console.log("%c✘ Test fehlgeschlagen: Der Text für 'Stützpunkt entfernen' wurde nicht gefunden.", failStyle);
}
// Überprüfung für "Stützpunkt hinzufügen"
if (addRegex.test(setupPolylinesCode)) {
console.log("%c✔ Test bestanden: Der Text für 'Stützpunkt hinzufügen' wurde gefunden.", successStyle);
} else {
//console.log("%c✘ Test fehlgeschlagen: Der Text für 'Stützpunkt hinzufügen' wurde nicht gefunden.", failStyle);
}
// Beispiel einer neutralen Nachricht (falls benötigt)
console.log("%c Info: Überprüfung abgeschlossen.", neutralStyle);
}, []);
return null; // Keine visuelle Ausgabe erforderlich
}

View File

@@ -12,7 +12,7 @@ const addItemsToMapContextMenu = (
setPopupCoordinates,
openPopupWithCoordinates // Hier wird die Funktion als Parameter hinzugefügt
) => {
const openPoiModal = (e) => {
const openPoiModal = e => {
setShowCoordinatesModal(false); // ✅ Jetzt verfügbar, weil als Parameter übergeben
setPopupCoordinates(e.latlng);
setShowPoiModal(true);
@@ -29,7 +29,7 @@ const addItemsToMapContextMenu = (
map.contextmenu.addItem({
text: "Reinzoomen",
icon: "img/zoom_in.png",
callback: (e) => {
callback: e => {
const currentZoom = map.getZoom();
const newZoom = Math.min(15, currentZoom + 3); // Stellt sicher, dass max. 15 erreicht wird
const zoomDifference = Math.abs(newZoom - currentZoom); // Anzahl der Zoom-Stufen
@@ -61,7 +61,7 @@ const addItemsToMapContextMenu = (
map.contextmenu.addItem({
text: "Hier zentrieren",
icon: "img/center_focus.png",
callback: (e) => {
callback: e => {
map.panTo(e.latlng);
},
});
@@ -71,8 +71,9 @@ const addItemsToMapContextMenu = (
if (!menuItemAdded && map && map.contextmenu) {
const editMode = localStorage.getItem("editMode") === "true";
if (editMode) {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("editMode localStorage:", localStorage.getItem("editMode"));
//console.log("editMode:", editMode);
}
map.contextmenu.addItem({
text: "POI hinzufügen",

View File

@@ -148,7 +148,6 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
// Konstanten für die URLs
//console.log("priorityConfig in MapComponent1: ", priorityConfig);
//-----------------------------------------
const [linePositions, setLinePositions] = useState([]);
const { lineColors, tooltipContents } = useLineData();
@@ -234,7 +233,6 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
}
locations.forEach(location => {});
};
//console.log("trigger in MapComponent.js:", poiReadTrigger);
}, [map, locations, poiReadTrigger]);
//--------------------------------------------
@@ -275,7 +273,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
]);
//---------------------------------------------
//console.log("priorityConfig in MapComponent2: ", priorityConfig);
useEffect(() => {
if (map) {
}
@@ -319,7 +317,6 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
);
newPolylines.forEach((polyline, index) => {
//console.log("polyline: ", polyline);
const tooltipContent =
tooltipContents[`${linePositions[index].idLD}-${linePositions[index].idModul}`] ||
"Die Linie ist noch nicht in Webservice vorhanden oder bekommt keine Daten";
@@ -380,14 +377,18 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
//Test in useEffect
useEffect(() => {
if (map) {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("🗺️ Map-Einstellungen werden wiederhergestellt...");
}
restoreMapSettings(map);
}
}, [map]);
//--------------------------------------------
useEffect(() => {
if (map) {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("map in MapComponent: ", map);
}
const handleMapMoveEnd = event => {
const newCenter = map.getCenter();
const newZoom = map.getZoom();
@@ -411,8 +412,6 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
//--------------------------------------------
// Area in DataSheet ->dropdownmenu
useEffect(() => {
//console.log("🔍 GisStationsStaticDistrict Inhalt:", GisStationsStaticDistrict);
// Sicherstellen, dass `Points` existiert und ein Array ist
const points = GisStationsStaticDistrict?.Points;
@@ -420,7 +419,9 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
const station = points.find(s => s.Area_Name === selectedArea);
if (station) {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("📌 Gefundene Station:", station);
}
map.flyTo([station.X, station.Y], 14);
} else {
console.warn("⚠️ Keine passende Station für die Area gefunden:", selectedArea);
@@ -464,8 +465,10 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
//--------------------------------------------
useEffect(() => {
if (map) {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("6- Karteninstanz (map) wurde jetzt erfolgreich initialisiert");
}
}
}, [map]);
//--------------------------------------------
useEffect(() => {
@@ -474,7 +477,9 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
map.whenReady(() => {
setTimeout(() => {
if (map.contextmenu) {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
//console.log("Contextmenu ist vorhanden");
}
} else {
console.warn("Contextmenu ist nicht verfügbar.");
}
@@ -499,7 +504,9 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
const handleLocationUpdate = async (idLocation, idMap, newCoords) => {
try {
await dispatch(updateAreaThunk({ idLocation, idMap, newCoords })).unwrap();
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("Koordinaten erfolgreich aktualisiert:", result);
}
} catch (error) {
console.error("Fehler beim Aktualisieren der Location:", error);
}
@@ -661,15 +668,15 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
//--------------------------------------
useEffect(() => {
if (isPolylineContextMenuOpen && countdownActive) {
//console.log("🔄 Starte Redux-Countdown für Kontextmenü!");
const interval = setInterval(() => {
dispatch(updateCountdown());
// console.log(`⏳ Redux Countdown: ${countdown} Sekunden`);
if (countdown <= 2) {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("🚀 Kontextmenü wird wegen Countdown < 2 geschlossen.");
}
dispatch(closePolylineContextMenu());
if (window.map?.contextmenu) {
@@ -690,8 +697,10 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
useEffect(() => {
if (map) {
window.map = map;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("✅ window.map wurde gesetzt:", window.map);
}
}
}, [map]);
//---------------------------------------
@@ -756,7 +765,9 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
// 🧠 Optional für Debugging für überlappende Markers
useEffect(() => {
if (oms) {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("📌 OMS ready:", oms);
}
window.oms = oms; // Für Debugging global
}
}, [oms]);
@@ -764,7 +775,9 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
//----------------------------------------------
useEffect(() => {
if (process.env.NODE_ENV === "development") {
alert("🚧 Development Mode aktiviert Mock-Daten werden verwendet!");
console.log("🚧 Development Mode aktiviert Mock-Daten werden verwendet!");
} else {
console.log("Production Mode aktiviert");
}
}, []);
//---------------------------------------------

View File

@@ -143,7 +143,9 @@ function MapLayersControlPanel() {
//------------------------------
useEffect(() => {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("🔍 GisStationsStaticDistrict Inhalt:", GisStationsStaticDistrict);
}
if (!GisStationsStaticDistrict) {
console.warn("⚠️ GisStationsStaticDistrict ist `null` oder nicht geladen.");
@@ -172,8 +174,9 @@ function MapLayersControlPanel() {
}
return isUnique;
});
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("📌 stationListing aktualisiert:", filteredAreas);
}
}, [GisStationsStaticDistrict, GisSystemStatic]);
//---------------------------

View File

@@ -1,2 +1,2 @@
// /config/appVersion
export const APP_VERSION = "1.1.235";
export const APP_VERSION = "1.1.236";

View File

@@ -90,7 +90,9 @@ const useAreaMarkersLayer = (map, oms, apiUrl, onUpdateSuccess) => {
newCoords: { x: lat, y: lng },
})
).unwrap();
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("✔️ Koordinaten erfolgreich aktualisiert:", { lat, lng });
}
onUpdateSuccess?.(); // optionaler Callback
} catch (error) {
console.error("❌ Fehler beim Aktualisieren der Koordinaten:", error);

View File

@@ -62,7 +62,7 @@ export class OverlappingMarkerSpiderfier {
}
nearbyMarkers(marker) {
return this.markers.filter((m) => {
return this.markers.filter(m => {
const distance = this.map.distance(marker.getLatLng(), m.getLatLng());
return distance < this.nearbyDistance && marker !== m;
});
@@ -74,7 +74,10 @@ export class OverlappingMarkerSpiderfier {
markers.forEach((marker, i) => {
const angle = this.circleStartAngle + (i * 2 * Math.PI) / markers.length;
const legLength = this.circleFootSeparation * (2 + i / markers.length);
const newPt = L.point(centerPt.x + legLength * Math.cos(angle), centerPt.y + legLength * Math.sin(angle));
const newPt = L.point(
centerPt.x + legLength * Math.cos(angle),
centerPt.y + legLength * Math.sin(angle)
);
const newLatLng = this.map.layerPointToLatLng(newPt);
if (!marker._oms) {
@@ -99,7 +102,7 @@ export class OverlappingMarkerSpiderfier {
//---------------------------------------------------------------------------------------------
unspiderfy() {
this.markers.forEach((marker) => {
this.markers.forEach(marker => {
if (marker._oms && marker._oms.spidered) {
// Falls eine Linie existiert, entferne sie aus der Karte
if (marker._oms.leg) {
@@ -115,7 +118,9 @@ export class OverlappingMarkerSpiderfier {
// 🔥 Künstliches Click-Event auslösen, um die UI zu aktualisieren
setTimeout(() => {
this.map.fire("click");
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("Click-Event ausgelöst in OverlappingMarkerspiderfier.js in unspiderfy ");
}
}, 10); // Kurze Verzögerung, um sicherzustellen, dass die UI neu gerendert wird
}

133
pages/api/health.js Normal file
View File

@@ -0,0 +1,133 @@
// /pages/api/health.js
export default async function handler(req, res) {
const basePath = "talas5";
const protocol = "http";
const hostname = "10.10.0.70";
const port = "80";
const idMap = "12";
const idUser = "484";
const idLD = "50922";
const buildUrl = method =>
`${protocol}://${hostname}:${port}/${basePath}/ClientData/WebServiceMap.asmx/${method}?idMap=${idMap}&idUser=${idUser}`;
const externalUrls = {
GisStationsStaticDistrict: buildUrl("GisStationsStaticDistrict"),
GisLinesStatus: `${protocol}://${hostname}:${port}/${basePath}/ClientData/WebServiceMap.asmx/GisLinesStatus?idMap=${idMap}`,
GisStationsMeasurements: buildUrl("GisStationsMeasurements"),
GisStationsStatusDistrict: buildUrl("GisStationsStatusDistrict"),
GisSystemStatic: buildUrl("GisSystemStatic"),
};
const internalApiBase = "http://localhost:3000";
const internalApis = {
//area
readArea: `${internalApiBase}/api/talas_v5_DB/area/readArea?m=${idMap}`,
//device
getAllStationsNames: `${internalApiBase}/api/talas_v5_DB/device/getAllStationsNames`,
getDevices: `${internalApiBase}/api/talas_v5_DB/device/getDevices`,
//gisLines
readGisLines: `${internalApiBase}/api/talas_v5_DB/gisLines/readGisLines`,
//locationDevice
getDeviceId: `${internalApiBase}/api/talas_v5_DB/locationDevice/getDeviceId`,
locationDeviceNameById: `${internalApiBase}/api/talas_v5_DB/locationDevice/locationDeviceNameById?idLD=${idLD}`,
locationDevices: `${internalApiBase}/api/talas_v5_DB/locationDevice/locationDevices`,
//pois
addPoi: `${internalApiBase}/api/talas_v5_DB/pois/addPoi`,
deletePoi: `${internalApiBase}/api/talas_v5_DB/pois/deletePoi`,
getPoiById: `${internalApiBase}/api/talas_v5_DB/pois/getPoiById`,
poiIcons: `${internalApiBase}/api/talas_v5_DB/pois/poi-icons`,
readAllPOIs: `${internalApiBase}/api/talas_v5_DB/pois/readAllPOIs`,
updateLocation: `${internalApiBase}/api/talas_v5_DB/pois/updateLocation`,
updatePoi: `${internalApiBase}/api/talas_v5_DB/pois/updatePoi`,
//poiTyp
readPoiTyp: `${internalApiBase}/api/talas_v5_DB/poiTyp/readPoiTyp`,
//station
getAllStationsNames: `${internalApiBase}/api/talas_v5_DB/station/getAllStationsNames`,
getDevices: `${internalApiBase}/api/talas_v5_DB/station/getDevices`,
//
priorityConfig: `${internalApiBase}/api/talas_v5_DB/priorityConfig`,
};
const results = {};
// Prüfe externe Webservices
await Promise.all(
Object.entries(externalUrls).map(async ([name, url]) => {
try {
const response = await fetch(url);
results[name] = {
ok: response.ok,
status: response.status,
url,
};
if (name === "GisSystemStatic" && response.ok) {
const data = await response.json();
results["UserRights"] = {
ok: Array.isArray(data.Rights),
length: data.Rights?.length || 0,
};
}
} catch (error) {
results[name] = {
ok: false,
error: error.message,
url,
};
}
})
);
// Prüfe interne API-Routen
await Promise.all(
Object.entries(internalApis).map(async ([name, url]) => {
try {
const response = await fetch(url);
results[`API_${name}`] = {
ok: response.ok,
status: response.status,
url,
};
} catch (error) {
results[`API_${name}`] = {
ok: false,
error: error.message,
url,
};
}
})
);
// Prüfe Mock-Status
const useMocksEnv = process.env.NEXT_PUBLIC_USE_MOCKS;
results["MockMode"] = {
expected: "false",
actual: useMocksEnv,
ok: useMocksEnv === "false",
info:
useMocksEnv === "false"
? "✅ Mockdaten deaktiviert Live-Daten aktiv."
: "⚠️ Mockdaten aktiv nicht für Produktion geeignet!",
};
// Prüfe Konfiguration der .env.production
results["envConfig"] = {
NODE_ENV: process.env.NODE_ENV || "undefined",
DB_HOST: process.env.DB_HOST || "❌ fehlt",
NEXT_PUBLIC_USE_MOCKS: useMocksEnv || "❌ fehlt",
status:
process.env.NODE_ENV === "production" && useMocksEnv === "false" && process.env.DB_HOST
? "✅ .env.production scheint korrekt."
: "⚠️ Bitte .env.production prüfen möglicherweise fehlt etwas.",
};
const allOk = Object.values(results).every(r => r.ok);
res.status(allOk ? 200 : 207).json({
status: allOk ? "ok" : "partial",
version: "1.0.0",
services: results,
});
}

BIN
pages/api/talas_v5_DB.zip Normal file

Binary file not shown.

View File

@@ -2,7 +2,9 @@
import getPool from "../../../../utils/mysqlPool";
export default async function handler(req, res) {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("Request erhalten:", req.method, req.body); // Debugging
}
const pool = getPool();
@@ -15,7 +17,9 @@ export default async function handler(req, res) {
const { idLocation, idMap, x, y } = req.body;
if (!idLocation || !idMap || x === undefined || y === undefined) {
return res.status(400).json({ error: "Alle Felder (idLocation, idMap, x, y) sind erforderlich" });
return res
.status(400)
.json({ error: "Alle Felder (idLocation, idMap, x, y) sind erforderlich" });
}
let connection;
@@ -23,18 +27,25 @@ export default async function handler(req, res) {
try {
// Verbindung zur Datenbank herstellen
connection = await pool.getConnection();
const query = "UPDATE location_coordinates SET x = ?, y = ? WHERE idLocation = ? AND idMaps = ?";
const query =
"UPDATE location_coordinates SET x = ?, y = ? WHERE idLocation = ? AND idMaps = ?";
const [result] = await connection.query(query, [x, y, idLocation, idMap]);
// Erfolgreiche Aktualisierung prüfen
if (result.affectedRows > 0) {
return res.status(200).json({ success: true, message: "Koordinaten erfolgreich aktualisiert" });
return res
.status(200)
.json({ success: true, message: "Koordinaten erfolgreich aktualisiert" });
} else {
return res.status(404).json({ error: "Kein Eintrag gefunden, der aktualisiert werden konnte" });
return res
.status(404)
.json({ error: "Kein Eintrag gefunden, der aktualisiert werden konnte" });
}
} catch (error) {
console.error("Fehler beim Aktualisieren der Koordinaten:", error);
return res.status(500).json({ error: "Interner Serverfehler beim Aktualisieren der Koordinaten" });
return res
.status(500)
.json({ error: "Interner Serverfehler beim Aktualisieren der Koordinaten" });
} finally {
if (connection) {
connection.release();

View File

@@ -1,5 +1,5 @@
// /pages/api/talas_v5_DB/device/getDevices.js
import getPool from "../../../../utils/mysqlPool"; // Import Singleton-Pool
import getPool from "@/utils/mysqlPool"; // Import Singleton-Pool
// API-Handler
export default async function handler(req, res) {

View File

@@ -13,9 +13,12 @@ export default async function handler(req, res) {
return res.status(400).json({ error: "Fehlende Daten" });
}
const newLineString = `LINESTRING(${newCoordinates.map((coord) => `${coord[0]} ${coord[1]}`).join(",")})`;
const newLineString = `LINESTRING(${newCoordinates
.map(coord => `${coord[0]} ${coord[1]}`)
.join(",")})`;
const query = "UPDATE talas_v5.gis_lines SET points = ST_GeomFromText(?) WHERE idLD = ? AND idModul = ?;";
const query =
"UPDATE talas_v5.gis_lines SET points = ST_GeomFromText(?) WHERE idLD = ? AND idModul = ?;";
let connection;
@@ -31,8 +34,9 @@ export default async function handler(req, res) {
// Commit der Transaktion
await connection.commit();
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("Transaction Complete.");
}
res.status(200).json({
success: "Updated successfully.",
affectedRows: results.affectedRows,

View File

@@ -6,9 +6,12 @@ export default async function handler(req, res) {
if (req.method === "POST") {
const { name, poiTypeId, latitude, longitude, idLD } = req.body;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("Received data:", req.body); // Überprüfen der empfangenen Daten
}
const query = "INSERT INTO poi (description, idPoiTyp, position, idLD) VALUES (?, ?, ST_GeomFromText(?),?)";
const query =
"INSERT INTO poi (description, idPoiTyp, position, idLD) VALUES (?, ?, ST_GeomFromText(?),?)";
const point = `POINT(${longitude} ${latitude})`;
const values = [name, poiTypeId, point, idLD];

View File

@@ -9,15 +9,16 @@ import { addPoiThunk } from "../redux/thunks/database/pois/addPoiThunk";
import { selectPoiMarkers } from "../redux/slices/database/pois/poiMarkersSlice";
import { selectAddPoiStatus, selectAddPoiError } from "../redux/slices/database/pois/addPoiSlice";
const MapComponentWithNoSSR = dynamic(() => import("../components/mainComponent/MapComponent"), { ssr: false });
const TestScriptWithNoSSR = dynamic(() => import("../components/TestScript"), { ssr: false });
const MapComponentWithNoSSR = dynamic(() => import("../components/mainComponent/MapComponent"), {
ssr: false,
});
export default function Home() {
const dispatch = useDispatch();
// Redux State
const locations = useSelector(selectPoiMarkers);
const poiReadTrigger = useSelector((state) => state.poiReadFromDbTrigger.trigger);
const poiReadTrigger = useSelector(state => state.poiReadFromDbTrigger.trigger);
const addPoiStatus = useSelector(selectAddPoiStatus);
const addPoiError = useSelector(selectAddPoiError);
@@ -27,7 +28,7 @@ export default function Home() {
// URL-Parameter auslesen und POIs laden
useEffect(() => {
const getURLParameter = (name) => {
const getURLParameter = name => {
const params = new URLSearchParams(window.location.search);
return params.get(name);
};
@@ -58,7 +59,6 @@ export default function Home() {
return (
<div>
<MapComponentWithNoSSR locations={locations} onAddLocation={handleAddLocation} />
<TestScriptWithNoSSR />
{addPoiStatus === "failed" && <p className="text-red-600"> Fehler: {addPoiError}</p>}
</div>

View File

@@ -31,5 +31,6 @@ const newContent = content.replace(versionRegex, `export const APP_VERSION = "${
// Datei speichern
fs.writeFileSync(versionFilePath, newContent, "utf8");
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log(`✅ Version erhöht auf: ${newVersion}`);
}

BIN
services/database.zip Normal file

Binary file not shown.

View File

@@ -3,7 +3,11 @@ export const fetchGisLinesStatusService = async () => {
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";
if (useMocks) {
console.log("🧪 Mock-Modus aktiviert: fetchGisLinesStatusService");
const mockBasePath = "/api/mocks/webservice/gisLinesStatus";
const mockURL = `${window.location.origin}${mockBasePath}`;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("🧪 Mock-Modus aktiviert: fetchGisLinesStatusService ", mockURL);
}
const response = await fetch("/api/mocks/webservice/gisLinesStatus");
if (!response.ok) {
@@ -24,7 +28,9 @@ export const fetchGisLinesStatusService = async () => {
const idMap = params.get("m");
const url = `${baseUrl}/GisLinesStatus?idMap=${idMap}`;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("📡 fetchGisLinesStatusService URL:", url);
}
const response = await fetch(url);
if (!response.ok) {

View File

@@ -3,7 +3,11 @@ export const fetchGisStationsMeasurementsService = async () => {
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";
if (useMocks) {
console.log("🧪 Mock-Modus aktiviert: fetchGisStationsMeasurementsService");
const mockBasePath = "/api/mocks/webservice/gisStationsMeasurements";
const mockURL = `${window.location.origin}${mockBasePath}`;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("🧪 Mock-Modus aktiviert: fetchGisStationsMeasurementsService ", mockURL);
}
const response = await fetch("/api/mocks/webservice/gisStationsMeasurements");
if (!response.ok) {
@@ -24,7 +28,9 @@ export const fetchGisStationsMeasurementsService = async () => {
const idUser = params.get("u");
const url = `${baseUrl}/GisStationsMeasurements?idMap=${idMap}&idUser=${idUser}`;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("📡 fetchGisStationsMeasurementsService URL:", url);
}
const response = await fetch(url);
if (!response.ok) {

View File

@@ -10,7 +10,11 @@ export const fetchGisStationsStaticDistrictService = async () => {
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";
if (useMocks) {
console.log("🧪 Mock-Modus aktiviert: fetchGisStationsStaticDistrictService");
const mockBasePath = "/api/mocks/webservice/gisStationsStaticDistrict";
const mockURL = `${window.location.origin}${mockBasePath}`;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("🧪 Mock-Modus aktiviert: fetchGisStationsStaticDistrictService ", mockURL);
}
const res = await fetch("/api/mocks/webservice/gisStationsStaticDistrict");
if (!res.ok) {
@@ -31,7 +35,9 @@ export const fetchGisStationsStaticDistrictService = async () => {
const idUser = params.get("u");
const url = `${baseUrl}/GisStationsStaticDistrict?idMap=${idMap}&idUser=${idUser}`;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("📡 fetchGisStationsStaticDistrictService URL:", url);
}
const response = await fetch(url);
if (!response.ok) {

View File

@@ -10,7 +10,11 @@ export const fetchGisStationsStatusDistrictService = async () => {
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";
if (useMocks) {
console.log("🧪 Mock-Modus aktiviert: fetchGisStationsStatusDistrictService");
const mockBasePath = "/api/mocks/webservice/gisStationsStatusDistrict";
const mockURL = `${window.location.origin}${mockBasePath}`;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("🧪 Mock-Modus aktiviert: fetchGisStationsStatusDistrictService ", mockURL);
}
const response = await fetch("/api/mocks/webservice/gisStationsStatusDistrict");
if (!response.ok) {
@@ -31,7 +35,9 @@ export const fetchGisStationsStatusDistrictService = async () => {
const idUser = params.get("u");
const url = `${baseUrl}/GisStationsStatusDistrict?idMap=${idMap}&idUser=${idUser}`;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("📡 fetchGisStationsStatusDistrictService URL:", url);
}
const response = await fetch(url);
if (!response.ok) {

View File

@@ -9,7 +9,11 @@ export const fetchGisSystemStaticService = async () => {
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";
if (useMocks) {
console.log("🧪 Mock-Modus aktiviert: fetchGisSystemStaticService");
const mockBasePath = "/api/mocks/webservice/gisSystemStatic";
const mockURL = `${window.location.origin}${mockBasePath}`;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("🧪 Mock-Modus aktiviert: fetchGisSystemStaticService ", mockURL);
}
const response = await fetch("/api/mocks/webservice/gisSystemStatic ");
if (!response.ok) {
@@ -30,7 +34,9 @@ export const fetchGisSystemStaticService = async () => {
const idUser = params.get("u");
const url = `${baseUrl}/GisSystemStatic?idMap=${idMap}&idUser=${idUser}`;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("📡 fetchGisSystemStaticService von service URL:", url);
}
const response = await fetch(url);
if (!response.ok) {

View File

@@ -9,7 +9,11 @@ export const fetchUserRightsService = async () => {
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";
if (useMocks) {
console.log("🧪 Mock-Modus aktiviert: fetchUserRightsService");
const mockBasePath = "/api/mocks/webservice/gisSystemStatic";
const mockURL = `${window.location.origin}${mockBasePath}`;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("🧪 Mock-Modus aktiviert: fetchUserRightsService ", mockURL);
}
const response = await fetch("/api/mocks/webservice/gisSystemStatic "); //gisSystemStatic enthält die Systeme (Systems) und die User Rechte (Rights)
if (!response.ok) {
@@ -26,7 +30,9 @@ export const fetchUserRightsService = async () => {
const idUser = params.get("u");
const url = `${baseUrl}/GisSystemStatic?idMap=${idMap}&idUser=${idUser}`;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("🔍 Rechte-Fetch URL:", url);
}
const response = await fetch(url, {
method: "GET",
@@ -40,7 +46,9 @@ export const fetchUserRightsService = async () => {
}
const json = await response.json();
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("👤 Rechte-Response JSON:", json);
}
return json.Rights || [];
}

View File

@@ -5,7 +5,15 @@ import "leaflet/dist/leaflet.css";
import "leaflet-contextmenu/dist/leaflet.contextmenu.css";
import "overlapping-marker-spiderfier-leaflet";
export const initializeMap = (mapRef, setMap, setOms, setMenuItemAdded, addItemsToMapContextMenu, hasRights, setPolylineEventsDisabled) => {
export const initializeMap = (
mapRef,
setMap,
setOms,
setMenuItemAdded,
addItemsToMapContextMenu,
hasRights,
setPolylineEventsDisabled
) => {
const basePath = process.env.NEXT_PUBLIC_BASE_PATH;
if (!mapRef.current) {
@@ -14,7 +22,9 @@ export const initializeMap = (mapRef, setMap, setOms, setMenuItemAdded, addItems
}
if (mapRef.current._leaflet_id) {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("⚠️ Karte bereits initialisiert");
}
return;
}

View File

@@ -2,7 +2,7 @@
import L from "leaflet";
// Call this function on page load to restore zoom and center
export const restoreMapSettings = (map) => {
export const restoreMapSettings = map => {
const savedZoom = localStorage.getItem("mapZoom");
const savedCenter = localStorage.getItem("mapCenter");
@@ -29,7 +29,7 @@ export const checkOverlappingMarkers = (map, markers, plusIcon, oms) => {
const overlappingGroups = {};
markers.forEach((marker) => {
markers.forEach(marker => {
if (map.hasLayer(marker)) {
const latlngStr = marker.getLatLng().toString();
if (overlappingGroups[latlngStr]) {
@@ -40,7 +40,7 @@ export const checkOverlappingMarkers = (map, markers, plusIcon, oms) => {
}
});
plusMarkers.forEach((plusMarker) => map.removeLayer(plusMarker));
plusMarkers.forEach(plusMarker => map.removeLayer(plusMarker));
plusMarkers = [];
for (const coords in overlappingGroups) {
@@ -62,18 +62,26 @@ export const checkOverlappingMarkers = (map, markers, plusIcon, oms) => {
export const handlePlusIconClick = (map, markers, oms, clickedLatLng) => {
// Debugging-Ausgabe
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("Plus-Icon Position:", clickedLatLng);
}
// Finde Marker in der Nähe der Klickposition
const nearbyMarkers = markers.filter((marker) => map.distance(marker.getLatLng(), clickedLatLng) < 50);
const nearbyMarkers = markers.filter(
marker => map.distance(marker.getLatLng(), clickedLatLng) < 50
);
// Debugging-Ausgabe
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("Gefundene Marker in der Nähe:", nearbyMarkers);
}
if (oms && nearbyMarkers.length > 0) {
// Spiderfy die gefundenen Marker
oms.spiderfy(nearbyMarkers);
} else {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("Keine überlappenden Marker gefunden.");
}
}
};

View File

@@ -26,24 +26,32 @@ function getPool() {
cachedPool.on("acquire", () => {
connectionCount++;
if (process.env.NODE_ENV === "development") {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("\x1b[36m%s\x1b[0m", ` Connection acquired (${connectionCount} total)`);
}
if (connectionCount > maxUsed) {
maxUsed = connectionCount;
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log(`📈 Neue Höchstzahl aktiver gleichzeitiger Verbindungen: ${maxUsed}`);
}
}
}
});
cachedPool.on("release", () => {
connectionCount--;
if (process.env.NODE_ENV === "development") {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("\x1b[32m%s\x1b[0m", ` Connection released (${connectionCount} total)`);
}
}
});
cachedPool.on("enqueue", () => {
if (process.env.NODE_ENV === "development") {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.warn("\x1b[33m%s\x1b[0m", "⏳ Pool voll Anfrage in Warteschlange");
}
}
});
}

View File

@@ -28,7 +28,9 @@ export function openInNewTab(e, target) {
}
if (link) {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("🟢 Öffne Link:", link);
}
window.open(link, "_blank");
} else {
console.error("❌ Kein gültiger Link gefunden.");

View File

@@ -2,7 +2,6 @@
export function openInSameWindow(e, marker, baseUrl) {
if (marker && marker.options && marker.options.link) {
//console.log("Marker data:", baseUrl + marker.options.link);
window.location.href = baseUrl + marker.options.link;
} else {
console.error("Fehler: Marker hat keine gültige 'link' Eigenschaft");

View File

@@ -6,7 +6,9 @@ export function subscribeToPolylineContextMenu() {
store.subscribe(() => {
const state = store.getState(); // Redux-Toolkit empfohlene Methode
if (state.polylineContextMenu.forceClose) {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("🚀 Redux-Event erkannt - Kontextmenü wird geschlossen.");
}
store.dispatch(closePolylineContextMenu());
if (window.map && window.map.contextmenu) {

View File

@@ -7,14 +7,27 @@ import endIcon from "../../components/gisPolylines/icons/EndIcon";
import { redrawPolyline } from "./redrawPolyline";
import { toast } from "react-toastify";
import { store } from "../../redux/store"; // Importiere den Store
import { openPolylineContextMenu, closePolylineContextMenu } from "../../redux/slices/database/polylines/polylineContextMenuSlice";
import {
openPolylineContextMenu,
closePolylineContextMenu,
} from "../../redux/slices/database/polylines/polylineContextMenuSlice";
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) => {
export const setupPolylines = (
map,
linePositions,
lineColors,
tooltipContents,
setNewCoords,
tempMarker,
currentZoom,
currentCenter,
polylineVisible
) => {
const mode = process.env.NEXT_PUBLIC_API_PORT_MODE;
const basePath = process.env.NEXT_PUBLIC_BASE_PATH || "";
if (!polylineVisible) {
@@ -25,7 +38,7 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
if (!polylineVisible) {
// Entferne alle Polylinien, wenn sie ausgeblendet werden sollen
if (window.polylines) {
window.polylines.forEach((polyline) => {
window.polylines.forEach(polyline => {
if (map.hasLayer(polyline)) {
map.removeLayer(polyline);
}
@@ -38,8 +51,6 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
const editMode = localStorage.getItem("editMode") === "true"; // Prüfen, ob der Bearbeitungsmodus aktiv ist
linePositions.forEach((lineData, lineIndex) => {
//console.log("LineData:", lineData.idLD, lineData.idModul);
// **Fix: Sicherstellen, dass activeLines definiert ist und idLD existiert**
const lineMarkers = [];
@@ -74,10 +85,13 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
color: lineColors[`${lineData.idLD}-${lineData.idModul}`] || "#000000",
}).addTo(map);
updatedPolyline.bindTooltip(tooltipContents[`${lineData.idLD}-${lineData.idModul}`] || "Tooltip", {
updatedPolyline.bindTooltip(
tooltipContents[`${lineData.idLD}-${lineData.idModul}`] || "Tooltip",
{
permanent: false,
direction: "auto",
});
}
);
updatedPolyline.on("mouseover", () => updatedPolyline.setStyle({ weight: 20 }));
updatedPolyline.on("mouseout", () => updatedPolyline.setStyle({ weight: 3 }));
@@ -95,10 +109,12 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
store
.dispatch(updatePolylineCoordinatesThunk(requestData))
.unwrap()
.then((data) => {
.then(data => {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("Koordinaten erfolgreich aktualisiert:", data);
}
})
.catch((error) => {
.catch(error => {
console.error("Fehler beim Aktualisieren der Koordinaten:", error.message);
});
} else {
@@ -150,32 +166,34 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
{
text: "Station öffnen (Tab)",
icon: "/img/screen_new.png",
callback: (e) => openInNewTab(e, lineData),
callback: e => openInNewTab(e, lineData),
},
{ separator: true },
{
text: "Koordinaten anzeigen",
icon: "/img/not_listed_location.png",
callback: (e) => {
alert("Breitengrad: " + e.latlng.lat.toFixed(5) + "\nLängengrad: " + e.latlng.lng.toFixed(5));
callback: e => {
alert(
"Breitengrad: " + e.latlng.lat.toFixed(5) + "\nLängengrad: " + e.latlng.lng.toFixed(5)
);
},
},
{ separator: true },
{
text: "Reinzoomen",
icon: "/img/zoom_in.png",
callback: (e) => map.zoomIn(),
callback: e => map.zoomIn(),
},
{
text: "Rauszoomen",
icon: "/img/zoom_out.png",
callback: (e) => map.zoomOut(),
callback: e => map.zoomOut(),
},
{
text: "Hier zentrieren",
icon: "/img/center_focus.png",
callback: (e) => map.panTo(e.latlng),
callback: e => map.panTo(e.latlng),
},
{ separator: true },
/* {
@@ -189,7 +207,7 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
{
text: "Stützpunkt hinzufügen",
icon: "/img/icons/gisLines/add-support-point.svg",
callback: (e) => {
callback: e => {
if (tempMarker) {
tempMarker.remove();
}
@@ -206,10 +224,13 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
{
text: "Station öffnen (Tab)",
icon: "/img/screen_new.png",
callback: (e) => {
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 baseUrl =
mode === "dev"
? `${window.location.protocol}//${window.location.hostname}:80${basePath}/`
: `${window.location.origin}${basePath}/`;
const link = `${baseUrl}devices/cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`;
@@ -221,26 +242,28 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
{
text: "Koordinaten anzeigen",
icon: "/img/not_listed_location.png",
callback: (e) => {
alert("Breitengrad: " + e.latlng.lat.toFixed(5) + "\nLängengrad: " + e.latlng.lng.toFixed(5));
callback: e => {
alert(
"Breitengrad: " + e.latlng.lat.toFixed(5) + "\nLängengrad: " + e.latlng.lng.toFixed(5)
);
},
},
{ separator: true },
{
text: "Reinzoomen",
icon: "/img/zoom_in.png",
callback: (e) => map.zoomIn(),
callback: e => map.zoomIn(),
},
{
text: "Rauszoomen",
icon: "/img/zoom_out.png",
callback: (e) => map.zoomOut(),
callback: e => map.zoomOut(),
},
{
text: "Hier zentrieren",
icon: "/img/center_focus.png",
callback: (e) => map.panTo(e.latlng),
callback: e => map.panTo(e.latlng),
},
{ separator: true }
/* {
@@ -254,32 +277,33 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
}
// Hier wird der Tooltip hinzugefügt
polyline.bindTooltip(tooltipContents[`${lineData.idLD}-${lineData.idModul}`] || "Standard-Tooltip-Inhalt setup", {
polyline.bindTooltip(
tooltipContents[`${lineData.idLD}-${lineData.idModul}`] || "Standard-Tooltip-Inhalt setup",
{
permanent: false,
direction: "auto",
});
}
);
polyline.on("mouseover", (e) => {
polyline.on("mouseover", e => {
const startTime = Date.now(); // Startzeit erfassen
polyline.setStyle({ weight: 14 });
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 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}`;
// console.log("Link der Linie:", link);
});
// error TypeError: Cannot read properties of null (reading 'contextmenu') wenn der Mas auf die Linie bleibt
polyline.on("mouseout", (e) => {
polyline.on("mouseout", e => {
polyline.setStyle({ weight: 3 });
//console.log("🚀 Maus hat die Polyline verlassen - Warten auf Klick außerhalb des Menüs.");
document.addEventListener("click", function handleOutsideClick(event) {
if (!event.target.closest(".leaflet-contextmenu")) {
//console.log("🛑 Klick außerhalb des Kontextmenüs erkannt - Schließe Menü.");
try {
store.dispatch(closePolylineContextMenu());
store.dispatch(forceCloseContextMenu());
@@ -296,7 +320,7 @@ export const setupPolylines = (map, linePositions, lineColors, tooltipContents,
}
});
});
polyline.on("contextmenu", (e) => {
polyline.on("contextmenu", e => {
store.dispatch(
openPolylineContextMenu({
position: { lat: e.latlng.lat, lng: e.latlng.lng },

View File

@@ -4,12 +4,16 @@ import { setSelectedDevice, clearSelectedDevice } from "../redux/slices/selected
export const setupDevices = async (map, deviceMarkers, dispatch) => {
for (const marker of deviceMarkers) {
marker.on("mouseover", function () {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("✅ Gerät ausgewählt:", marker);
}
dispatch(setSelectedDevice(marker.options)); // Gerät in Redux speichern
});
marker.on("mouseout", function () {
if (process.env.NEXT_PUBLIC_DEBUG_LOG === "true") {
console.log("❌ Gerät abgewählt");
}
dispatch(clearSelectedDevice()); // Gerät aus Redux entfernen
});