Merge branch 'develop'
This commit is contained in:
44
.env.local
44
.env.local
@@ -1,11 +1,45 @@
|
||||
#.env.local
|
||||
#je nach dem Mysql Server, ob localhost freigegeben ist oder die IP Adresse des Servers, manchmal die beide und manchmal nur eine
|
||||
DB_HOST=localhost #HTTP error! status: 500 wenn auf dem Server ist
|
||||
#DB_HOST=192.168.10.58
|
||||
|
||||
#DB_HOST=10.10.0.13
|
||||
#DB_HOST=10.10.0.70 # auf localhost blockiert
|
||||
#DB_USER=root
|
||||
#DB_PASSWORD="root#$"
|
||||
#DB_NAME=talas_v5
|
||||
#DB_PORT=3306
|
||||
#########################
|
||||
|
||||
#NEXT_PUBLIC_BASE_URL="http://10.10.0.13/talas5/devices/"
|
||||
#NEXT_PUBLIC_SERVER_URL="http://10.10.0.13"
|
||||
#NEXT_PUBLIC_PROXY_TARGET="http://10.10.0.13"
|
||||
#NEXT_PUBLIC_ONLINE_TILE_LAYER="http://10.10.0.13:3000/mapTiles/{z}/{x}/{y}.png"
|
||||
#########################
|
||||
|
||||
|
||||
DB_HOST=10.10.0.70
|
||||
DB_USER=root
|
||||
DB_PASSWORD="root#$"
|
||||
DB_NAME=talas_v5
|
||||
DB_PORT=3306
|
||||
######################### Kontetmenü -> Station in tab öffnen
|
||||
#BASE_URL=http://10.10.0.13/talas5/devices/
|
||||
|
||||
#########################
|
||||
#device nur Verlinkung wenn die gleiche DB ist
|
||||
NEXT_PUBLIC_BASE_URL="http://10.10.0.70/talas5/devices/"
|
||||
NEXT_PUBLIC_SERVER_URL="http://10.10.0.70"
|
||||
NEXT_PUBLIC_PROXY_TARGET="http://10.10.0.70"
|
||||
#NEXT_PUBLIC_ONLINE_TILE_LAYER="http://10.10.0.13:3000/mapTiles/{z}/{x}/{y}.png"
|
||||
#########################
|
||||
|
||||
#DB_HOST=192.168.10.168
|
||||
#DB_USER=root
|
||||
#DB_PASSWORD="root#$"
|
||||
#DB_NAME=talas_v5
|
||||
#DB_PORT=3306
|
||||
#########################
|
||||
#URLs für den Client (clientseitig)
|
||||
#NEXT_PUBLIC_BASE_URL="http://192.168.10.168/talas5/devices/"
|
||||
#NEXT_PUBLIC_SERVER_URL="http://192.168.10.168"
|
||||
#NEXT_PUBLIC_PROXY_TARGET="http://192.168.10.168"
|
||||
#NEXT_PUBLIC_ONLINE_TILE_LAYER="http://192.168.10.14:3000/mapTiles/{z}/{x}/{y}.png"
|
||||
|
||||
######################### online
|
||||
NEXT_PUBLIC_ONLINE_TILE_LAYER="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
3
.prettierrc
Normal file
3
.prettierrc
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"printWidth": 250
|
||||
}
|
||||
1
.vscode/settings.json
vendored
Normal file
1
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
43
Jenkinsfile
vendored
43
Jenkinsfile
vendored
@@ -2,31 +2,36 @@ pipeline {
|
||||
agent any
|
||||
|
||||
stages {
|
||||
stage('Checkout SCM') {
|
||||
steps {
|
||||
checkout([$class: 'GitSCM', branches: [[name: '**']],
|
||||
doGenerateSubmoduleConfigurations: false,
|
||||
extensions: [],
|
||||
userRemoteConfigs: [[url: 'http://172.20.0.2:3000/Ismail/NodeMap', credentialsId: 'd378f013-2f24-417b-9afd-33df5d410ab8']]])
|
||||
}
|
||||
}
|
||||
stage('Check Node.js Version') {
|
||||
steps {
|
||||
script {
|
||||
def nodeVersion = sh(script: 'node --version', returnStdout: true).trim()
|
||||
echo "Node.js version: ${nodeVersion}"
|
||||
}
|
||||
}
|
||||
}
|
||||
stage('Install Dependencies') {
|
||||
steps {
|
||||
// Installiere npm Abhängigkeiten
|
||||
sh 'npm install'
|
||||
script {
|
||||
sh 'npm install'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Run Tests') {
|
||||
stage('Run Unit Tests') {
|
||||
steps {
|
||||
// Führt Ihre Tests aus
|
||||
sh 'npm test'
|
||||
script {
|
||||
sh 'npm test'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
// Archivieren Sie die Testberichte, wenn verfügbar
|
||||
junit '**/test-results.xml'
|
||||
}
|
||||
success {
|
||||
echo 'Die Tests wurden erfolgreich abgeschlossen!'
|
||||
}
|
||||
failure {
|
||||
echo 'Einige Tests sind fehlgeschlagen.'
|
||||
}
|
||||
// Weitere Stages ...
|
||||
}
|
||||
}
|
||||
|
||||
BIN
NodeMap.pdf
Normal file
BIN
NodeMap.pdf
Normal file
Binary file not shown.
2
Wiki.md
2
Wiki.md
@@ -146,7 +146,7 @@ Bei Problemen während der Weiterentwicklung könnte es hilfreich sein, die Seit
|
||||
- **DataSheet.js**: Verantwortlich für die Anzeige und Interaktion mit den Layer- und Stationsauswahlen. Ermöglicht das Aktivieren/Deaktivieren von Layern und zeigt Informationen zu geografischen Punkten.
|
||||
- **MapComponent.js**: Kernkomponente für die Darstellung der Karte. Beinhaltet Logik für das Hinzufügen von Layern, Zoom-Funktionen und andere interaktive Elemente.
|
||||
- **PoiUpdateModal.js**:Komponente zum Aktualisieren(update) und löschen von Pois.
|
||||
- **ShowAddStationPopup.js**:Komponente zum hinzufügen von Pois.
|
||||
- **AddPoiModalWindow.js**:Komponente zum hinzufügen von Pois.
|
||||
|
||||
### /public
|
||||
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
module.exports = {
|
||||
map: () => ({
|
||||
setView: jest.fn(),
|
||||
addLayer: jest.fn(),
|
||||
}),
|
||||
tileLayer: () => ({
|
||||
addTo: jest.fn(),
|
||||
}),
|
||||
marker: () => ({
|
||||
addTo: jest.fn(),
|
||||
}),
|
||||
// __mocks__/leaflet.js
|
||||
const L = {
|
||||
divIcon: jest.fn(() => new L.DivIcon()),
|
||||
DivIcon: function () {
|
||||
this.options = {
|
||||
className: "custom-start-icon",
|
||||
html: `
|
||||
<svg width="18" height="18" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<polygon points="10,2 18,18 2,18" fill="black" />
|
||||
<polygon points="10,5 16,16 4,16" fill="gray" />
|
||||
</svg>
|
||||
`,
|
||||
iconSize: [18, 18],
|
||||
iconAnchor: [9, 10],
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
L.DivIcon.prototype = {
|
||||
constructor: L.DivIcon,
|
||||
};
|
||||
|
||||
module.exports = L;
|
||||
|
||||
82
__tests__/unit/components/DataSheet.test.js
Normal file
82
__tests__/unit/components/DataSheet.test.js
Normal file
@@ -0,0 +1,82 @@
|
||||
// __tests__/components/DataSheet.test.js
|
||||
import React from "react";
|
||||
import { render, screen, waitFor } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import DataSheet from "../../components/DataSheet";
|
||||
import { RecoilRoot } from "recoil";
|
||||
import * as Recoil from "recoil";
|
||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil";
|
||||
import { gisStationsStaticDistrictState } from "../../store/atoms/gisStationState";
|
||||
import { gisSystemStaticState } from "../../store/atoms/gisSystemState";
|
||||
import { mapLayersState } from "../../store/atoms/mapLayersState";
|
||||
import { selectedAreaState } from "../../store/atoms/selectedAreaState";
|
||||
import { zoomTriggerState } from "../../store/atoms/zoomTriggerState";
|
||||
import { poiLayerVisibleState } from "../../store/atoms/poiLayerVisibleState";
|
||||
|
||||
// Stelle sicher, dass alle notwendigen Atome korrekt gemockt sind
|
||||
jest.mock("../../store/atoms/gisStationState", () => ({
|
||||
gisStationState: {
|
||||
subscribe: jest.fn(),
|
||||
getSnapshot: jest.fn(() => []), // Mocked return value
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock("../../store/atoms/gisSystemState", () => ({
|
||||
gisSystemStaticState: {
|
||||
subscribe: jest.fn(),
|
||||
getSnapshot: jest.fn(() => []), // Mocked return value
|
||||
},
|
||||
}));
|
||||
|
||||
describe("DataSheet Component", () => {
|
||||
//--------------------------------------------------------------------------------
|
||||
it("renders the basic fields and initial station/system listings", async () => {
|
||||
render(
|
||||
<RecoilRoot>
|
||||
<DataSheet />
|
||||
</RecoilRoot>
|
||||
);
|
||||
|
||||
// Waiting for asynchronous tasks to complete
|
||||
await waitFor(() => {
|
||||
// Check if the specific elements are present after data processing
|
||||
expect(screen.getByRole("combobox")).toBeInTheDocument();
|
||||
expect(screen.getByLabelText("POIs")).toBeInTheDocument();
|
||||
expect(screen.getByRole("option", { name: "Station wählen" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Optionally print out the full DOM for debugging
|
||||
screen.debug();
|
||||
});
|
||||
//--------------------------------------------------------------------------------
|
||||
test("should open dropdown on click", async () => {
|
||||
render(
|
||||
<RecoilRoot>
|
||||
<DataSheet />
|
||||
</RecoilRoot>
|
||||
);
|
||||
const combobox = screen.getByRole("combobox");
|
||||
userEvent.click(combobox);
|
||||
// Überprüfe, ob die Dropdown-Optionen angezeigt werden
|
||||
expect(screen.getByRole("option", { name: "Station wählen" })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
test("should toggle checkbox", async () => {
|
||||
render(
|
||||
<RecoilRoot>
|
||||
<DataSheet />
|
||||
</RecoilRoot>
|
||||
);
|
||||
const checkbox = screen.getByLabelText("POIs");
|
||||
// Stelle sicher, dass die Checkbox nicht angekreuzt ist
|
||||
expect(checkbox).not.toBeChecked();
|
||||
// Klicke auf die Checkbox
|
||||
userEvent.click(checkbox);
|
||||
// Jetzt sollte sie angekreuzt sein
|
||||
expect(checkbox).toBeChecked();
|
||||
});
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
});
|
||||
89
__tests__/unit/components/MapComponent.test.js
Normal file
89
__tests__/unit/components/MapComponent.test.js
Normal file
@@ -0,0 +1,89 @@
|
||||
// __tests__/MapComponent.test.js
|
||||
|
||||
// Ein einfacher Testfall, der sicherstellt, dass die Addition korrekt ist
|
||||
test("simple addition", () => {
|
||||
const a = 1;
|
||||
const b = 2;
|
||||
const c = a + b;
|
||||
expect(c).toBe(3); // Überprüft, ob c gleich 3 ist
|
||||
});
|
||||
|
||||
//import L from "leaflet";
|
||||
//import { checkOverlappingMarkers } from "../utils/mapUtils"; // Passe den Pfad entsprechend an
|
||||
|
||||
/* describe("checkOverlappingMarkers", () => {
|
||||
let map;
|
||||
|
||||
beforeEach(() => {
|
||||
// Erstelle eine neue Leaflet-Karte für jeden Test
|
||||
map = L.map(document.createElement("div"));
|
||||
});
|
||||
|
||||
it("should group markers by coordinates and add plus icons for overlapping markers", () => {
|
||||
// Erstelle einige Beispielmarker
|
||||
const markers = [
|
||||
L.marker([51.505, -0.09]),
|
||||
L.marker([51.505, -0.09]),
|
||||
L.marker([51.51, -0.1]),
|
||||
];
|
||||
|
||||
const plusIcon = L.divIcon({ className: "plus-icon" });
|
||||
|
||||
// Rufe die Funktion auf
|
||||
checkOverlappingMarkers(map, markers, plusIcon);
|
||||
|
||||
// Überprüfe, dass die Marker zu Gruppen hinzugefügt wurden
|
||||
const overlappingGroups = map._layers;
|
||||
expect(Object.keys(overlappingGroups).length).toBeGreaterThan(0);
|
||||
|
||||
// Überprüfe, dass die Plus-Marker hinzugefügt wurden
|
||||
const plusMarkers = Object.values(overlappingGroups).filter(
|
||||
(layer) =>
|
||||
layer.options.icon &&
|
||||
layer.options.icon.options.className === "plus-icon"
|
||||
);
|
||||
expect(plusMarkers.length).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("should handle non-array markers argument gracefully", () => {
|
||||
const plusIcon = L.divIcon({ className: "plus-icon" });
|
||||
|
||||
// Rufe die Funktion mit einem ungültigen Argument auf
|
||||
checkOverlappingMarkers(map, null, plusIcon);
|
||||
|
||||
// Stelle sicher, dass keine Marker hinzugefügt wurden
|
||||
const layers = map._layers;
|
||||
expect(Object.keys(layers).length).toBe(0);
|
||||
});
|
||||
|
||||
it("should not add plus markers if there are no overlaps", () => {
|
||||
// Erstelle einige Beispielmarker
|
||||
const markers = [
|
||||
L.marker([51.505, -0.09]),
|
||||
L.marker([51.51, -0.1]),
|
||||
L.marker([51.52, -0.12]),
|
||||
];
|
||||
|
||||
const plusIcon = L.divIcon({ className: "plus-icon" });
|
||||
|
||||
// Rufe die Funktion auf
|
||||
checkOverlappingMarkers(map, markers, plusIcon);
|
||||
|
||||
// Überprüfe, dass keine Plus-Marker hinzugefügt wurden
|
||||
const plusMarkers = Object.values(map._layers).filter(
|
||||
(layer) =>
|
||||
layer.options.icon &&
|
||||
layer.options.icon.options.className === "plus-icon"
|
||||
);
|
||||
expect(plusMarkers.length).toBe(0);
|
||||
});
|
||||
}); */
|
||||
/*
|
||||
In diesem Test:
|
||||
|
||||
Wird eine neue Leaflet-Karte vor jedem Test erstellt.
|
||||
checkOverlappingMarkers wird aufgerufen, um zu überprüfen, ob die Funktion die Marker richtig gruppiert und Plus-Icons für überlappende Marker hinzufügt.
|
||||
Der Test überprüft auch, ob die Funktion ungültige Argumente (wie null für Marker) korrekt behandelt.
|
||||
Es wird sichergestellt, dass keine Plus-Marker hinzugefügt werden, wenn keine Überlappungen vorliegen.
|
||||
Stelle sicher, dass du die Pfade und Importe entsprechend deiner Projektstruktur anpasst.
|
||||
*/
|
||||
@@ -0,0 +1,40 @@
|
||||
// __tests__/components/gisPolylines/icons/CircleIcon.test.js
|
||||
jest.mock("leaflet", () => {
|
||||
const actualLeaflet = jest.requireActual("leaflet");
|
||||
return {
|
||||
...actualLeaflet,
|
||||
DivIcon: jest.fn().mockImplementation((options) => ({
|
||||
...options,
|
||||
options,
|
||||
_leaflet_id: Math.random(),
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
import L from "leaflet";
|
||||
import CircleIcon from "../../../components/gisPolylines/icons/CircleIcon";
|
||||
|
||||
describe("CircleIcon", () => {
|
||||
test("should be a Leaflet divIcon with correct properties", () => {
|
||||
// console.log("CircleIcon options:", CircleIcon.options);
|
||||
expect(CircleIcon).toEqual(
|
||||
expect.objectContaining({
|
||||
options: expect.objectContaining({
|
||||
className: "custom-circle-icon leaflet-marker-icon",
|
||||
html: '<div style="background-color:gray; width:10px; height:10px; border-radius:50%; border: solid black 1px;"></div>',
|
||||
iconSize: [25, 25],
|
||||
iconAnchor: [5, 5],
|
||||
}),
|
||||
})
|
||||
);
|
||||
expect(CircleIcon.options.className).toContain("custom-circle-icon");
|
||||
expect(CircleIcon.options.html).toContain("<div");
|
||||
expect(CircleIcon.options.html).toContain("background-color:gray");
|
||||
expect(CircleIcon.options.html).toContain("border-radius:50%");
|
||||
expect(CircleIcon.options.html).toContain("width:10px");
|
||||
expect(CircleIcon.options.html).toContain("height:10px");
|
||||
expect(CircleIcon.options.html).toContain("border: solid black 1px");
|
||||
expect(CircleIcon.options.iconSize).toEqual([25, 25]);
|
||||
expect(CircleIcon.options.iconAnchor).toEqual([5, 5]);
|
||||
});
|
||||
});
|
||||
24
__tests__/unit/components/gisPolylines/icons/EndIcon.test.js
Normal file
24
__tests__/unit/components/gisPolylines/icons/EndIcon.test.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// __tests__/components/gisPolylines/icons/EndIcon.test.js
|
||||
jest.mock("leaflet", () => {
|
||||
const actualLeaflet = jest.requireActual("leaflet");
|
||||
return {
|
||||
...actualLeaflet,
|
||||
DivIcon: jest.fn().mockImplementation((options) => ({
|
||||
...options,
|
||||
options,
|
||||
_leaflet_id: Math.random(),
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
import L from "leaflet";
|
||||
import EndIcon from "../../../../components/gisPolylines/icons/EndIcon";
|
||||
//console.log("console log EndIcon: ", EndIcon);
|
||||
describe("endIcon", () => {
|
||||
test("should be a custom-end-icon with correct HTML and styles", () => {
|
||||
expect(EndIcon.options.className).toBe("custom-end-icon");
|
||||
expect(EndIcon.options.html).toBe("<div style='background-color: gray; width: 14px; height: 14px; border: solid black 2px;'></div>");
|
||||
expect(EndIcon.options.iconSize).toEqual([14, 14]);
|
||||
expect(EndIcon.options.iconAnchor).toEqual([7, 7]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
// __tests__/components/gisPolylines/icons/StartIcon.test.js
|
||||
jest.mock("leaflet", () => {
|
||||
const actualLeaflet = jest.requireActual("leaflet");
|
||||
return {
|
||||
...actualLeaflet,
|
||||
DivIcon: jest.fn().mockImplementation((options) => ({
|
||||
...options,
|
||||
options,
|
||||
_leaflet_id: Math.random(),
|
||||
_createIcon: jest.fn(),
|
||||
_createImg: jest.fn(),
|
||||
_getIconUrl: jest.fn(),
|
||||
_initHooks: [],
|
||||
_initHooksCalled: true,
|
||||
_setIconStyles: jest.fn(),
|
||||
callInitHooks: jest.fn(),
|
||||
createIcon: jest.fn(),
|
||||
createShadow: jest.fn(),
|
||||
initialize: jest.fn(),
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
import L from "leaflet";
|
||||
import StartIcon from "../../../../../components/gisPolylines/icons/StartIcon";
|
||||
|
||||
describe("StartIcon", () => {
|
||||
test("should be a Leaflet divIcon with correct properties", () => {
|
||||
//console.log("StartIcon options:", StartIcon.options);
|
||||
expect(StartIcon).toEqual(
|
||||
expect.objectContaining({
|
||||
options: expect.objectContaining({
|
||||
className: "custom-start-icon",
|
||||
html: expect.stringContaining("<svg"),
|
||||
iconSize: [18, 18],
|
||||
iconAnchor: [9, 10],
|
||||
}),
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
42
__tests__/unit/hooks/useLineData.test.js
Normal file
42
__tests__/unit/hooks/useLineData.test.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import { renderHook, act, waitFor } from "@testing-library/react";
|
||||
import useLineData from "../../../hooks/useLineData";
|
||||
import React from "react";
|
||||
|
||||
const mockUrl = "http://mockurl.com";
|
||||
const mockData1 = {
|
||||
Statis: [{ IdLD: 1, Modul: "mod1", PrioColor: "red", ModulName: "Module 1", ModulTyp: "Type 1", Message: "Message 1", PrioName: "High", DpName: "DP 1", Value: "Value 1" }],
|
||||
};
|
||||
const mockData2 = [{ idLD: 1, idModul: "mod1" }];
|
||||
|
||||
global.fetch = jest.fn((url) => {
|
||||
if (url === mockUrl) {
|
||||
return Promise.resolve({
|
||||
json: () => Promise.resolve(mockData1),
|
||||
});
|
||||
} else {
|
||||
return Promise.resolve({
|
||||
json: () => Promise.resolve(mockData2),
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("useLineData", () => {
|
||||
test("should fetch line data and set line colors and tooltip contents", async () => {
|
||||
const setLineStatusData = jest.fn();
|
||||
|
||||
const { result } = renderHook(() => useLineData(mockUrl, setLineStatusData));
|
||||
|
||||
await waitFor(
|
||||
() => {
|
||||
expect(setLineStatusData).toHaveBeenCalledWith(expect.any(Array));
|
||||
expect(result.current).toEqual(
|
||||
expect.objectContaining({
|
||||
lineColors: expect.any(Object),
|
||||
tooltipContents: expect.any(Object),
|
||||
})
|
||||
);
|
||||
},
|
||||
{ timeout: 5000 } // Increase the timeout to 5000ms
|
||||
);
|
||||
});
|
||||
});
|
||||
86
__tests__/unit/pois/AddPoiModalWindow.test.js
Normal file
86
__tests__/unit/pois/AddPoiModalWindow.test.js
Normal file
@@ -0,0 +1,86 @@
|
||||
// __tests__/components/pois/AddPoiModalWindow.test.js
|
||||
|
||||
import React from "react";
|
||||
import { render, screen, fireEvent, waitFor, act } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import AddPoiModalWindow from "../../../components/pois/AddPoiModalWindow";
|
||||
import { RecoilRoot } from "recoil";
|
||||
|
||||
// Mock für die fetch-Funktion
|
||||
global.fetch = jest.fn((url) => {
|
||||
if (url === "/api/talas_v5_DB/poiTyp/readPoiTyp") {
|
||||
return Promise.resolve({
|
||||
json: () => Promise.resolve([{ idPoiTyp: "1", name: "Type1" }]),
|
||||
});
|
||||
} else if (url === "/api/talas5/location_device") {
|
||||
return Promise.resolve({
|
||||
json: () => Promise.resolve([{ idLD: "1", name: "Device1" }]),
|
||||
});
|
||||
} else if (url === "/api/talas_v5_DB/pois/addLocation") {
|
||||
return Promise.resolve({ ok: true });
|
||||
}
|
||||
});
|
||||
|
||||
describe("AddPoiModalWindow", () => {
|
||||
const mockOnClose = jest.fn();
|
||||
const mockMap = {
|
||||
closePopup: jest.fn(),
|
||||
};
|
||||
const mockLatLng = { lat: 52.52, lng: 13.405 };
|
||||
|
||||
// Mock window.location.reload
|
||||
beforeAll(() => {
|
||||
Object.defineProperty(window, "location", {
|
||||
value: {
|
||||
...window.location,
|
||||
reload: jest.fn(),
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fetch.mockClear();
|
||||
window.location.reload.mockClear(); // Clear the mock before each test
|
||||
});
|
||||
|
||||
test("renders correctly and allows form submission", async () => {
|
||||
await act(async () => {
|
||||
render(
|
||||
<RecoilRoot>
|
||||
<AddPoiModalWindow onClose={mockOnClose} map={mockMap} latlng={mockLatLng} />
|
||||
</RecoilRoot>
|
||||
);
|
||||
});
|
||||
|
||||
// Überprüfen, ob die Formularelemente gerendert werden
|
||||
expect(screen.getByLabelText(/Name/i)).toBeInTheDocument();
|
||||
expect(screen.getByLabelText(/Gerät/i)).toBeInTheDocument();
|
||||
expect(screen.getByLabelText(/Typ/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/Lat/i)).toHaveTextContent(`Lat : ${mockLatLng.lat.toFixed(5)}`);
|
||||
expect(screen.getByText(/Lng/i)).toHaveTextContent(`Lng : ${mockLatLng.lng.toFixed(5)}`);
|
||||
|
||||
// Simulieren der Eingabe in das Namensfeld
|
||||
fireEvent.change(screen.getByLabelText(/Name/i), { target: { value: "New POI" } });
|
||||
expect(screen.getByLabelText(/Name/i)).toHaveValue("New POI");
|
||||
|
||||
// Simulieren der Auswahl eines Geräts
|
||||
fireEvent.change(screen.getByLabelText(/Gerät/i), { target: { value: "Device1" } });
|
||||
expect(screen.getByLabelText(/Gerät/i)).toHaveValue("Device1");
|
||||
|
||||
// Simulieren der Auswahl eines Typs
|
||||
fireEvent.change(screen.getByLabelText(/Typ/i), { target: { value: "1" } });
|
||||
expect(screen.getByLabelText(/Typ/i)).toHaveValue("1");
|
||||
|
||||
// Simulieren des Formulareingabeverfahrens
|
||||
fireEvent.submit(screen.getByRole("button", { name: /POI hinzufügen/i }));
|
||||
|
||||
// Warten auf die Formulareinreichung und Überprüfen der Ergebnisse
|
||||
await waitFor(() => {
|
||||
expect(mockOnClose).toHaveBeenCalled();
|
||||
expect(mockMap.closePopup).toHaveBeenCalled();
|
||||
expect(fetch).toHaveBeenCalledWith("/api/talas_v5_DB/pois/addLocation", expect.any(Object));
|
||||
expect(window.location.reload).toHaveBeenCalled(); // Verify that reload was called
|
||||
});
|
||||
});
|
||||
});
|
||||
77
__tests__/unit/pois/AddPoiModalWindowPopup.test.js
Normal file
77
__tests__/unit/pois/AddPoiModalWindowPopup.test.js
Normal file
@@ -0,0 +1,77 @@
|
||||
// __tests__/components/pois/AddPoiModalWindowPopup.test.js
|
||||
|
||||
import React from "react";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import AddPoiModalWindowPopup from "../../../components/pois/AddPoiModalWindowPopup";
|
||||
|
||||
// Mock the AddPoiModalWindow component
|
||||
jest.mock("../../../components/pois/AddPoiModalWindow", () => ({ onClose, onSubmit, latlng }) => (
|
||||
<div data-testid="add-poi-modal-window">
|
||||
<button onClick={() => console.log("Mocked Close Modal Click")}>Close Modal</button>
|
||||
<button onClick={onSubmit}>Submit</button>
|
||||
<div>
|
||||
Coordinates: {latlng.lat}, {latlng.lng}
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
|
||||
describe("AddPoiModalWindowPopup", () => {
|
||||
const closePopupMock = jest.fn();
|
||||
const handleAddStationMock = jest.fn();
|
||||
const popupCoordinatesMock = { lat: 52.52, lng: 13.405 };
|
||||
|
||||
// Suppress console.log for the duration of these tests
|
||||
beforeAll(() => {
|
||||
jest.spyOn(console, "log").mockImplementation(() => {});
|
||||
});
|
||||
|
||||
// Restore console.log after all tests
|
||||
afterAll(() => {
|
||||
console.log.mockRestore();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
closePopupMock.mockClear();
|
||||
handleAddStationMock.mockClear();
|
||||
});
|
||||
|
||||
test("renders the popup when showPopup is true", () => {
|
||||
render(<AddPoiModalWindowPopup showPopup={true} closePopup={closePopupMock} handleAddStation={handleAddStationMock} popupCoordinates={popupCoordinatesMock} />);
|
||||
|
||||
expect(screen.getByTestId("add-poi-modal-window")).toBeInTheDocument();
|
||||
expect(screen.getByText("Coordinates: 52.52, 13.405")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("does not render the popup when showPopup is false", () => {
|
||||
render(<AddPoiModalWindowPopup showPopup={false} closePopup={closePopupMock} handleAddStation={handleAddStationMock} popupCoordinates={popupCoordinatesMock} />);
|
||||
|
||||
expect(screen.queryByTestId("add-poi-modal-window")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("closes the popup when the top right close button is clicked", () => {
|
||||
render(<AddPoiModalWindowPopup showPopup={true} closePopup={closePopupMock} handleAddStation={handleAddStationMock} popupCoordinates={popupCoordinatesMock} />);
|
||||
|
||||
// Use the aria-label to uniquely identify the close button in the outer component
|
||||
const closeButton = screen.getByRole("button", { name: "Close" });
|
||||
|
||||
// Click the button with aria-label "Close"
|
||||
fireEvent.click(closeButton);
|
||||
expect(closePopupMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("submits the form when the submit button is clicked", () => {
|
||||
render(<AddPoiModalWindowPopup showPopup={true} closePopup={closePopupMock} handleAddStation={handleAddStationMock} popupCoordinates={popupCoordinatesMock} />);
|
||||
|
||||
fireEvent.click(screen.getByText("Submit"));
|
||||
expect(handleAddStationMock).toHaveBeenCalledTimes(1); // This should now pass
|
||||
});
|
||||
|
||||
test('clicking the "Close Modal" button inside AddPoiModalWindow should not close the popup', () => {
|
||||
render(<AddPoiModalWindowPopup showPopup={true} closePopup={closePopupMock} handleAddStation={handleAddStationMock} popupCoordinates={popupCoordinatesMock} />);
|
||||
|
||||
// Click the "Close Modal" button inside the mock
|
||||
fireEvent.click(screen.getByText("Close Modal"));
|
||||
expect(closePopupMock).toHaveBeenCalledTimes(0); // Should not call the popup close
|
||||
});
|
||||
});
|
||||
75
__tests__/unit/pois/AddPoiModalWindowWrapper.test.js
Normal file
75
__tests__/unit/pois/AddPoiModalWindowWrapper.test.js
Normal file
@@ -0,0 +1,75 @@
|
||||
// __tests__/components/pois/AddPoiModalWindowWrapper.test.js
|
||||
|
||||
import React from "react";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import AddPoiModalWindowWrapper from "../../../components/pois/AddPoiModalWindowWrapper";
|
||||
|
||||
// Mock the AddPoiModalWindow component to avoid testing its internal implementation here
|
||||
jest.mock("../../../components/pois/AddPoiModalWindow", () => ({ onClose, onSubmit, latlng }) => (
|
||||
<div data-testid="add-poi-modal-window">
|
||||
<button onClick={onClose}>Mocked Close</button>
|
||||
<button onClick={onSubmit}>Mocked Submit</button>
|
||||
<div>
|
||||
Mocked Coordinates: {latlng.lat}, {latlng.lng}
|
||||
</div>
|
||||
</div>
|
||||
));
|
||||
|
||||
describe("AddPoiModalWindowWrapper", () => {
|
||||
const onCloseMock = jest.fn();
|
||||
const handleAddStationMock = jest.fn();
|
||||
const latlngMock = { lat: 52.52, lng: 13.405 };
|
||||
|
||||
beforeEach(() => {
|
||||
onCloseMock.mockClear();
|
||||
handleAddStationMock.mockClear();
|
||||
});
|
||||
|
||||
test("renders the modal when 'show' is true", () => {
|
||||
render(<AddPoiModalWindowWrapper show={true} onClose={onCloseMock} handleAddStation={handleAddStationMock} latlng={latlngMock} />);
|
||||
|
||||
// Check if the modal and its contents are in the document
|
||||
expect(screen.getByTestId("add-poi-modal-window")).toBeInTheDocument();
|
||||
expect(screen.getByText("Mocked Coordinates: 52.52, 13.405")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("does not render the modal when 'show' is false", () => {
|
||||
render(<AddPoiModalWindowWrapper show={false} onClose={onCloseMock} handleAddStation={handleAddStationMock} latlng={latlngMock} />);
|
||||
|
||||
// Check if the modal is not in the document
|
||||
expect(screen.queryByTestId("add-poi-modal-window")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("calls onClose when the close button is clicked", () => {
|
||||
render(<AddPoiModalWindowWrapper show={true} onClose={onCloseMock} handleAddStation={handleAddStationMock} latlng={latlngMock} />);
|
||||
|
||||
// Click the close button
|
||||
fireEvent.click(screen.getByRole("button", { name: "Close" }));
|
||||
expect(onCloseMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("calls onClose when the background is clicked", () => {
|
||||
render(<AddPoiModalWindowWrapper show={true} onClose={onCloseMock} handleAddStation={handleAddStationMock} latlng={latlngMock} />);
|
||||
|
||||
// Click the background overlay
|
||||
fireEvent.click(screen.getByTestId("modal-overlay"));
|
||||
expect(onCloseMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test("does not call onClose when the modal content is clicked", () => {
|
||||
render(<AddPoiModalWindowWrapper show={true} onClose={onCloseMock} handleAddStation={handleAddStationMock} latlng={latlngMock} />);
|
||||
|
||||
// Click the modal content
|
||||
fireEvent.click(screen.getByRole("dialog"));
|
||||
expect(onCloseMock).toHaveBeenCalledTimes(0);
|
||||
});
|
||||
|
||||
test("calls handleAddStation when the submit button is clicked", () => {
|
||||
render(<AddPoiModalWindowWrapper show={true} onClose={onCloseMock} handleAddStation={handleAddStationMock} latlng={latlngMock} />);
|
||||
|
||||
// Click the submit button
|
||||
fireEvent.click(screen.getByText("Mocked Submit"));
|
||||
expect(handleAddStationMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
117
__tests__/unit/pois/PoiUpdateModal.test.js
Normal file
117
__tests__/unit/pois/PoiUpdateModal.test.js
Normal file
@@ -0,0 +1,117 @@
|
||||
// __tests__/components/pois/PoiUpdateModal.test.js
|
||||
|
||||
import React from "react";
|
||||
import { render, screen, fireEvent, waitFor, act } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import PoiUpdateModal from "../../../components/pois/PoiUpdateModal";
|
||||
import { useRecoilValue } from "recoil";
|
||||
import { selectedPoiState, currentPoiState } from "../../../store/atoms/poiState";
|
||||
|
||||
// Mock the recoil states
|
||||
jest.mock("recoil");
|
||||
|
||||
describe("PoiUpdateModal", () => {
|
||||
const mockOnClose = jest.fn();
|
||||
const mockOnSubmit = jest.fn();
|
||||
const poiDataMock = {
|
||||
idPoi: "123",
|
||||
name: "Test POI",
|
||||
description: "Test Description",
|
||||
idPoiTyp: "1",
|
||||
idLD: "2",
|
||||
};
|
||||
|
||||
const selectedPoiMock = {
|
||||
idPoi: "123",
|
||||
typ: "Type1",
|
||||
};
|
||||
|
||||
const currentPoiMock = {
|
||||
idLD: "2",
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
useRecoilValue.mockImplementation((state) => {
|
||||
if (state === selectedPoiState) return selectedPoiMock;
|
||||
if (state === currentPoiState) return currentPoiMock;
|
||||
});
|
||||
|
||||
mockOnClose.mockClear();
|
||||
mockOnSubmit.mockClear();
|
||||
|
||||
global.fetch = jest.fn((url) => {
|
||||
if (url === "/api/talas_v5_DB/poiTyp/readPoiTyp") {
|
||||
return Promise.resolve({
|
||||
json: () => Promise.resolve([{ idPoiTyp: "1", name: "Type1" }]),
|
||||
});
|
||||
} else if (url === "/api/talas_v5_DB/locationDevice/locationDevices") {
|
||||
return Promise.resolve({
|
||||
json: () => Promise.resolve([{ id: "2", name: "Device1" }]),
|
||||
});
|
||||
} else if (url.startsWith("/api/talas_v5_DB/locationDevice/getDeviceId")) {
|
||||
return Promise.resolve({
|
||||
json: () => Promise.resolve({ idLD: "2", name: "Device1" }),
|
||||
});
|
||||
} else if (url.startsWith("/api/talas_v5_DB/pois/deletePoi")) {
|
||||
return Promise.resolve({ ok: true });
|
||||
} else if (url === "/api/talas_v5_DB/pois/updatePoi") {
|
||||
return Promise.resolve({ ok: true });
|
||||
}
|
||||
});
|
||||
|
||||
global.alert = jest.fn(); // Mock alert
|
||||
delete window.location;
|
||||
window.location = { reload: jest.fn() }; // Mock location.reload
|
||||
});
|
||||
|
||||
test("renders modal with correct data", async () => {
|
||||
await act(async () => {
|
||||
render(<PoiUpdateModal onClose={mockOnClose} poiData={poiDataMock} onSubmit={mockOnSubmit} />);
|
||||
});
|
||||
|
||||
expect(screen.getByDisplayValue("Test Description")).toBeInTheDocument();
|
||||
expect(screen.getByDisplayValue("Device1")).toBeInTheDocument();
|
||||
expect(screen.getByDisplayValue("Type1")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("handles POI update submission", async () => {
|
||||
await act(async () => {
|
||||
render(<PoiUpdateModal onClose={mockOnClose} poiData={poiDataMock} onSubmit={mockOnSubmit} />);
|
||||
});
|
||||
|
||||
fireEvent.change(screen.getByLabelText("Beschreibung:"), { target: { value: "Updated Description" } });
|
||||
fireEvent.click(screen.getByText("POI aktualisieren"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(global.fetch).toHaveBeenCalledWith("/api/talas_v5_DB/pois/updatePoi", expect.any(Object));
|
||||
expect(mockOnClose).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
test("handles POI deletion", async () => {
|
||||
window.confirm = jest.fn().mockImplementation(() => true); // Mock confirm dialog to always accept
|
||||
|
||||
await act(async () => {
|
||||
render(<PoiUpdateModal onClose={mockOnClose} poiData={poiDataMock} onSubmit={mockOnSubmit} />);
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByText("POI löschen"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(global.fetch).toHaveBeenCalledWith(expect.stringContaining("/api/talas_v5_DB/pois/deletePoi"), { method: "DELETE" });
|
||||
expect(mockOnClose).toHaveBeenCalledTimes(1);
|
||||
expect(window.location.reload).toHaveBeenCalledTimes(1);
|
||||
expect(global.alert).toHaveBeenCalledWith("POI wurde erfolgreich gelöscht.");
|
||||
});
|
||||
});
|
||||
|
||||
test("closes the modal when the close button is clicked", async () => {
|
||||
await act(async () => {
|
||||
render(<PoiUpdateModal onClose={mockOnClose} poiData={poiDataMock} onSubmit={mockOnSubmit} />);
|
||||
});
|
||||
|
||||
fireEvent.click(screen.getByLabelText("Close"));
|
||||
|
||||
expect(mockOnClose).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
57
__tests__/unit/pois/PoiUpdateModalWindow.test.js
Normal file
57
__tests__/unit/pois/PoiUpdateModalWindow.test.js
Normal file
@@ -0,0 +1,57 @@
|
||||
// __tests__/components/pois/PoiUpdateModalWindow.test.js
|
||||
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import PoiUpdateModalWindow from "../../../components/pois/PoiUpdateModalWindow";
|
||||
import PoiUpdateModal from "../../../components/pois/PoiUpdateModal";
|
||||
|
||||
// Mock the PoiUpdateModal component to avoid testing its internal implementation here
|
||||
jest.mock("../../../components/pois/PoiUpdateModal", () => ({ onClose, poiData, onSubmit, latlng }) => (
|
||||
<div data-testid="poi-update-modal">
|
||||
<button onClick={onClose}>Close</button>
|
||||
<div>POI Data: {poiData ? poiData.name : "No Data"}</div>
|
||||
<div>LatLng: {latlng ? `${latlng.lat}, ${latlng.lng}` : "No Coordinates"}</div>
|
||||
</div>
|
||||
));
|
||||
|
||||
describe("PoiUpdateModalWindow", () => {
|
||||
const closePoiUpdateModalMock = jest.fn();
|
||||
const currentPoiDataMock = {
|
||||
idPoi: "123",
|
||||
name: "Test POI",
|
||||
description: "Test Description",
|
||||
idPoiTyp: "1",
|
||||
idLD: "2",
|
||||
};
|
||||
|
||||
const popupCoordinatesMock = { lat: 52.52, lng: 13.405 };
|
||||
|
||||
beforeEach(() => {
|
||||
closePoiUpdateModalMock.mockClear();
|
||||
});
|
||||
|
||||
test("renders PoiUpdateModal when showPoiUpdateModal is true", () => {
|
||||
render(<PoiUpdateModalWindow showPoiUpdateModal={true} closePoiUpdateModal={closePoiUpdateModalMock} currentPoiData={currentPoiDataMock} popupCoordinates={popupCoordinatesMock} />);
|
||||
|
||||
// Check if the modal and its contents are in the document
|
||||
expect(screen.getByTestId("poi-update-modal")).toBeInTheDocument();
|
||||
expect(screen.getByText("POI Data: Test POI")).toBeInTheDocument();
|
||||
expect(screen.getByText("LatLng: 52.52, 13.405")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("does not render PoiUpdateModal when showPoiUpdateModal is false", () => {
|
||||
render(<PoiUpdateModalWindow showPoiUpdateModal={false} closePoiUpdateModal={closePoiUpdateModalMock} currentPoiData={currentPoiDataMock} popupCoordinates={popupCoordinatesMock} />);
|
||||
|
||||
// Check if the modal is not in the document
|
||||
expect(screen.queryByTestId("poi-update-modal")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("calls closePoiUpdateModal when the close button is clicked", () => {
|
||||
render(<PoiUpdateModalWindow showPoiUpdateModal={true} closePoiUpdateModal={closePoiUpdateModalMock} currentPoiData={currentPoiDataMock} popupCoordinates={popupCoordinatesMock} />);
|
||||
|
||||
// Click the close button
|
||||
screen.getByText("Close").click();
|
||||
expect(closePoiUpdateModalMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
79
__tests__/unit/pois/PoiUpdateModalWrapper.test.js
Normal file
79
__tests__/unit/pois/PoiUpdateModalWrapper.test.js
Normal file
@@ -0,0 +1,79 @@
|
||||
// __tests__/components/pois/PoiUpdateModalWrapper.test.js
|
||||
|
||||
import React from "react";
|
||||
import { render, screen, fireEvent, act } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom";
|
||||
import PoiUpdateModalWrapper from "../../../components/pois/PoiUpdateModalWrapper";
|
||||
import { useRecoilValue, useSetRecoilState } from "recoil";
|
||||
import { currentPoiState, selectedPoiState } from "../../../store/atoms/poiState";
|
||||
import { poiReadFromDbTriggerAtom } from "../../../store/atoms/poiReadFromDbTriggerAtom";
|
||||
|
||||
// Mock Recoil hooks
|
||||
jest.mock("recoil");
|
||||
|
||||
describe("PoiUpdateModalWrapper", () => {
|
||||
const mockOnClose = jest.fn();
|
||||
const currentPoiMock = {
|
||||
idPoi: "123",
|
||||
name: "Test POI",
|
||||
description: "Test Description",
|
||||
idPoiTyp: "1",
|
||||
idLD: "2",
|
||||
};
|
||||
const latlngMock = { lat: 52.52, lng: 13.405 };
|
||||
|
||||
beforeEach(() => {
|
||||
// Mock the recoil values
|
||||
useRecoilValue.mockImplementation((atom) => {
|
||||
if (atom === currentPoiState) return currentPoiMock;
|
||||
if (atom === poiReadFromDbTriggerAtom) return 0;
|
||||
});
|
||||
useSetRecoilState.mockImplementation(() => jest.fn());
|
||||
|
||||
mockOnClose.mockClear();
|
||||
|
||||
// Mock global fetch
|
||||
global.fetch = jest.fn((url) =>
|
||||
Promise.resolve({
|
||||
json: () => {
|
||||
if (url.includes("getDeviceIdById")) {
|
||||
return Promise.resolve({ idLD: "2", name: "Device1" });
|
||||
}
|
||||
if (url.includes("readPoiTyp")) {
|
||||
return Promise.resolve([{ idPoiTyp: "1", name: "Type1" }]);
|
||||
}
|
||||
if (url.includes("locationDevices")) {
|
||||
return Promise.resolve([{ id: "2", name: "Device1" }]);
|
||||
}
|
||||
return Promise.resolve({});
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("renders PoiUpdateModal when 'show' is true", async () => {
|
||||
await act(async () => {
|
||||
render(<PoiUpdateModalWrapper show={true} onClose={mockOnClose} latlng={latlngMock} />);
|
||||
});
|
||||
|
||||
// Check if the modal and its contents are in the document
|
||||
expect(screen.getByDisplayValue("Test Description")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("does not render PoiUpdateModal when 'show' is false", () => {
|
||||
render(<PoiUpdateModalWrapper show={false} onClose={mockOnClose} latlng={latlngMock} />);
|
||||
|
||||
// Check if the modal is not in the document
|
||||
expect(screen.queryByDisplayValue("Test POI")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("calls onClose when the modal close button is clicked", async () => {
|
||||
await act(async () => {
|
||||
render(<PoiUpdateModalWrapper show={true} onClose={mockOnClose} latlng={latlngMock} />);
|
||||
});
|
||||
|
||||
// Simulate closing the modal
|
||||
fireEvent.click(screen.getByLabelText("Close"));
|
||||
expect(mockOnClose).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
111
__tests__/unit/pois/PoiUtils.test.js
Normal file
111
__tests__/unit/pois/PoiUtils.test.js
Normal file
@@ -0,0 +1,111 @@
|
||||
// __tests__/components/pois/PoiUtils.test.js
|
||||
|
||||
import { createPoiMarkers, addMarkersToMap, updateLocationInDatabase } from "../../../components/pois/PoiUtils";
|
||||
|
||||
// Mock Leaflet
|
||||
jest.mock("leaflet", () => {
|
||||
const Leaflet = {
|
||||
marker: jest.fn((latlng, options) => ({
|
||||
addTo: jest.fn(),
|
||||
on: jest.fn(),
|
||||
options: options,
|
||||
getLatLng: jest.fn(() => ({
|
||||
lat: latlng[0],
|
||||
lng: latlng[1],
|
||||
})),
|
||||
})),
|
||||
icon: jest.fn((options) => options),
|
||||
};
|
||||
return Leaflet;
|
||||
});
|
||||
|
||||
describe("PoiUtils", () => {
|
||||
describe("createPoiMarkers", () => {
|
||||
it("should create markers with correct coordinates and icon", () => {
|
||||
const poiData = [
|
||||
{ idPoi: "1", latitude: 52.52, longitude: 13.405 },
|
||||
{ idPoi: "2", latitude: 48.8566, longitude: 2.3522 },
|
||||
];
|
||||
const iconPath = "path/to/icon.png";
|
||||
const markers = createPoiMarkers(poiData, iconPath);
|
||||
|
||||
expect(markers).toHaveLength(2);
|
||||
|
||||
markers.forEach((marker, index) => {
|
||||
expect(marker.options.icon.iconUrl).toBe(iconPath);
|
||||
expect(marker.options.icon.iconSize).toEqual([25, 41]);
|
||||
expect(marker.options.id).toBe(poiData[index].idPoi);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("addMarkersToMap", () => {
|
||||
it("should add markers to map and bind events", () => {
|
||||
const mockMap = {};
|
||||
const mockLayerGroup = { addLayer: jest.fn() };
|
||||
const mockMarker = {
|
||||
addTo: jest.fn(),
|
||||
on: jest.fn(),
|
||||
};
|
||||
|
||||
const markers = [mockMarker, mockMarker];
|
||||
|
||||
addMarkersToMap(markers, mockMap, mockLayerGroup);
|
||||
|
||||
markers.forEach((marker) => {
|
||||
expect(marker.addTo).toHaveBeenCalledWith(mockLayerGroup);
|
||||
expect(marker.on).toHaveBeenCalledWith("mouseover", expect.any(Function));
|
||||
expect(marker.on).toHaveBeenCalledWith("mouseout", expect.any(Function));
|
||||
expect(marker.on).toHaveBeenCalledWith("dragend", expect.any(Function));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("updateLocationInDatabase", () => {
|
||||
beforeEach(() => {
|
||||
global.fetch = jest.fn(() =>
|
||||
Promise.resolve({
|
||||
ok: true,
|
||||
json: () => Promise.resolve({}),
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it("should call fetch with correct parameters", async () => {
|
||||
const id = "1";
|
||||
const newLatitude = 52.52;
|
||||
const newLongitude = 13.405;
|
||||
|
||||
await updateLocationInDatabase(id, newLatitude, newLongitude);
|
||||
|
||||
expect(fetch).toHaveBeenCalledWith("/api/talas_v5_DB/pois/updateLocation", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
id,
|
||||
latitude: newLatitude,
|
||||
longitude: newLongitude,
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it("should log error when fetch response is not ok", async () => {
|
||||
console.error = jest.fn();
|
||||
|
||||
global.fetch = jest.fn(() =>
|
||||
Promise.resolve({
|
||||
ok: false,
|
||||
json: () => Promise.resolve({}),
|
||||
})
|
||||
);
|
||||
|
||||
await updateLocationInDatabase("1", 52.52, 13.405);
|
||||
|
||||
expect(console.error).toHaveBeenCalledWith("Fehler beim Aktualisieren der Position");
|
||||
});
|
||||
});
|
||||
});
|
||||
6
__tests__/unit/utils/mapUtils.test.js
Normal file
6
__tests__/unit/utils/mapUtils.test.js
Normal file
@@ -0,0 +1,6 @@
|
||||
// __tests__/utils/mapUtils.test.js
|
||||
describe("Dummy test suite", () => {
|
||||
test("dummy test", () => {
|
||||
expect(true).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -5,58 +5,75 @@ import { gisSystemStaticState } from "../store/atoms/gisSystemState";
|
||||
import { mapLayersState } from "../store/atoms/mapLayersState";
|
||||
import { selectedAreaState } from "../store/atoms/selectedAreaState";
|
||||
import { zoomTriggerState } from "../store/atoms/zoomTriggerState";
|
||||
import { poiLayerVisibleState } from "../store/atoms/poiLayerVisible";
|
||||
import { poiLayerVisibleState } from "../store/atoms/poiLayerVisibleState";
|
||||
import EditModeToggle from "./EditModeToggle";
|
||||
import { polylineLayerVisibleState } from "../store/atoms/polylineLayerVisibleState"; // Import für Polyline-Visibility
|
||||
|
||||
function DataSheet() {
|
||||
const [poiVisible, setPoiVisible] = useRecoilState(poiLayerVisibleState);
|
||||
const setSelectedArea = useSetRecoilState(selectedAreaState);
|
||||
const [mapLayersVisibility, setMapLayersVisibility] =
|
||||
useRecoilState(mapLayersState);
|
||||
const [mapLayersVisibility, setMapLayersVisibility] = useRecoilState(mapLayersState);
|
||||
const [stationListing, setStationListing] = useState([]);
|
||||
const [systemListing, setSystemListing] = useState([]);
|
||||
const GisStationsStaticDistrict = useRecoilValue(
|
||||
gisStationsStaticDistrictState
|
||||
);
|
||||
const GisStationsStaticDistrict = useRecoilValue(gisStationsStaticDistrictState);
|
||||
const GisSystemStatic = useRecoilValue(gisSystemStaticState);
|
||||
const setZoomTrigger = useSetRecoilState(zoomTriggerState);
|
||||
const [polylineVisible, setPolylineVisible] = useRecoilState(polylineLayerVisibleState); // Zustand für Polylines
|
||||
useEffect(() => {
|
||||
const storedPoiVisible = localStorage.getItem("poiVisible");
|
||||
if (storedPoiVisible !== null) {
|
||||
setPoiVisible(storedPoiVisible === "true");
|
||||
}
|
||||
const storedPolylineVisible = localStorage.getItem("polylineVisible");
|
||||
if (storedPolylineVisible !== null) {
|
||||
setPolylineVisible(storedPolylineVisible === "true");
|
||||
}
|
||||
|
||||
const storedMapLayersVisibility = localStorage.getItem("mapLayersVisibility");
|
||||
if (storedMapLayersVisibility) {
|
||||
setMapLayersVisibility(JSON.parse(storedMapLayersVisibility));
|
||||
}
|
||||
}, [setPoiVisible, setMapLayersVisibility]);
|
||||
|
||||
const handleAreaChange = (event) => {
|
||||
const selectedIndex = event.target.options.selectedIndex;
|
||||
const areaName = event.target.options[selectedIndex].text;
|
||||
setSelectedArea(areaName);
|
||||
console.log("Area selected oder areaName in DataSheet.js:", areaName);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const allowedSystems = new Set(
|
||||
GisSystemStatic.filter((system) => system.Allow === 1).map(
|
||||
(system) => system.IdSystem
|
||||
)
|
||||
);
|
||||
const allowedSystems = new Set(GisSystemStatic.filter((system) => system.Allow === 1).map((system) => system.IdSystem));
|
||||
|
||||
const seenNames = new Set();
|
||||
const filteredAreas = GisStationsStaticDistrict.filter((item) => {
|
||||
const isUnique =
|
||||
!seenNames.has(item.Area_Name) && allowedSystems.has(item.System);
|
||||
const isUnique = !seenNames.has(item.Area_Name) && allowedSystems.has(item.System);
|
||||
if (isUnique) {
|
||||
seenNames.add(item.Area_Name);
|
||||
}
|
||||
return isUnique;
|
||||
});
|
||||
console.log("filterdArea GisStationsStaticDistrict:", filteredAreas);
|
||||
console.log("GisSystemStatic:", GisSystemStatic);
|
||||
console.log("allowedSystems:", allowedSystems);
|
||||
|
||||
setStationListing(
|
||||
filteredAreas.map((area, index) => ({
|
||||
id: index + 1,
|
||||
name: area.Area_Name,
|
||||
}))
|
||||
);
|
||||
|
||||
const seenSystemNames = new Set();
|
||||
const filteredSystems = GisSystemStatic.filter((item) => {
|
||||
const formattedName = item.Name.replace(/[\s\-]+/g, "");
|
||||
console.log(formattedName);
|
||||
const isUnique = !seenSystemNames.has(formattedName) && item.Allow === 1;
|
||||
if (isUnique) {
|
||||
seenSystemNames.add(formattedName);
|
||||
}
|
||||
return isUnique;
|
||||
});
|
||||
|
||||
setSystemListing(
|
||||
filteredSystems.map((system, index) => ({
|
||||
id: index + 1,
|
||||
@@ -67,35 +84,38 @@ function DataSheet() {
|
||||
|
||||
const handleCheckboxChange = (name, event) => {
|
||||
const { checked } = event.target;
|
||||
console.log(`Checkbox ${name} checked state:`, checked);
|
||||
|
||||
setMapLayersVisibility((prev) => {
|
||||
const newState = {
|
||||
...prev,
|
||||
[name]: checked,
|
||||
};
|
||||
console.log(`New mapLayersVisibility state:`, newState);
|
||||
localStorage.setItem("mapLayersVisibility", JSON.stringify(newState)); // Store in localStorage
|
||||
return newState;
|
||||
});
|
||||
};
|
||||
|
||||
const handlePoiCheckboxChange = (event) => {
|
||||
const { checked } = event.target;
|
||||
setPoiVisible(checked);
|
||||
localStorage.setItem("poiVisible", checked); // Store POI visibility in localStorage
|
||||
};
|
||||
|
||||
const handleIconClick = () => {
|
||||
setSelectedArea("Station wählen");
|
||||
setZoomTrigger((current) => current + 1);
|
||||
};
|
||||
const handlePolylineCheckboxChange = (event) => {
|
||||
const { checked } = event.target;
|
||||
setPolylineVisible(checked);
|
||||
localStorage.setItem("polylineVisible", checked); // Store Polyline visibility in localStorage
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
id="mainDataSheet"
|
||||
className="absolute top-3 right-3 w-1/6 min-w-[300px] z-10 bg-white p-2 rounded-lg shadow-lg"
|
||||
>
|
||||
<div id="mainDataSheet" className="absolute top-3 right-3 w-1/6 min-w-[300px] max-w-[400px] z-10 bg-white p-2 rounded-lg shadow-lg">
|
||||
<div className="flex flex-col gap-4 p-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<select
|
||||
onChange={handleAreaChange}
|
||||
id="stationListing"
|
||||
className="border-solid-1 p-2 rounded ml-1 font-semibold"
|
||||
>
|
||||
<div className="flex items-center justify-between space-x-2">
|
||||
<select onChange={handleAreaChange} id="stationListing" className="border-solid-1 p-2 rounded ml-1 font-semibold" style={{ minWidth: "150px", maxWidth: "200px" }}>
|
||||
<option value="Station wählen">Station wählen</option>
|
||||
{stationListing.map((station) => (
|
||||
<option key={station.id} value={station.id}>
|
||||
@@ -103,37 +123,38 @@ function DataSheet() {
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<img
|
||||
src="/img/expand-icon.svg"
|
||||
alt="Expand"
|
||||
className="h-6 w-6 ml-2 cursor-pointer"
|
||||
onClick={handleIconClick}
|
||||
/>
|
||||
<div className="flex items-center space-x-2">
|
||||
<EditModeToggle />
|
||||
<img src="/img/expand-icon.svg" alt="Expand" className="h-6 w-6 cursor-pointer" onClick={handleIconClick} />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
{/* Checkboxen in einem gemeinsamen Container */}
|
||||
<div className="flex flex-col gap-2">
|
||||
{systemListing.map((system) => (
|
||||
<React.Fragment key={system.id}>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={mapLayersVisibility[system.name] || false}
|
||||
onChange={(e) => handleCheckboxChange(system.name, e)}
|
||||
/>
|
||||
<label className="text-sm ml-2">{system.name}</label>
|
||||
<br />
|
||||
<div className="flex items-center">
|
||||
<input type="checkbox" checked={mapLayersVisibility[system.name] || false} onChange={(e) => handleCheckboxChange(system.name, e)} id={`system-${system.id}`} />
|
||||
<label htmlFor={`system-${system.id}`} className="text-sm ml-2">
|
||||
{system.name}
|
||||
</label>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
))}
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={poiVisible}
|
||||
onChange={(e) => {
|
||||
const checked = e.target.checked;
|
||||
setPoiVisible(checked);
|
||||
console.log(
|
||||
`POIs sind jetzt ${checked ? "sichtbar" : "nicht sichtbar"}.`
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<label className="text-sm ml-2">POIs</label>
|
||||
|
||||
<div className="flex items-center">
|
||||
<input type="checkbox" checked={poiVisible} onChange={handlePoiCheckboxChange} id="poi-checkbox" />
|
||||
<label htmlFor="poi-checkbox" className="text-sm ml-2">
|
||||
POIs
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center">
|
||||
<input type="checkbox" checked={polylineVisible} onChange={handlePolylineCheckboxChange} id="polyline-checkbox" />
|
||||
<label htmlFor="polyline-checkbox" className="text-sm ml-2">
|
||||
Kabelstrecken
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
38
components/EditModeToggle.js
Normal file
38
components/EditModeToggle.js
Normal file
@@ -0,0 +1,38 @@
|
||||
// /components/EditModeToggle.js
|
||||
import React, { useState, useEffect } from "react";
|
||||
import EditOffIcon from "@mui/icons-material/EditOff";
|
||||
import ModeEditIcon from "@mui/icons-material/ModeEdit";
|
||||
import Tooltip from "@mui/material/Tooltip"; // Importiere Tooltip von Material-UI
|
||||
|
||||
function EditModeToggle() {
|
||||
const [editMode, setEditMode] = useState(() => localStorage.getItem("editMode") === "true");
|
||||
|
||||
const toggleEditMode = () => {
|
||||
const newEditMode = !editMode;
|
||||
setEditMode(newEditMode);
|
||||
localStorage.setItem("editMode", newEditMode);
|
||||
//Browser neu laden, um die Änderungen anzuwenden
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const storedMode = localStorage.getItem("editMode") === "true";
|
||||
setEditMode(storedMode);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div onClick={toggleEditMode} style={{ cursor: "pointer" }}>
|
||||
{editMode ? (
|
||||
<Tooltip title="Bearbeitungsmodus deaktivieren" placement="top">
|
||||
<EditOffIcon />
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip title="Bearbeitungsmodus aktivieren" placement="top">
|
||||
<ModeEditIcon />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditModeToggle;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,9 +16,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
const [deviceName, setDeviceName] = useState("");
|
||||
const [idLD, setIdLD] = useState(poiData ? poiData.idLD : "");
|
||||
|
||||
const [description, setDescription] = useState(
|
||||
poiData ? poiData.description : ""
|
||||
);
|
||||
const [description, setDescription] = useState(poiData ? poiData.description : "");
|
||||
|
||||
useEffect(() => {
|
||||
if (poiData) {
|
||||
@@ -37,16 +35,11 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
const fetchDeviceId = async () => {
|
||||
if (poiData && poiData.idLD) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/talas_v5_DB/locationDevice/getDeviceIdById?idLD=${poiData.idLD}`
|
||||
);
|
||||
const response = await fetch(`/api/talas_v5_DB/locationDevice/getDeviceIdById?idLD=${poiData.idLD}`);
|
||||
const data = await response.json();
|
||||
if (data) setDeviceName(data.name);
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"Fehler beim Abrufen der Geräteinformation in PoiUpdateModel.js: ",
|
||||
error
|
||||
);
|
||||
console.error("Fehler beim Abrufen der Geräteinformation in PoiUpdateModel.js: ", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -57,12 +50,9 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
const handleDeletePoi = async () => {
|
||||
if (confirm("Sind Sie sicher, dass Sie diesen POI löschen möchten?")) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/talas_v5_DB/pois/deletePoi?id=${poiId}`,
|
||||
{
|
||||
method: "DELETE",
|
||||
}
|
||||
);
|
||||
const response = await fetch(`/api/talas_v5_DB/pois/deletePoi?id=${poiId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
if (response.ok) {
|
||||
alert("POI wurde erfolgreich gelöscht.");
|
||||
onClose();
|
||||
@@ -71,7 +61,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
throw new Error("Fehler beim Löschen des POI.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Löschen des POI:", error);
|
||||
console.error("Fehler beim Löschen des POI 1:", error);
|
||||
alert("Fehler beim Löschen des POI.");
|
||||
}
|
||||
}
|
||||
@@ -106,16 +96,13 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
const data = await response.json();
|
||||
setLocationDeviceData(data);
|
||||
if (poiData && poiData.idLD) {
|
||||
const selectedDevice = data.find(
|
||||
(device) => device.id === poiData.idLD
|
||||
);
|
||||
setDeviceName(selectedDevice ? selectedDevice.id : data[0].id);
|
||||
const selectedDevice = data.find((device) => device.id === poiData.idLD);
|
||||
setDeviceName(selectedDevice ? selectedDevice.id : data[0].id); // Hier wird die ID als initialer Zustand gesetzt
|
||||
console.log("Selected Device:", selectedDevice);
|
||||
console.log("Selected devciceName:", deviceName);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"Fehler beim Abrufen der Standort- und Gerätedaten:",
|
||||
error
|
||||
);
|
||||
console.error("Fehler beim Abrufen der Standort- und Gerätedaten:", error);
|
||||
}
|
||||
};
|
||||
fetchData();
|
||||
@@ -126,9 +113,10 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
setLocationDeviceData(data);
|
||||
const currentDevice = data.find(
|
||||
(device) => device.idLD === currentPoi.idLD
|
||||
);
|
||||
console.log("Standort- und Gerätedaten 3:", data);
|
||||
console.log("Standort- und Gerätedaten 3 poiData:", poiData);
|
||||
// Findet das Gerät, das der aktuellen IDLD entspricht
|
||||
const currentDevice = data.find((device) => device.idLD === currentPoi.idLD);
|
||||
if (currentDevice) {
|
||||
setDeviceName(currentDevice.name);
|
||||
}
|
||||
@@ -141,9 +129,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
const idLDResponse = await fetch(
|
||||
`/api/talas_v5_DB/locationDevice/getDeviceId?deviceName=${encodeURIComponent(deviceName)}`
|
||||
);
|
||||
const idLDResponse = await fetch(`/api/talas_v5_DB/locationDevice/getDeviceId?deviceName=${encodeURIComponent(deviceName)}`);
|
||||
const idLDData = await idLDResponse.json();
|
||||
const idLD = idLDData.idLD;
|
||||
try {
|
||||
@@ -166,9 +152,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
window.location.reload();
|
||||
} else {
|
||||
const errorResponse = await response.json();
|
||||
throw new Error(
|
||||
errorResponse.error || "Fehler beim Aktualisieren des POI."
|
||||
);
|
||||
throw new Error(errorResponse.error || "Fehler beim Aktualisieren des POI.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Aktualisieren des POI:", error);
|
||||
@@ -176,39 +160,37 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
}
|
||||
};
|
||||
|
||||
//ausgewählte poi Informationen in Console anzeigen
|
||||
console.log("Selected POI:", selectedPoi);
|
||||
console.log("Selected POI Gerät id in poiUpdateModal.js:", selectedPoi.id);
|
||||
console.log("Selected POI Typ name in poiUpdateModal.js:", selectedPoi.typ); //als Typ in dropdown menu
|
||||
console.log("Selected POI Beschreibung in poiUpdateModal.js:", selectedPoi.description);
|
||||
console.log("Selected POI Gerät deviceId in poiUpdateModal.js:", selectedPoi.deviceId);
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className="m-0 p-2 w-full">
|
||||
<div className="flex items-center mb-4">
|
||||
<label htmlFor="description" className="block mr-2 flex-none">
|
||||
Beschreibung:
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="description"
|
||||
name="description"
|
||||
value={description}
|
||||
onChange={(e) => setDescription(e.target.value)}
|
||||
placeholder="Beschreibung der Station"
|
||||
className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm"
|
||||
/>
|
||||
<input type="text" id="description" name="description" value={description} onChange={(e) => setDescription(e.target.value)} placeholder="Beschreibung der Station" className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm" />
|
||||
</div>
|
||||
|
||||
<div className="flex items-center mb-4">
|
||||
<label htmlFor="deviceName" className="block mr-2 flex-none">
|
||||
Gerät:
|
||||
</label>
|
||||
<select
|
||||
id="deviceName"
|
||||
name="deviceName"
|
||||
value={deviceName}
|
||||
onChange={(e) => setDeviceName(e.target.value)}
|
||||
className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm"
|
||||
>
|
||||
{locationDeviceData.map((device, index) => (
|
||||
<option key={index} value={device.id}>
|
||||
{device.name}
|
||||
</option>
|
||||
))}
|
||||
<select id="deviceName" name="deviceName" value={deviceName} onChange={(e) => setDeviceName(e.target.value)} className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm">
|
||||
{locationDeviceData.map(
|
||||
(device, index) => (
|
||||
console.log("device.id und name:", device),
|
||||
(
|
||||
<option key={index} value={device.id}>
|
||||
{device.name}
|
||||
</option>
|
||||
)
|
||||
)
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -216,13 +198,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
<label htmlFor="idPoiTyp2" className="block mr-2 flex-none">
|
||||
Typ:
|
||||
</label>
|
||||
<select
|
||||
id="idPoiTyp2"
|
||||
name="idPoiTyp2"
|
||||
value={poiTypeId}
|
||||
onChange={(e) => setPoiTypeId(e.target.value)}
|
||||
className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm"
|
||||
>
|
||||
<select id="idPoiTyp2" name="idPoiTyp2" value={poiTypeId} onChange={(e) => setPoiTypeId(e.target.value)} className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm">
|
||||
{poiTypData.map((poiTyp, index) => (
|
||||
<option key={index} value={poiTyp.idPoiTyp}>
|
||||
{poiTyp.name}
|
||||
@@ -239,10 +215,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => {
|
||||
POI löschen
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded w-full"
|
||||
>
|
||||
<button type="submit" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded w-full">
|
||||
POI aktualisieren
|
||||
</button>
|
||||
</form>
|
||||
|
||||
@@ -23,6 +23,7 @@ export const addMarkersToMap = (markers, map, layerGroup) => {
|
||||
marker.on("mouseover", () => marker.openPopup());
|
||||
marker.on("mouseout", () => marker.closePopup());
|
||||
marker.on("dragend", (e) => {
|
||||
console.log("Marker wurde verschoben in addMarkersToMap");
|
||||
const newLat = e.target.getLatLng().lat;
|
||||
const newLng = e.target.getLatLng().lng;
|
||||
const markerId = e.target.options.id;
|
||||
@@ -32,11 +33,7 @@ export const addMarkersToMap = (markers, map, layerGroup) => {
|
||||
};
|
||||
|
||||
// Funktion zum Aktualisieren der Standorte in der Datenbank
|
||||
export const updateLocationInDatabase = async (
|
||||
id,
|
||||
newLatitude,
|
||||
newLongitude
|
||||
) => {
|
||||
export const updateLocationInDatabase = async (id, newLatitude, newLongitude) => {
|
||||
const response = await fetch("/api/talas_v5_DB/pois/updateLocation", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
|
||||
37
components/TestScript.js
Normal file
37
components/TestScript.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// components/TestScript.js
|
||||
import { useEffect } from "react";
|
||||
import setupPolylinesCode from "!!raw-loader!../utils/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
|
||||
}
|
||||
30
components/VersionInfoModal.js
Normal file
30
components/VersionInfoModal.js
Normal file
@@ -0,0 +1,30 @@
|
||||
// components/VersionInfoModal.js
|
||||
import React from "react";
|
||||
|
||||
const VersionInfoModal = ({ showVersionInfoModal, closeVersionInfoModal, MAP_VERSION }) => {
|
||||
return (
|
||||
<>
|
||||
{showVersionInfoModal && (
|
||||
<div className="fixed inset-0 flex items-center justify-center z-50">
|
||||
<div className="fixed inset-0 bg-black bg-opacity-50" onClick={closeVersionInfoModal}></div>
|
||||
<div className="bg-white p-6 rounded-lg shadow-lg z-60 max-w-lg mx-auto">
|
||||
<img src="img/Logo_TALAS.png" alt="TALAS V5 Logo" className="w-1/2 mx-auto my-4" />
|
||||
<div className="bg-white border p-6 rounded-lg shadow-lg z-60 max-w-lg mx-auto">
|
||||
<h2 className="text-xl font-bold mb-6 text-start leading-tight">Littwin Systemtechnik GmbH & Co. KG</h2>
|
||||
<h4 className="text-lg font-bold mb-2 text-start leading-tight">Bürgermeister-Brötje Str. 28</h4>
|
||||
<h4 className="text-lg font-bold mb-2 text-start leading-tight">D-26180 Rastede</h4>
|
||||
<h5 className="text-md mb-2 text-start leading-snug">T: +49 4402 9725 77-0</h5>
|
||||
<h5 className="text-md mb-2 text-start leading-snug">E: kontakt@littwin-systemtechnik.de</h5>
|
||||
</div>
|
||||
<p className="text-gray-700 text-center font-bold mt-4 leading-relaxed">TALAS.Map Version {MAP_VERSION}</p>
|
||||
<button onClick={closeVersionInfoModal} className="mt-4 bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-700 mx-auto block">
|
||||
Schließen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default VersionInfoModal;
|
||||
26
components/gisPolylines/PolylineContextMenu.js
Normal file
26
components/gisPolylines/PolylineContextMenu.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// /components/gisPolylines/PolylineContextMenu.js
|
||||
import React from "react";
|
||||
|
||||
const PolylineContextMenu = ({ position, onAddPoint, onRemovePoint, onClose }) => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: position.y,
|
||||
left: position.x,
|
||||
backgroundColor: "white",
|
||||
border: "1px solid black",
|
||||
padding: "10px",
|
||||
zIndex: 1000,
|
||||
}}
|
||||
>
|
||||
<ul>
|
||||
<li onClick={onAddPoint}>Stützpunkt hinzufügen</li>
|
||||
<li onClick={onRemovePoint}>Stützpunkt entfernen</li>
|
||||
<li onClick={onClose}>Schließen</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PolylineContextMenu;
|
||||
12
components/gisPolylines/icons/CircleIcon.js
Normal file
12
components/gisPolylines/icons/CircleIcon.js
Normal file
@@ -0,0 +1,12 @@
|
||||
// /components/gisPolylines/icons/CircleIcon.js
|
||||
import L from "leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
|
||||
const CircleIcon = new L.DivIcon({
|
||||
className: "custom-circle-icon leaflet-marker-icon",
|
||||
html: '<div style="background-color:gray; width:10px; height:10px; border-radius:50%; border: solid black 1px;"></div>',
|
||||
iconSize: [25, 25],
|
||||
iconAnchor: [5, 5],
|
||||
});
|
||||
|
||||
export default CircleIcon;
|
||||
11
components/gisPolylines/icons/EndIcon.js
Normal file
11
components/gisPolylines/icons/EndIcon.js
Normal file
@@ -0,0 +1,11 @@
|
||||
// /components/gisPolylines/icons/EndIcon.js
|
||||
// Viereck als End-Icon für die Route
|
||||
import L from "leaflet";
|
||||
const EndIcon = L.divIcon({
|
||||
className: "custom-end-icon",
|
||||
html: "<div style='background-color: gray; width: 14px; height: 14px; border: solid black 2px;'></div>", // Graues Viereck
|
||||
iconSize: [14, 14],
|
||||
iconAnchor: [7, 7], // Mittelpunkt des Vierecks als Anker
|
||||
});
|
||||
|
||||
export default EndIcon;
|
||||
17
components/gisPolylines/icons/StartIcon.js
Normal file
17
components/gisPolylines/icons/StartIcon.js
Normal file
@@ -0,0 +1,17 @@
|
||||
// /components/gisPolylines/icons/StartIcon.js
|
||||
//Custom triangle icon for draggable markers
|
||||
import L from "leaflet";
|
||||
|
||||
const StartIcon = L.divIcon({
|
||||
className: "custom-start-icon",
|
||||
html: `
|
||||
<svg width="18" height="18" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||
<polygon points="10,2 18,18 2,18" fill="black" />
|
||||
<polygon points="10,5 16,16 4,16" fill="gray" />
|
||||
</svg>
|
||||
`, // Schwarzes Dreieck innerhalb eines grauen Dreiecks
|
||||
iconSize: [18, 18],
|
||||
iconAnchor: [9, 10],
|
||||
});
|
||||
|
||||
export default StartIcon;
|
||||
27
components/gisPolylines/icons/SupportPointIcons.js
Normal file
27
components/gisPolylines/icons/SupportPointIcons.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// komponents/gisPolylines/icons/SupportPointIcons
|
||||
import L from "leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
|
||||
// Icon für Stützpunkt hinzufügen
|
||||
export const AddSupportPointIcon = L.divIcon({
|
||||
className: "custom-add-support-point-icon",
|
||||
html: `
|
||||
<div style='background-color:green;border-radius:50%;width:12px;height:12px;border: solid white 2px;'>
|
||||
<div style='color: white; font-size: 10px; text-align: center; line-height: 12px;'>+</div>
|
||||
</div>
|
||||
`,
|
||||
iconSize: [24, 24],
|
||||
iconAnchor: [12, 12],
|
||||
});
|
||||
|
||||
// Icon für Stützpunkt entfernen
|
||||
export const RemoveSupportPointIcon = L.divIcon({
|
||||
className: "custom-remove-support-point-icon",
|
||||
html: `
|
||||
<div style='background-color:red;border-radius:50%;width:12px;height:12px;border: solid white 2px;'>
|
||||
<div style='color: white; font-size: 10px; text-align: center; line-height: 12px;'>-</div>
|
||||
</div>
|
||||
`,
|
||||
iconSize: [24, 24],
|
||||
iconAnchor: [12, 12],
|
||||
});
|
||||
162
components/imports.js
Normal file
162
components/imports.js
Normal file
@@ -0,0 +1,162 @@
|
||||
// imports.js
|
||||
import React, { useEffect, useRef, useState, useCallback } from "react";
|
||||
import L, { marker } from "leaflet";
|
||||
import "leaflet/dist/leaflet.css";
|
||||
import "leaflet-contextmenu/dist/leaflet.contextmenu.css";
|
||||
import "leaflet-contextmenu";
|
||||
import * as config from "../config/config.js";
|
||||
import * as urls from "../config/urls.js";
|
||||
import "leaflet.smooth_marker_bouncing";
|
||||
import OverlappingMarkerSpiderfier from "overlapping-marker-spiderfier-leaflet";
|
||||
import DataSheet from "./DataSheet.js";
|
||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from "recoil";
|
||||
import { gisStationsStaticDistrictState } from "../store/atoms/gisStationState.js";
|
||||
import { gisSystemStaticState } from "../store/atoms/gisSystemState.js";
|
||||
import { mapLayersState } from "../store/atoms/mapLayersState.js";
|
||||
import { selectedAreaState } from "../store/atoms/selectedAreaState.js";
|
||||
import { zoomTriggerState } from "../store/atoms/zoomTriggerState.js";
|
||||
import { poiTypState } from "../store/atoms/poiTypState.js";
|
||||
import AddPoiModalWindow from "./pois/AddPoiModalWindow.js";
|
||||
import { poiReadFromDbTriggerAtom } from "../store/atoms/poiReadFromDbTriggerAtom.js";
|
||||
import { InformationCircleIcon } from "@heroicons/react/20/solid"; // oder 'outline'
|
||||
import PoiUpdateModal from "./pois/PoiUpdateModal.js";
|
||||
import { selectedPoiState } from "../store/atoms/poiState.js";
|
||||
import { currentPoiState } from "../store/atoms/currentPoiState.js";
|
||||
import { ToastContainer, toast } from "react-toastify";
|
||||
import "react-toastify/dist/ReactToastify.css";
|
||||
import { mapIdState, userIdState } from "../store/atoms/urlParameterState.js";
|
||||
import { poiLayerVisibleState } from "../store/atoms/poiLayerVisibleState.js";
|
||||
import plusRoundIcon from "./PlusRoundIcon.js";
|
||||
import { parsePoint, findClosestPoints } from "../utils/geometryUtils.js";
|
||||
import { insertNewPOI, removePOI, handleEditPoi } from "../utils/poiUtils.js";
|
||||
import { createAndSetDevices } from "../utils/createAndSetDevices.js";
|
||||
import { redrawPolyline, restoreMapSettings, checkOverlappingMarkers } from "../utils/mapUtils.js";
|
||||
import circleIcon from "./gisPolylines/icons/CircleIcon.js";
|
||||
import startIcon from "./gisPolylines/icons/StartIcon.js";
|
||||
import endIcon from "./gisPolylines/icons/EndIcon.js";
|
||||
import { fetchGisStatusStations, fetchPriorityConfig, fetchPoiData, updateLocationInDatabase, fetchUserRights, fetchDeviceNameById } from "../services/apiService.js";
|
||||
import { addContextMenuToMarker } from "../utils/addContextMenuToMarker.js";
|
||||
import { MAP_VERSION } from "../config/settings.js";
|
||||
import * as layers from "../config/layers.js";
|
||||
import { zoomIn, zoomOut, centerHere } from "../utils/zoomAndCenterUtils.js";
|
||||
import { initializeMap } from "../utils/initializeMap.js";
|
||||
import { addItemsToMapContextMenu } from "./useMapContextMenu.js";
|
||||
import useGmaMarkersLayer from "../hooks/layers/useGmaMarkersLayer.js"; // Import the custom hook
|
||||
import useTalasMarkersLayer from "../hooks/layers/useTalasMarkersLayer.js"; // Import the custom hook
|
||||
import useEciMarkersLayer from "../hooks/layers/useEciMarkersLayer.js";
|
||||
import useGsmModemMarkersLayer from "../hooks/layers/useGsmModemMarkersLayer.js";
|
||||
import useCiscoRouterMarkersLayer from "../hooks/layers/useCiscoRouterMarkersLayer.js";
|
||||
import useWagoMarkersLayer from "../hooks/layers/useWagoMarkersLayer.js";
|
||||
import useSiemensMarkersLayer from "../hooks/layers/useSiemensMarkersLayer.js";
|
||||
import useOtdrMarkersLayer from "../hooks/layers/useOtdrMarkersLayer.js";
|
||||
import useWdmMarkersLayer from "../hooks/layers/useWdmMarkersLayer.js";
|
||||
import useMessstellenMarkersLayer from "../hooks/layers/useMessstellenMarkersLayer.js";
|
||||
import useTalasiclMarkersLayer from "../hooks/layers/useTalasiclMarkersLayer.js";
|
||||
import useDauzMarkersLayer from "../hooks/layers/useDauzMarkersLayer.js";
|
||||
import useSmsfunkmodemMarkersLayer from "../hooks/layers/useSmsfunkmodemMarkersLayer.js";
|
||||
import useUlafMarkersLayer from "../hooks/layers/useUlafMarkersLayer.js";
|
||||
import useSonstigeMarkersLayer from "../hooks/layers/useSonstigeMarkersLayer.js";
|
||||
import handlePoiSelect from "../utils/handlePoiSelect.js";
|
||||
import { fetchGisStationsStaticDistrict, fetchGisStationsStatusDistrict, fetchGisStationsMeasurements, fetchGisSystemStatic } from "../services/fetchData.js";
|
||||
import { setupPolylines } from "../utils/setupPolylines.js";
|
||||
import { setupPOIs } from "../utils/setupPOIs.js";
|
||||
import VersionInfoModal from "./VersionInfoModal.js";
|
||||
//--------------------------------------------
|
||||
import PoiUpdateModalWrapper from "./pois/PoiUpdateModalWrapper";
|
||||
import AddPoiModalWindowWrapper from "./pois/AddPoiModalWindowWrapper";
|
||||
import useFetchPoiData from "../hooks/useFetchPoiData";
|
||||
import usePoiTypData from "../hooks/usePoiTypData";
|
||||
import useMarkerLayers from "../hooks/useMarkerLayers";
|
||||
import useLayerVisibility from "../hooks/useLayerVisibility";
|
||||
import useLineData from "../hooks/useLineData.js";
|
||||
|
||||
export {
|
||||
React,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
useCallback,
|
||||
L,
|
||||
marker,
|
||||
config,
|
||||
urls,
|
||||
OverlappingMarkerSpiderfier,
|
||||
DataSheet,
|
||||
useRecoilState,
|
||||
useRecoilValue,
|
||||
useSetRecoilState,
|
||||
gisStationsStaticDistrictState,
|
||||
gisSystemStaticState,
|
||||
mapLayersState,
|
||||
selectedAreaState,
|
||||
zoomTriggerState,
|
||||
poiTypState,
|
||||
AddPoiModalWindow,
|
||||
poiReadFromDbTriggerAtom,
|
||||
InformationCircleIcon,
|
||||
PoiUpdateModal,
|
||||
selectedPoiState,
|
||||
currentPoiState,
|
||||
ToastContainer,
|
||||
toast,
|
||||
mapIdState,
|
||||
userIdState,
|
||||
poiLayerVisibleState,
|
||||
plusRoundIcon,
|
||||
parsePoint,
|
||||
findClosestPoints,
|
||||
insertNewPOI,
|
||||
removePOI,
|
||||
createAndSetDevices,
|
||||
handleEditPoi,
|
||||
redrawPolyline,
|
||||
restoreMapSettings,
|
||||
checkOverlappingMarkers,
|
||||
circleIcon,
|
||||
startIcon,
|
||||
endIcon,
|
||||
fetchGisStatusStations,
|
||||
fetchPriorityConfig,
|
||||
fetchPoiData,
|
||||
updateLocationInDatabase,
|
||||
fetchUserRights,
|
||||
fetchDeviceNameById,
|
||||
addContextMenuToMarker,
|
||||
MAP_VERSION,
|
||||
layers,
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
centerHere,
|
||||
initializeMap,
|
||||
addItemsToMapContextMenu,
|
||||
useGmaMarkersLayer,
|
||||
useTalasMarkersLayer,
|
||||
useEciMarkersLayer,
|
||||
useGsmModemMarkersLayer,
|
||||
useCiscoRouterMarkersLayer,
|
||||
useWagoMarkersLayer,
|
||||
useSiemensMarkersLayer,
|
||||
useOtdrMarkersLayer,
|
||||
useWdmMarkersLayer,
|
||||
useMessstellenMarkersLayer,
|
||||
useTalasiclMarkersLayer,
|
||||
useDauzMarkersLayer,
|
||||
useSmsfunkmodemMarkersLayer,
|
||||
useUlafMarkersLayer,
|
||||
useSonstigeMarkersLayer,
|
||||
handlePoiSelect,
|
||||
fetchGisStationsStaticDistrict,
|
||||
fetchGisStationsStatusDistrict,
|
||||
fetchGisStationsMeasurements,
|
||||
fetchGisSystemStatic,
|
||||
setupPolylines,
|
||||
setupPOIs,
|
||||
VersionInfoModal,
|
||||
PoiUpdateModalWrapper,
|
||||
AddPoiModalWindowWrapper,
|
||||
useFetchPoiData,
|
||||
usePoiTypData,
|
||||
useMarkerLayers,
|
||||
useLayerVisibility,
|
||||
useLineData,
|
||||
};
|
||||
217
components/pois/AddPoiModalWindow.js
Normal file
217
components/pois/AddPoiModalWindow.js
Normal file
@@ -0,0 +1,217 @@
|
||||
// components/pois/AddPoiModalWindow.js
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Select from "react-select"; // Importiere react-select
|
||||
import { useSetRecoilState, useRecoilState } from "recoil";
|
||||
import { mapLayersState } from "../../store/atoms/mapLayersState";
|
||||
import { poiReadFromDbTriggerAtom } from "../../store/atoms/poiReadFromDbTriggerAtom";
|
||||
|
||||
const AddPoiModalWindow = ({ onClose, map, latlng }) => {
|
||||
const [poiTypData, setpoiTypData] = useState([]);
|
||||
const [name, setName] = useState("");
|
||||
const [poiTypeId, setPoiTypeId] = useState(null); // Verwende null für react-select
|
||||
const [latitude] = useState(latlng.lat.toFixed(5));
|
||||
const [longitude] = useState(latlng.lng.toFixed(5));
|
||||
const setTrigger = useSetRecoilState(poiReadFromDbTriggerAtom); // Verwende useSetRecoilState
|
||||
const [locationDeviceData, setLocationDeviceData] = useState([]);
|
||||
const [filteredDevices, setFilteredDevices] = useState([]); // Gefilterte Geräte
|
||||
const [deviceName, setDeviceName] = useState(null); // Verwende null für react-select
|
||||
const [mapLayersVisibility] = useRecoilState(mapLayersState); // Um die aktiven Layer zu erhalten
|
||||
|
||||
// Map von Systemnamen zu ids (wie zuvor)
|
||||
const systemNameToIdMap = {
|
||||
TALAS: 1,
|
||||
ECI: 2,
|
||||
ULAF: 3,
|
||||
GSMModem: 5,
|
||||
CiscoRouter: 6,
|
||||
WAGO: 7,
|
||||
Siemens: 8,
|
||||
OTDR: 9,
|
||||
WDM: 10,
|
||||
GMA: 11,
|
||||
Messdatensammler: 12,
|
||||
Messstellen: 13,
|
||||
TALASICL: 100,
|
||||
DAUZ: 110,
|
||||
SMSFunkmodem: 111,
|
||||
Basisgerät: 200,
|
||||
};
|
||||
|
||||
// API-Abfrage, um die Geräte zu laden
|
||||
useEffect(() => {
|
||||
const fetchInitialData = async () => {
|
||||
try {
|
||||
const [poiTypResponse, locationDeviceResponse] = await Promise.all([fetch("/api/talas_v5_DB/poiTyp/readPoiTyp"), fetch("/api/talas5/location_device")]);
|
||||
|
||||
const poiTypData = await poiTypResponse.json();
|
||||
setpoiTypData(poiTypData);
|
||||
|
||||
const locationDeviceData = await locationDeviceResponse.json();
|
||||
console.log("Geräte von der API:", locationDeviceData); // Geräte-Daten aus der API anzeigen
|
||||
setLocationDeviceData(locationDeviceData);
|
||||
|
||||
// Filtere die Geräte basierend auf den sichtbaren Systemen
|
||||
filterDevices(locationDeviceData);
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Abrufen der Daten:", error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchInitialData();
|
||||
}, []);
|
||||
|
||||
// Funktion zum Filtern der Geräte basierend auf den aktiven Systemen (Layern)
|
||||
const filterDevices = (devices) => {
|
||||
const activeSystems = Object.keys(mapLayersVisibility).filter((system) => mapLayersVisibility[system]);
|
||||
console.log("Aktive Systeme:", activeSystems); // Anzeigen der aktiven Systeme
|
||||
|
||||
// Mappe aktive Systeme auf ihre ids
|
||||
const activeSystemIds = activeSystems.map((system) => systemNameToIdMap[system]).filter((id) => id !== undefined);
|
||||
console.log("Aktive System-IDs:", activeSystemIds); // Anzeigen der aktiven System-IDs
|
||||
|
||||
// Filtere die Geräte nach aktiven Systemen basierend auf idsystem_typ
|
||||
const filtered = devices.filter((device) => activeSystemIds.includes(device.idsystem_typ));
|
||||
console.log("Gefilterte Geräte:", filtered); // Gefilterte Geräte anzeigen
|
||||
|
||||
setFilteredDevices(filtered); // Setze die gefilterten Geräte
|
||||
};
|
||||
|
||||
// Wenn mapLayersVisibility sich ändert, filtere die Geräte erneut
|
||||
useEffect(() => {
|
||||
if (locationDeviceData.length > 0) {
|
||||
filterDevices(locationDeviceData);
|
||||
}
|
||||
}, [mapLayersVisibility, locationDeviceData]);
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
if (!poiTypeId) {
|
||||
alert("Bitte wählen Sie einen Typ aus.");
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = {
|
||||
name,
|
||||
poiTypeId: poiTypeId.value,
|
||||
latitude,
|
||||
longitude,
|
||||
idLD: filteredDevices.find((device) => device.name === deviceName?.value).idLD,
|
||||
};
|
||||
|
||||
const response = await fetch("/api/talas_v5_DB/pois/addLocation", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(formData),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
setTrigger((trigger) => trigger + 1); // Verwenden des Triggers zur Aktualisierung
|
||||
onClose();
|
||||
window.location.reload();
|
||||
} else {
|
||||
console.error("Fehler beim Hinzufügen des POI");
|
||||
}
|
||||
|
||||
if (map && typeof map.closePopup === "function") {
|
||||
map.closePopup();
|
||||
}
|
||||
};
|
||||
|
||||
// Erstelle Optionen für react-select
|
||||
const poiTypeOptions = poiTypData.map((poiTyp) => ({
|
||||
value: poiTyp.idPoiTyp,
|
||||
label: poiTyp.name,
|
||||
}));
|
||||
|
||||
const deviceOptions = filteredDevices.map((device) => ({
|
||||
value: device.name,
|
||||
label: device.name,
|
||||
}));
|
||||
|
||||
// Custom styles for react-select
|
||||
const customStyles = {
|
||||
control: (provided) => ({
|
||||
...provided,
|
||||
width: "100%",
|
||||
minWidth: "300px", // Minimum width for the dropdown
|
||||
maxWidth: "100%", // Maximum width (you can adjust this if needed)
|
||||
}),
|
||||
menu: (provided) => ({
|
||||
...provided,
|
||||
width: "100%",
|
||||
minWidth: "300px", // Ensure the dropdown menu stays at the minimum width
|
||||
}),
|
||||
};
|
||||
|
||||
// Style für größere Breite des Modals und für Inputs
|
||||
const modalStyles = {
|
||||
// width: "300px", // größere Breite für das Modal
|
||||
//maxWidth: "100%", // responsive, passt sich an
|
||||
//padding: "20px", // Polsterung für das Modal
|
||||
//backgroundColor: "white", // Hintergrundfarbe
|
||||
//borderRadius: "8px", // Abgerundete Ecken
|
||||
//boxShadow: "0px 4px 12px rgba(0, 0, 0, 0.1)", // Schatten für das Modal
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} style={modalStyles} className="m-0 p-2 w-full">
|
||||
<div className="flex flex-col mb-4">
|
||||
<label htmlFor="name" className="block mb-2 font-bold text-sm text-gray-700">
|
||||
Beschreibung :
|
||||
</label>
|
||||
<input type="text" id="name" value={name} onChange={(e) => setName(e.target.value)} className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm" />
|
||||
</div>
|
||||
|
||||
{/* React Select for Devices */}
|
||||
<div className="flex flex-col mb-4">
|
||||
<label htmlFor="deviceName" className="block mb-2 font-bold text-sm text-gray-700">
|
||||
Gerät :
|
||||
</label>
|
||||
<Select
|
||||
id="deviceName"
|
||||
value={deviceName}
|
||||
onChange={setDeviceName}
|
||||
options={deviceOptions}
|
||||
placeholder="Gerät auswählen..."
|
||||
isClearable
|
||||
styles={customStyles} // Apply custom styles here
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* React Select for POI Types */}
|
||||
<div className="flex flex-col mb-4">
|
||||
<label htmlFor="idPoiTyp" className="block mb-2 font-bold text-sm text-gray-700">
|
||||
Typ:
|
||||
</label>
|
||||
<Select
|
||||
id="idPoiTyp"
|
||||
value={poiTypeId}
|
||||
onChange={setPoiTypeId}
|
||||
options={poiTypeOptions}
|
||||
placeholder="Typ auswählen..."
|
||||
styles={customStyles} // Apply custom styles here
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center justify-between mb-4">
|
||||
<div className="flex flex-col items-center">
|
||||
<label htmlFor="lat" className="block mb-2 text-xs text-gray-700">
|
||||
Lat : {latitude}
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex flex-col items-center">
|
||||
<label htmlFor="lng" className="block mb-2 text-xs text-gray-700">
|
||||
Lng : {longitude}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded w-full">
|
||||
POI hinzufügen
|
||||
</button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddPoiModalWindow;
|
||||
24
components/pois/AddPoiModalWindowPopup.js
Normal file
24
components/pois/AddPoiModalWindowPopup.js
Normal file
@@ -0,0 +1,24 @@
|
||||
// components/pois/AddPoiModalWindowPopup.js
|
||||
import React from "react";
|
||||
import AddPoiModalWindow from "./AddPoiModalWindow.js";
|
||||
|
||||
const AddPoiModalWindowPopup = ({ showPopup, closePopup, handleAddStation, popupCoordinates }) => {
|
||||
return (
|
||||
<>
|
||||
{showPopup && (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-10 flex justify-center items-center z-[1000]" onClick={closePopup}>
|
||||
<div className="relative bg-white p-6 rounded-lg shadow-lg" onClick={(e) => e.stopPropagation()}>
|
||||
<button onClick={closePopup} className="absolute top-0 right-0 mt-2 mr-2 p-1 text-gray-700 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-gray-600" aria-label="Close">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
<AddPoiModalWindow onClose={closePopup} onSubmit={handleAddStation} latlng={popupCoordinates} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddPoiModalWindowPopup;
|
||||
30
components/pois/AddPoiModalWindowWrapper.js
Normal file
30
components/pois/AddPoiModalWindowWrapper.js
Normal file
@@ -0,0 +1,30 @@
|
||||
// components/pois/AddPoiModalWindowWrapper.js
|
||||
import React from "react";
|
||||
import AddPoiModalWindow from "./AddPoiModalWindow";
|
||||
|
||||
const AddPoiModalWindowWrapper = ({ show, onClose, latlng, handleAddStation }) => {
|
||||
return (
|
||||
show && (
|
||||
<div
|
||||
className="fixed inset-0 bg-black bg-opacity-10 flex justify-center items-center z-[1000]"
|
||||
onClick={onClose}
|
||||
data-testid="modal-overlay" // Hinzugefügt, um den Hintergrund zu identifizieren
|
||||
>
|
||||
<div
|
||||
className="relative bg-white p-6 rounded-lg shadow-lg"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
role="dialog" // Hinzugefügt, um das Dialog-Element zu identifizieren
|
||||
>
|
||||
<button onClick={onClose} className="absolute top-0 right-0 mt-2 mr-2 p-1 text-gray-700 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-gray-600" aria-label="Close">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
<AddPoiModalWindow onClose={onClose} onSubmit={handleAddStation} latlng={latlng} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default AddPoiModalWindowWrapper;
|
||||
256
components/pois/PoiUpdateModal.js
Normal file
256
components/pois/PoiUpdateModal.js
Normal file
@@ -0,0 +1,256 @@
|
||||
// /components/pois/PoiUpdateModal.js
|
||||
import React, { useState, useEffect } from "react";
|
||||
import Select from "react-select"; // Importiere react-select
|
||||
import { useRecoilState } from "recoil";
|
||||
import { selectedPoiState } from "../../store/atoms/poiState";
|
||||
import { currentPoiState } from "../../store/atoms/currentPoiState";
|
||||
import { mapLayersState } from "../../store/atoms/mapLayersState";
|
||||
|
||||
const PoiUpdateModal = ({ onClose, poiData, onSubmit }) => {
|
||||
const currentPoi = useRecoilState(currentPoiState);
|
||||
const selectedPoi = useRecoilState(selectedPoiState);
|
||||
const [mapLayersVisibility] = useRecoilState(mapLayersState);
|
||||
|
||||
const [poiId, setPoiId] = useState(poiData ? poiData.idPoi : "");
|
||||
const [name, setName] = useState(poiData ? poiData.name : "");
|
||||
const [poiTypData, setPoiTypData] = useState([]);
|
||||
const [poiTypeId, setPoiTypeId] = useState(null); // Verwende null für react-select
|
||||
const [locationDeviceData, setLocationDeviceData] = useState([]);
|
||||
const [filteredDevices, setFilteredDevices] = useState([]);
|
||||
const [deviceName, setDeviceName] = useState(poiData ? poiData.deviceName : null); // Verwende null für react-select
|
||||
const [idLD, setIdLD] = useState(poiData ? poiData.idLD : "");
|
||||
const [description, setDescription] = useState(poiData ? poiData.description : "");
|
||||
|
||||
// Map von Systemnamen zu IDs (wie zuvor)
|
||||
const systemNameToIdMap = {
|
||||
TALAS: 1,
|
||||
ECI: 2,
|
||||
ULAF: 3,
|
||||
GSMModem: 5,
|
||||
CiscoRouter: 6,
|
||||
WAGO: 7,
|
||||
Siemens: 8,
|
||||
OTDR: 9,
|
||||
WDM: 10,
|
||||
GMA: 11,
|
||||
Messdatensammler: 12,
|
||||
Messstellen: 13,
|
||||
TALASICL: 100,
|
||||
DAUZ: 110,
|
||||
SMSFunkmodem: 111,
|
||||
Basisgerät: 200,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (poiData) {
|
||||
setPoiId(poiData.idPoi);
|
||||
setName(poiData.name);
|
||||
setPoiTypeId(poiData.idPoiTyp); // Setze den Typ-ID
|
||||
setIdLD(poiData.idLD);
|
||||
setDescription(poiData.description);
|
||||
}
|
||||
}, [poiData]);
|
||||
|
||||
// Fetch POI types and set the current POI type in the react-select dropdown
|
||||
useEffect(() => {
|
||||
const fetchPoiTypData = async () => {
|
||||
try {
|
||||
const response = await fetch("/api/talas_v5_DB/poiTyp/readPoiTyp");
|
||||
const data = await response.json();
|
||||
setPoiTypData(data);
|
||||
|
||||
// Prüfe den gespeicherten Typ im localStorage
|
||||
const storedPoiType = localStorage.getItem("selectedPoiType");
|
||||
|
||||
// Finde den passenden Typ in den abgerufenen Daten und setze ihn als ausgewählt
|
||||
if (storedPoiType) {
|
||||
const matchingType = data.find((type) => type.name === storedPoiType);
|
||||
if (matchingType) {
|
||||
setPoiTypeId({ value: matchingType.idPoiTyp, label: matchingType.name });
|
||||
}
|
||||
} else if (poiData && poiData.idPoiTyp) {
|
||||
// Falls kein Typ im localStorage ist, setze den Typ von poiData
|
||||
const matchingType = data.find((type) => type.idPoiTyp === poiData.idPoiTyp);
|
||||
if (matchingType) {
|
||||
setPoiTypeId({ value: matchingType.idPoiTyp, label: matchingType.name });
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Abrufen der poiTyp Daten:", error);
|
||||
}
|
||||
};
|
||||
fetchPoiTypData();
|
||||
}, [poiData]);
|
||||
|
||||
// Fetch location devices and pre-select the current device
|
||||
useEffect(() => {
|
||||
const fetchLocationDevices = async () => {
|
||||
try {
|
||||
const response = await fetch("/api/talas5/location_device");
|
||||
const data = await response.json();
|
||||
setLocationDeviceData(data);
|
||||
filterDevices(data);
|
||||
|
||||
if (poiData && poiData.idLD) {
|
||||
const selectedDevice = data.find((device) => device.idLD === poiData.idLD);
|
||||
setDeviceName(selectedDevice ? { value: selectedDevice.name, label: selectedDevice.name } : null);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Abrufen der Standort- und Gerätedaten:", error);
|
||||
}
|
||||
};
|
||||
fetchLocationDevices();
|
||||
}, [poiData]);
|
||||
|
||||
// Funktion zum Filtern der Geräte basierend auf den aktiven Systemen (Layern)
|
||||
const filterDevices = (devices) => {
|
||||
const activeSystems = Object.keys(mapLayersVisibility).filter((system) => mapLayersVisibility[system]);
|
||||
|
||||
// Mappe aktive Systeme auf ihre ids
|
||||
const activeSystemIds = activeSystems.map((system) => systemNameToIdMap[system]).filter((id) => id !== undefined);
|
||||
|
||||
// Filtere die Geräte nach aktiven Systemen basierend auf idsystem_typ
|
||||
const filtered = devices.filter((device) => activeSystemIds.includes(device.idsystem_typ));
|
||||
setFilteredDevices(filtered);
|
||||
};
|
||||
|
||||
const handleSubmit = async (event) => {
|
||||
event.preventDefault();
|
||||
const idLDResponse = await fetch(`/api/talas_v5_DB/locationDevice/getDeviceId?deviceName=${encodeURIComponent(deviceName?.value)}`);
|
||||
const idLDData = await idLDResponse.json();
|
||||
const idLD = idLDData.idLD;
|
||||
|
||||
try {
|
||||
const response = await fetch("/api/talas_v5_DB/pois/updatePoi", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
idPoi: poiId,
|
||||
name: name,
|
||||
description: description,
|
||||
idPoiTyp: poiTypeId?.value, // Den ausgewählten Typ mitsenden
|
||||
idLD: idLD,
|
||||
}),
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
onClose();
|
||||
window.location.reload();
|
||||
} else {
|
||||
const errorResponse = await response.json();
|
||||
throw new Error(errorResponse.error || "Fehler beim Aktualisieren des POI.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Aktualisieren des POI:", error);
|
||||
alert("Fehler beim Aktualisieren des POI.");
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeletePoi = async () => {
|
||||
if (confirm("Sind Sie sicher, dass Sie diesen POI löschen möchten?")) {
|
||||
try {
|
||||
const response = await fetch(`/api/talas_v5_DB/pois/deletePoi?id=${poiId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
if (response.ok) {
|
||||
onClose();
|
||||
window.location.reload(); // Aktualisiert die Seite nach dem Löschen
|
||||
} else {
|
||||
throw new Error("Fehler beim Löschen des POI.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Löschen des POI:", error);
|
||||
alert("Fehler beim Löschen des POI.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Erstelle Optionen für react-select
|
||||
const poiTypeOptions = poiTypData.map((poiTyp) => ({
|
||||
value: poiTyp.idPoiTyp,
|
||||
label: poiTyp.name,
|
||||
}));
|
||||
|
||||
const deviceOptions = filteredDevices.map((device) => ({
|
||||
value: device.name,
|
||||
label: device.name,
|
||||
}));
|
||||
|
||||
// Custom styles for react-select
|
||||
const customStyles = {
|
||||
control: (provided) => ({
|
||||
...provided,
|
||||
width: "100%",
|
||||
minWidth: "300px", // Minimum width for the dropdown
|
||||
maxWidth: "100%", // Maximum width (you can adjust this if needed)
|
||||
}),
|
||||
menu: (provided) => ({
|
||||
...provided,
|
||||
width: "100%",
|
||||
minWidth: "300px", // Ensure the dropdown menu stays at the minimum width
|
||||
}),
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black bg-opacity-10 flex justify-center items-center z-[1000]" onClick={onClose}>
|
||||
<div className="relative bg-white p-6 rounded-lg shadow-lg" onClick={(e) => e.stopPropagation()}>
|
||||
<button onClick={onClose} className="absolute top-0 right-0 mt-2 mr-2 p-1 text-gray-700 hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-gray-600" aria-label="Close">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
<form onSubmit={handleSubmit} className="m-0 p-2 w-full">
|
||||
<div className="flex flex-col mb-4">
|
||||
<label htmlFor="description" className="block mb-2 font-bold text-sm text-gray-700">
|
||||
Beschreibung:
|
||||
</label>
|
||||
<input type="text" id="description" name="description" value={description} onChange={(e) => setDescription(e.target.value)} placeholder="Beschreibung der Station" className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm" />
|
||||
</div>
|
||||
|
||||
{/* React Select for Devices */}
|
||||
<div className="flex flex-col mb-4">
|
||||
<label htmlFor="deviceName" className="block mb-2 font-bold text-sm text-gray-700">
|
||||
Gerät:
|
||||
</label>
|
||||
<Select
|
||||
id="deviceName"
|
||||
value={deviceName}
|
||||
onChange={setDeviceName}
|
||||
options={deviceOptions} // Options for filtering
|
||||
placeholder="Gerät auswählen..."
|
||||
isClearable={true} // Allow clearing the selection
|
||||
styles={customStyles} // Apply custom styles
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* React Select for POI Types */}
|
||||
<div className="flex flex-col mb-4">
|
||||
<label htmlFor="idPoiTyp" className="block mb-2 font-bold text-sm text-gray-700">
|
||||
Typ:
|
||||
</label>
|
||||
<Select
|
||||
id="idPoiTyp"
|
||||
value={poiTypeId}
|
||||
onChange={setPoiTypeId}
|
||||
options={poiTypeOptions} // Options for filtering
|
||||
placeholder="Typ auswählen..."
|
||||
isClearable={true}
|
||||
styles={customStyles} // Apply custom styles
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button type="button" onClick={handleDeletePoi} className="bg-red-400 hover:bg-red-600 text-white font-bold py-2 px-4 rounded w-full mb-4">
|
||||
POI löschen
|
||||
</button>
|
||||
<button type="submit" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded w-full">
|
||||
POI aktualisieren
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PoiUpdateModal;
|
||||
9
components/pois/PoiUpdateModalWindow.js
Normal file
9
components/pois/PoiUpdateModalWindow.js
Normal file
@@ -0,0 +1,9 @@
|
||||
// components/pois/PoiUpdateModalWindow.js
|
||||
import React from "react";
|
||||
import PoiUpdateModal from "./PoiUpdateModal.js";
|
||||
|
||||
const PoiUpdateModalWindow = ({ showPoiUpdateModal, closePoiUpdateModal, currentPoiData, popupCoordinates }) => {
|
||||
return <>{showPoiUpdateModal && <PoiUpdateModal onClose={closePoiUpdateModal} poiData={currentPoiData} onSubmit={() => {}} latlng={popupCoordinates} />}</>;
|
||||
};
|
||||
|
||||
export default PoiUpdateModalWindow;
|
||||
26
components/pois/PoiUpdateModalWrapper.js
Normal file
26
components/pois/PoiUpdateModalWrapper.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// components/pois/PoiUpdateModalWrapper.js
|
||||
import React, { useState } from "react";
|
||||
import PoiUpdateModal from "./PoiUpdateModal";
|
||||
import { useRecoilValue, useSetRecoilState } from "recoil";
|
||||
import { currentPoiState, selectedPoiState } from "../../store/atoms/poiState";
|
||||
import { poiReadFromDbTriggerAtom } from "../../store/atoms/poiReadFromDbTriggerAtom";
|
||||
|
||||
const PoiUpdateModalWrapper = ({ show, onClose, latlng }) => {
|
||||
const setSelectedPoi = useSetRecoilState(selectedPoiState);
|
||||
const setCurrentPoi = useSetRecoilState(currentPoiState);
|
||||
const currentPoi = useRecoilValue(currentPoiState);
|
||||
const poiReadTrigger = useRecoilValue(poiReadFromDbTriggerAtom);
|
||||
|
||||
return (
|
||||
show && (
|
||||
<PoiUpdateModal
|
||||
onClose={onClose}
|
||||
poiData={currentPoi}
|
||||
onSubmit={() => {}} // Add your submit logic here
|
||||
latlng={latlng}
|
||||
/>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default PoiUpdateModalWrapper;
|
||||
53
components/pois/PoiUtils.js
Normal file
53
components/pois/PoiUtils.js
Normal file
@@ -0,0 +1,53 @@
|
||||
// components/pois/PoiUtils.js
|
||||
import L from "leaflet";
|
||||
|
||||
// Funktion, um POI Markers zu erstellen
|
||||
export const createPoiMarkers = (poiData, iconPath) => {
|
||||
return poiData.map((location) => {
|
||||
return L.marker([location.latitude, location.longitude], {
|
||||
icon: L.icon({
|
||||
iconUrl: iconPath,
|
||||
iconSize: [25, 41],
|
||||
iconAnchor: [12, 41],
|
||||
popupAnchor: [1, -34],
|
||||
draggable: true,
|
||||
}),
|
||||
id: location.idPoi,
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Funktion zum Hinzufügen von Markern zur Karte und zum Umgang mit Events
|
||||
export const addMarkersToMap = (markers, map, layerGroup) => {
|
||||
markers.forEach((marker) => {
|
||||
marker.addTo(layerGroup);
|
||||
marker.on("mouseover", () => marker.openPopup());
|
||||
marker.on("mouseout", () => marker.closePopup());
|
||||
marker.on("dragend", (e) => {
|
||||
console.log("Marker wurde verschoben in addMarkersToMap");
|
||||
const newLat = e.target.getLatLng().lat;
|
||||
const newLng = e.target.getLatLng().lng;
|
||||
const markerId = e.target.options.id;
|
||||
updateLocationInDatabase(markerId, newLat, newLng);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
// Funktion zum Aktualisieren der Standorte in der Datenbank
|
||||
export const updateLocationInDatabase = async (id, newLatitude, newLongitude) => {
|
||||
const response = await fetch("/api/talas_v5_DB/pois/updateLocation", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
id,
|
||||
latitude: newLatitude,
|
||||
longitude: newLongitude,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
console.error("Fehler beim Aktualisieren der Position");
|
||||
}
|
||||
};
|
||||
|
||||
// Weitere Funktionen können hier hinzugefügt werden
|
||||
@@ -1,22 +1,85 @@
|
||||
import { useState, useCallback } from "react";
|
||||
// /components/useMapContextMenu.js
|
||||
import { toast } from "react-toastify";
|
||||
import { zoomIn, zoomOut, centerHere } from "../utils/zoomAndCenterUtils"; // Assuming these are imported correctly
|
||||
|
||||
const useMapContextMenu = (map, hasRights, addStationCallback) => {
|
||||
const [menuItemAdded, setMenuItemAdded] = useState(false);
|
||||
const zoomInCallback = (e, map) => {
|
||||
zoomIn(e, map);
|
||||
};
|
||||
|
||||
const addItemsToMapContextMenu = useCallback(() => {
|
||||
if (map && !menuItemAdded) {
|
||||
const zoomOutCallback = (map) => {
|
||||
zoomOut(map);
|
||||
};
|
||||
|
||||
const centerHereCallback = (e, map) => {
|
||||
centerHere(e, map);
|
||||
};
|
||||
// Funktion zum Anzeigen der Koordinaten
|
||||
const showCoordinates = (e) => {
|
||||
alert("Breitengrad: " + e.latlng.lat.toFixed(5) + "\nLängengrad: " + e.latlng.lng.toFixed(5));
|
||||
};
|
||||
// Kontextmenü Callback für "POI hinzufügen"
|
||||
const addStationCallback = (event, hasRights, setShowPopup, setPopupCoordinates) => {
|
||||
const editMode = localStorage.getItem("editMode") === "true";
|
||||
hasRights = editMode ? hasRights : undefined;
|
||||
if (hasRights) {
|
||||
setPopupCoordinates(event.latlng);
|
||||
setShowPopup(true);
|
||||
} else {
|
||||
toast.error("Benutzer hat keine Berechtigung zum Hinzufügen.", {
|
||||
position: "top-center",
|
||||
autoClose: 5000,
|
||||
hideProgressBar: false,
|
||||
closeOnClick: true,
|
||||
pauseOnHover: true,
|
||||
draggable: true,
|
||||
progress: undefined,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const addItemsToMapContextMenu = (map, menuItemAdded, setMenuItemAdded, hasRights, setShowPopup, setPopupCoordinates) => {
|
||||
// Überprüfe den Bearbeitungsmodus in localStorage
|
||||
const editMode = localStorage.getItem("editMode") === "true";
|
||||
hasRights = editMode ? hasRights : undefined;
|
||||
|
||||
if (!menuItemAdded && map && map.contextmenu) {
|
||||
map.contextmenu.addItem({
|
||||
text: "Koordinaten anzeigen",
|
||||
icon: "img/not_listed_location.png",
|
||||
callback: showCoordinates,
|
||||
});
|
||||
|
||||
map.contextmenu.addItem({ separator: true });
|
||||
|
||||
map.contextmenu.addItem({
|
||||
text: "Reinzoomen",
|
||||
icon: "img/zoom_in.png",
|
||||
callback: (e) => zoomInCallback(e, map),
|
||||
});
|
||||
|
||||
map.contextmenu.addItem({
|
||||
text: "Rauszoomen",
|
||||
icon: "img/zoom_out.png",
|
||||
callback: () => zoomOutCallback(map),
|
||||
});
|
||||
|
||||
map.contextmenu.addItem({
|
||||
text: "Hier zentrieren",
|
||||
icon: "img/center_focus.png",
|
||||
callback: (e) => centerHereCallback(e, map),
|
||||
});
|
||||
|
||||
// wenn localStorage Variable editMode true ist, dann wird der Button "POI hinzufügen" angezeigt
|
||||
if (editMode) {
|
||||
map.contextmenu.addItem({ separator: true });
|
||||
map.contextmenu.addItem({
|
||||
text: "POI hinzufügen",
|
||||
icon: "img/add_station.png",
|
||||
className: "background-red",
|
||||
callback: (event) => addStationCallback(event, hasRights),
|
||||
callback: (event) => addStationCallback(event, hasRights, setShowPopup, setPopupCoordinates),
|
||||
});
|
||||
|
||||
setMenuItemAdded(true); // Menüpunkt wurde hinzugefült, Zustand aktualisieren
|
||||
}
|
||||
}, [map, menuItemAdded, hasRights, addStationCallback]);
|
||||
|
||||
return { addItemsToMapContextMenu };
|
||||
setMenuItemAdded(true);
|
||||
}
|
||||
};
|
||||
|
||||
export default useMapContextMenu;
|
||||
|
||||
@@ -1,21 +1,22 @@
|
||||
// /config/config.js
|
||||
|
||||
import * as urls from "../config/urls.js";
|
||||
// Definieren der grundlegenden Umgebungseinstellungen und Konfigurationen der Karte
|
||||
const mapVersion = "0.5.3"; // Die Version der verwendeten Karte
|
||||
const standardSideMenu = true; // Einstellung, ob ein standardmäßiges Seitenmenü verwendet wird
|
||||
const fullSideMenu = false; // Einstellung, ob ein vollständiges Seitenmenü verwendet wird
|
||||
//const serverURL = "/api"; // Die Basis-URL des Servers, von dem Daten bezogen werden
|
||||
const serverURL = "http://10.10.0.13";
|
||||
console.log("serverURL in config:", serverURL);
|
||||
//const serverURL = "http://10.10.0.13";
|
||||
//const serverURL = "http://10.10.0.70";
|
||||
const serverURL = process.env.NEXT_PUBLIC_SERVER_URL;
|
||||
if (!serverURL) {
|
||||
throw new Error("Die Umgebungsvariable NEXT_PUBLIC_SERVER_URL ist nicht gesetzt!");
|
||||
}
|
||||
console.log("%c 1- serverURL in config:", "color: #006400;", serverURL);
|
||||
|
||||
// Initialisieren von Variablen, die später im Browserkontext gesetzt werden
|
||||
let windowHeight, url_string, url, idMap, idUser;
|
||||
//Online Daten
|
||||
let mapGisStationsStaticDistrictUrl,
|
||||
mapGisStationsStatusDistrictUrl,
|
||||
mapGisStationsMeasurementsUrl,
|
||||
mapGisSystemStaticUrl,
|
||||
mapDataIconUrl,
|
||||
webserviceGisLinesStatusUrl;
|
||||
let mapGisStationsStaticDistrictUrl, mapGisStationsStatusDistrictUrl, mapGisStationsMeasurementsUrl, mapGisSystemStaticUrl, mapDataIconUrl, webserviceGisLinesStatusUrl;
|
||||
|
||||
// Prüfen, ob das Code im Browser ausgeführt wird
|
||||
if (typeof window !== "undefined") {
|
||||
@@ -23,13 +24,14 @@ if (typeof window !== "undefined") {
|
||||
windowHeight = window.innerHeight; // Die Höhe des Browserfensters
|
||||
url_string = window.location.href; // Die vollständige URL als String
|
||||
url = new URL(url_string); // Die URL als URL-Objekt, um Teile der URL einfacher zu handhaben
|
||||
console.log("URL in config:", url);
|
||||
console.log("URL origin in config:", url.origin); //http://localhost:3000
|
||||
console.log("%c 2- URL in config:", "color: #006400; font-size: 16px; background-color: #f0f0f0;", url);
|
||||
|
||||
console.log("%c 3- URL origin in config:", "color: #006400;", url.origin); //http://localhost:3000
|
||||
idMap = url.searchParams.get("m"); // Ein Parameter aus der URL, Standardwert ist '10'
|
||||
idUser = url.searchParams.get("u"); // Ein weiterer Parameter aus der URL, Standardwert ist '484 admin zu testen von Stationen ausblenden und einblenden in der Card'
|
||||
|
||||
console.log(`Parameter 'idMap' : ${idMap}`);
|
||||
console.log(`Parameter 'idUser': ${idUser}`);
|
||||
console.log(`4- Parameter 'idMap' : ${idMap}`);
|
||||
console.log(`5- Parameter 'idUser': ${idUser}`);
|
||||
|
||||
// Konstruktion von URLs, die auf spezifische Ressourcen auf dem Server zeigen
|
||||
//http://localhost:3000/?m=10&u=485
|
||||
@@ -45,8 +47,9 @@ if (typeof window !== "undefined") {
|
||||
//webserviceGisLinesStatusUrl = `http://localhost:3000/api/linesColorApi`;
|
||||
//webserviceGisLinesStatusUrl = `http://localhost:3000/api/linesColorApi`;
|
||||
//webserviceGisLinesStatusUrl = `${"serverURL"}:3000/api/linesColorApi`;
|
||||
webserviceGisLinesStatusUrl = `http://localhost:3000/api/linesColorApi`;
|
||||
// webserviceGisLinesStatusUrl = `http://localhost:3000/api/linesColorApi`;
|
||||
//webserviceGisLinesStatusUrl = `http://192.168.10.14/talas5/ClientData/WebServiceMap.asmx/GisLinesStatus?idMap=${idMap}`;
|
||||
webserviceGisLinesStatusUrl = `${serverURL}/talas5/ClientData/WebServiceMap.asmx/GisLinesStatus?idMap=${idMap}`;
|
||||
|
||||
//http://10.10.0.13/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic?idMap=12&idUser=484
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// /config/settings.js
|
||||
// Definieren der grundlegenden Umgebungseinstellungen und Konfigurationen der Karte
|
||||
export const MAP_VERSION = "1.0.0";
|
||||
export const MAP_VERSION = "1.0.3";
|
||||
//export const STANDARD_SIDE_MENU = true;
|
||||
//export const FULL_SIDE_MENU = false;
|
||||
|
||||
@@ -1,23 +1,32 @@
|
||||
// /sonstige/urls.js
|
||||
// /config/urls.js
|
||||
|
||||
// BASE_URL für Station öffnen in neuer tab und gleicher tab, im localhost gab es keine Probleme mit der Frame
|
||||
//export const BASE_URL = "http://10.10.0.13/talas5/devices/";
|
||||
//const baseUrl = "http://localhost:3000/talas5/devices/";
|
||||
//const baseUrl = "http://192.168.10.14/talas5/devices/";
|
||||
//----
|
||||
//Talas_v5 Server
|
||||
//export const OFFLINE_TILE_LAYER = "/mapTiles/{z}/{x}/{y}.png"; // wenn im von localhost also selben Server die Karte angezeigt wird
|
||||
//export const OFFLINE_TILE_LAYER = "/mapTiles/{z}/{x}/{y}.png";
|
||||
export const BASE_URL = "http://10.10.0.13/talas5/devices/";
|
||||
export const OFFLINE_TILE_LAYER = "/mapTiles/{z}/{x}/{y}.png";
|
||||
export const ONLINE_TILE_LAYER =
|
||||
"http://10.10.0.13:3000/mapTiles/{z}/{x}/{y}.png"; //Talas_v5 Server */
|
||||
export const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL; //Station in Tab öffnen
|
||||
export const SERVER_URL = process.env.NEXT_PUBLIC_SERVER_URL; //Die Konstante ist in MapComponent.js und useLineData.js verwendet
|
||||
export const PROXY_TARGET = process.env.NEXT_PUBLIC_PROXY_TARGET; // damit nodejs auf Port 3000 auf dem Server Talas5 auf Port 80 aufgerufen kann, ansonsten gibt CORS Fehler
|
||||
export const ONLINE_TILE_LAYER = process.env.NEXT_PUBLIC_ONLINE_TILE_LAYER; //Map von Talas_v5 Server
|
||||
//-----------------------------------
|
||||
//export const ONLINE_TILE_LAYER = "http://10.10.0.13:3000/mapTiles/{z}/{x}/{y}.png"; //Map von Talas_v5 Server
|
||||
// export const PROXY_TARGET = "http://10.10.0.70"; // damit nodejs auf Port 3000 auf dem Server Talas5 auf Port 80 aufgerufen kann, ansonsten gibt CORS Fehler
|
||||
// export const SERVER_URL = "http://10.10.0.70"; //Die Konstante ist in MapComponent.js und useLineData.js verwendet
|
||||
// export const BASE_URL = "http://10.10.0.70/talas5/devices/"; //Station in Tab öffnen
|
||||
// //-----------------------------------
|
||||
/* export const ONLINE_TILE_LAYER = "http://192.168.10.14:3000/mapTiles/{z}/{x}/{y}.png"; //Map von Talas_v5 Server
|
||||
export const PROXY_TARGET = "http://192.168.10.167"; // damit nodejs auf Port 3000 auf dem Server Talas5 auf Port 80 aufgerufen kann, ansonsten gibt CORS Fehler
|
||||
export const SERVER_URL = "http://192.168.10.167"; //Die Konstante ist in MapComponent.js und useLineData.js verwendet
|
||||
export const BASE_URL = "http://192.168.10.167/talas5/devices/"; //Station in Tab öffnen */
|
||||
//-----------------------------------
|
||||
// export const ONLINE_TILE_LAYER = "http://192.168.10.14:3000/mapTiles/{z}/{x}/{y}.png"; //Map von Talas_v5 Server */
|
||||
// export const PROXY_TARGET = "http://localhost"; // damit nodejs auf Port 3000 auf dem Server Talas5 auf Port 80 aufgerufen kann, ansonsten gibt CORS Fehler
|
||||
// export const SERVER_URL = "http://localhost"; //in MapComponent.js wird es verwendet
|
||||
// export const BASE_URL = "http://localhost/talas5/devices/"; //Station in Tab öffnen
|
||||
//-----------------------------------
|
||||
//-----------------------------------
|
||||
// weil ich keine API habe, ansonsten serverURL ist localhost(IP-Adresse) für GisSystemStatic für die Benutzerrechte
|
||||
//const serverURL = `${protocol}//${hostname}`;
|
||||
//const serverURL = `${protocol}//${hostname}${port ? `:${port}` : ""}`;
|
||||
//const serverURL = "http://localhost:3000";
|
||||
export const SERVER_URL = "http://10.10.0.13";
|
||||
//export const SERVER_URL = "http://10.10.0.13";
|
||||
//export const SERVER_URL = "http://10.10.0.70";
|
||||
|
||||
// Online Daten URLs
|
||||
/* export const MAP_GIS_STATIONS_STATIC_DISTRICT_URL = `${SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisStationsStaticDistrict?idMap=${c}&idUser=${user}`; //idMap: 10, idUser: 484
|
||||
|
||||
16
cypress.config.js
Normal file
16
cypress.config.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const { defineConfig } = require("cypress");
|
||||
|
||||
module.exports = defineConfig({
|
||||
e2e: {
|
||||
setupNodeEvents(on, config) {
|
||||
// implement node event listeners here
|
||||
},
|
||||
},
|
||||
|
||||
component: {
|
||||
devServer: {
|
||||
framework: "next",
|
||||
bundler: "webpack",
|
||||
},
|
||||
},
|
||||
});
|
||||
46
cypress/e2e/spec.cy.js
Normal file
46
cypress/e2e/spec.cy.js
Normal file
@@ -0,0 +1,46 @@
|
||||
describe("Map Initial Load Test", () => {
|
||||
it("should load the map with the correct center and zoom", () => {
|
||||
// Besuche die Seite, auf der die Karte angezeigt wird
|
||||
cy.visit("http://192.168.10.167:3000/?m=12&u=485");
|
||||
|
||||
// Überprüfe, ob das Kartenelement existiert
|
||||
cy.get("#map").should("be.visible");
|
||||
|
||||
// Überprüfe, ob die Karte das korrekte Zentrum und den korrekten Zoom hat
|
||||
cy.window().then((win) => {
|
||||
const map = win.L.map;
|
||||
const center = map.getCenter();
|
||||
const zoom = map.getZoom();
|
||||
|
||||
expect(center.lat).to.be.closeTo(53.111111, 0.0001);
|
||||
expect(center.lng).to.be.closeTo(8.4625, 0.0001);
|
||||
expect(zoom).to.eq(12);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe("Map Context Menu Test", () => {
|
||||
it("should show context menu on right click", () => {
|
||||
cy.visit("http://192.168.10.167:3000/?m=12&u=485");
|
||||
|
||||
// Rechte Maustaste auf eine Koordinate in der Karte klicken
|
||||
cy.get("#map").rightclick(400, 300); // Rechtsklick auf eine Position in der Karte
|
||||
|
||||
// Überprüfen, ob das Kontextmenü angezeigt wird
|
||||
cy.contains("Station öffnen (Tab)").should("be.visible");
|
||||
});
|
||||
|
||||
it("should open a new tab when context menu option is clicked", () => {
|
||||
cy.visit("http://192.168.10.167:3000/?m=12&u=485");
|
||||
|
||||
cy.get("#map").rightclick(400, 300);
|
||||
|
||||
cy.contains("Station öffnen (Tab)").click();
|
||||
|
||||
// Testen, ob ein neuer Tab mit dem richtigen Link geöffnet wird
|
||||
cy.window().then((win) => {
|
||||
cy.stub(win, "open").as("windowOpen");
|
||||
});
|
||||
|
||||
cy.get("@windowOpen").should("be.calledWith", "https://example.com"); // Ersetze dies durch die tatsächliche URL
|
||||
});
|
||||
});
|
||||
5
cypress/fixtures/example.json
Normal file
5
cypress/fixtures/example.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "Using fixtures to represent data",
|
||||
"email": "hello@cypress.io",
|
||||
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||
}
|
||||
20
cypress/integration/map_test_spec.js
Normal file
20
cypress/integration/map_test_spec.js
Normal file
@@ -0,0 +1,20 @@
|
||||
describe("Map Initial Load Test", () => {
|
||||
it("should load the map with the correct center and zoom", () => {
|
||||
// Besuche die Seite, auf der die Karte angezeigt wird
|
||||
cy.visit("http://192.168.10.167:3000/?m=12&u=485");
|
||||
|
||||
// Überprüfe, ob das Kartenelement existiert
|
||||
cy.get("#map").should("be.visible");
|
||||
|
||||
// Überprüfe, ob die Karte das korrekte Zentrum und den korrekten Zoom hat
|
||||
cy.window().then((win) => {
|
||||
const map = win.L.map;
|
||||
const center = map.getCenter();
|
||||
const zoom = map.getZoom();
|
||||
|
||||
expect(center.lat).to.be.closeTo(53.111111, 0.0001);
|
||||
expect(center.lng).to.be.closeTo(8.4625, 0.0001);
|
||||
expect(zoom).to.eq(12);
|
||||
});
|
||||
});
|
||||
});
|
||||
25
cypress/support/commands.js
Normal file
25
cypress/support/commands.js
Normal file
@@ -0,0 +1,25 @@
|
||||
// ***********************************************
|
||||
// This example commands.js shows you how to
|
||||
// create various custom commands and overwrite
|
||||
// existing commands.
|
||||
//
|
||||
// For more comprehensive examples of custom
|
||||
// commands please read more here:
|
||||
// https://on.cypress.io/custom-commands
|
||||
// ***********************************************
|
||||
//
|
||||
//
|
||||
// -- This is a parent command --
|
||||
// Cypress.Commands.add('login', (email, password) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a child command --
|
||||
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This is a dual command --
|
||||
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||
//
|
||||
//
|
||||
// -- This will overwrite an existing command --
|
||||
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
|
||||
14
cypress/support/component-index.html
Normal file
14
cypress/support/component-index.html
Normal file
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>Components App</title>
|
||||
<!-- Used by Next.js to inject CSS. -->
|
||||
<div id="__next_css__DO_NOT_USE__"></div>
|
||||
</head>
|
||||
<body>
|
||||
<div data-cy-root></div>
|
||||
</body>
|
||||
</html>
|
||||
27
cypress/support/component.js
Normal file
27
cypress/support/component.js
Normal file
@@ -0,0 +1,27 @@
|
||||
// ***********************************************************
|
||||
// This example support/component.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
|
||||
import { mount } from 'cypress/react18'
|
||||
|
||||
Cypress.Commands.add('mount', mount)
|
||||
|
||||
// Example use:
|
||||
// cy.mount(<MyComponent />)
|
||||
20
cypress/support/e2e.js
Normal file
20
cypress/support/e2e.js
Normal file
@@ -0,0 +1,20 @@
|
||||
// ***********************************************************
|
||||
// This example support/e2e.js is processed and
|
||||
// loaded automatically before your test files.
|
||||
//
|
||||
// This is a great place to put global configuration and
|
||||
// behavior that modifies Cypress.
|
||||
//
|
||||
// You can change the location of this file or turn off
|
||||
// automatically serving support files with the
|
||||
// 'supportFile' configuration option.
|
||||
//
|
||||
// You can read more here:
|
||||
// https://on.cypress.io/configuration
|
||||
// ***********************************************************
|
||||
|
||||
// Import commands.js using ES2015 syntax:
|
||||
import './commands'
|
||||
|
||||
// Alternatively you can use CommonJS syntax:
|
||||
// require('./commands')
|
||||
49
hooks/layers/useCiscoRouterMarkersLayer.js
Normal file
49
hooks/layers/useCiscoRouterMarkersLayer.js
Normal file
@@ -0,0 +1,49 @@
|
||||
// hooks/useCiscoRouterMarkersLayer.js
|
||||
import { useEffect, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import { createAndSetDevices } from "../../utils/createAndSetDevices";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
import { checkOverlappingMarkers } from "../../utils/mapUtils";
|
||||
|
||||
const useCiscoRouterMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
|
||||
const [ciscoRouterMarkers, setCiscoRouterMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (GisSystemStatic && GisSystemStatic.length && map) {
|
||||
createAndSetDevices(6, setCiscoRouterMarkers, GisSystemStatic, priorityConfig); // Cisco Router
|
||||
}
|
||||
}, [GisSystemStatic, map, priorityConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && ciscoRouterMarkers.length) {
|
||||
ciscoRouterMarkers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
|
||||
// Popup on mouseover and mouseout
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
});
|
||||
|
||||
// Disable map context menu
|
||||
map.options.contextmenu = false;
|
||||
map.options.contextmenuItems = [];
|
||||
|
||||
oms.map.options.contextmenu = false;
|
||||
oms.map.options.contextmenuItems = [];
|
||||
|
||||
// Call the function to check for overlapping markers
|
||||
checkOverlappingMarkers(oms, map);
|
||||
}
|
||||
}, [map, ciscoRouterMarkers]);
|
||||
|
||||
return ciscoRouterMarkers;
|
||||
};
|
||||
|
||||
export default useCiscoRouterMarkersLayer;
|
||||
45
hooks/layers/useDauzMarkersLayer.js
Normal file
45
hooks/layers/useDauzMarkersLayer.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// hooks/useDauzMarkersLayer.js
|
||||
import { useEffect, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
import { createAndSetDevices } from "../../utils/createAndSetDevices";
|
||||
|
||||
const useDauzMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
|
||||
const [dauzMarkers, setDauzMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (GisSystemStatic && GisSystemStatic.length && map) {
|
||||
createAndSetDevices(110, setDauzMarkers, GisSystemStatic, priorityConfig); // DAUZ
|
||||
}
|
||||
}, [GisSystemStatic, map, priorityConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && dauzMarkers.length) {
|
||||
dauzMarkers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
|
||||
// Popup on mouseover and mouseout
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
});
|
||||
|
||||
// Disable map context menu
|
||||
map.options.contextmenu = false;
|
||||
map.options.contextmenuItems = [];
|
||||
|
||||
oms.map.options.contextmenu = false;
|
||||
oms.map.options.contextmenuItems = [];
|
||||
}
|
||||
}, [map, dauzMarkers, oms]);
|
||||
|
||||
return dauzMarkers;
|
||||
};
|
||||
|
||||
export default useDauzMarkersLayer;
|
||||
48
hooks/layers/useEciMarkersLayer.js
Normal file
48
hooks/layers/useEciMarkersLayer.js
Normal file
@@ -0,0 +1,48 @@
|
||||
// /hooks/layers/useEciMarkersLayer.js
|
||||
import { useEffect, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import { createAndSetDevices } from "../../utils/createAndSetDevices";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
import { checkOverlappingMarkers } from "../../utils/mapUtils";
|
||||
|
||||
const useEciMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
|
||||
const [eciMarkers, setEciMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (GisSystemStatic && GisSystemStatic.length && map) {
|
||||
createAndSetDevices(2, setEciMarkers, GisSystemStatic, priorityConfig); // ECI-System
|
||||
}
|
||||
}, [GisSystemStatic, map, priorityConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && eciMarkers.length) {
|
||||
eciMarkers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
|
||||
// Popup beim Überfahren mit der Maus öffnen und schließen
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
});
|
||||
// Disable map context menu
|
||||
map.options.contextmenu = false;
|
||||
map.options.contextmenuItems = [];
|
||||
|
||||
oms.map.options.contextmenu = false;
|
||||
oms.map.options.contextmenuItems = [];
|
||||
|
||||
// Call the function to check for overlapping markers
|
||||
checkOverlappingMarkers(oms, map);
|
||||
}
|
||||
}, [map, eciMarkers]);
|
||||
|
||||
return eciMarkers;
|
||||
};
|
||||
|
||||
export default useEciMarkersLayer;
|
||||
81
hooks/layers/useGmaMarkersLayer.js
Normal file
81
hooks/layers/useGmaMarkersLayer.js
Normal file
@@ -0,0 +1,81 @@
|
||||
import { useEffect } from "react";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
|
||||
const useMarkersLayer = (map, markers, GisStationsMeasurements, GMA, oms) => {
|
||||
useEffect(() => {
|
||||
if (!map) return;
|
||||
|
||||
// Entferne alte Marker
|
||||
GMA.clearLayers();
|
||||
|
||||
// Hinzufügen neuer Marker
|
||||
markers.forEach((marker) => {
|
||||
// Finde die Messungen, die zu diesem Marker gehören
|
||||
const relevantMeasurements = GisStationsMeasurements.filter((m) => m.Area_Name === marker.options.areaName);
|
||||
|
||||
let measurements = {};
|
||||
let area_name = marker.options.areaName;
|
||||
let idLD = marker.options.idLD;
|
||||
|
||||
relevantMeasurements.forEach((m) => {
|
||||
measurements[m.Na] = m.Val;
|
||||
});
|
||||
|
||||
// Überprüfe, ob die Messwerte vorhanden sind, und setze Standardwerte
|
||||
const lt = measurements["LT"] || "---";
|
||||
const fbt = measurements["FBT"] || "---";
|
||||
const gt = measurements["GT"] || "---";
|
||||
const rlf = measurements["RLF"] || "---";
|
||||
|
||||
console.log(`Station oder Bereich ${area_name} - LT: ${lt}, FBT: ${fbt}, GT: ${gt}, RLF: ${rlf}`);
|
||||
console.log(`Station idLD: ${idLD} `);
|
||||
|
||||
// Tooltip für den Marker binden
|
||||
marker.bindTooltip(
|
||||
`
|
||||
<div class="p-0 rounded-lg bg-white bg-opacity-90">
|
||||
<div class="font-bold text-sm text-black">
|
||||
<span>${area_name}</span>
|
||||
</div>
|
||||
<div class="font-bold text-xxs text-blue-700">
|
||||
<span>LT : ${lt} °C</span>
|
||||
</div>
|
||||
<div class="font-bold text-xxs text-red-700">
|
||||
<span>FBT : ${fbt} °C</span>
|
||||
</div>
|
||||
<div class="font-bold text-xxs text-yellow-500">
|
||||
<span>GT : ${gt}</span>
|
||||
</div>
|
||||
<div class="font-bold text-xxs text-green-700">
|
||||
<span>RLF : ${rlf} %</span>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
{
|
||||
permanent: true,
|
||||
direction: "auto",
|
||||
offset: [60, 0],
|
||||
}
|
||||
);
|
||||
|
||||
// Ereignisse für das Öffnen und Schließen des Tooltips
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
// Kontextmenü hinzufügen
|
||||
addContextMenuToMarker(marker);
|
||||
|
||||
// Füge den Marker zur Layer-Gruppe hinzu
|
||||
GMA.addLayer(marker);
|
||||
oms.addMarker(marker);
|
||||
});
|
||||
|
||||
map.addLayer(GMA);
|
||||
}, [map, markers, GisStationsMeasurements, GMA, oms]);
|
||||
};
|
||||
|
||||
export default useMarkersLayer;
|
||||
47
hooks/layers/useGsmModemMarkersLayer.js
Normal file
47
hooks/layers/useGsmModemMarkersLayer.js
Normal file
@@ -0,0 +1,47 @@
|
||||
// hooks/useGsmModemMarkersLayer.js
|
||||
import { useEffect, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import { createAndSetDevices } from "../../utils/createAndSetDevices";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
import { checkOverlappingMarkers } from "../../utils/mapUtils";
|
||||
|
||||
const useGsmModemMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
|
||||
const [gsmModemMarkers, setGsmModemMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (GisSystemStatic && GisSystemStatic.length && map) {
|
||||
createAndSetDevices(5, setGsmModemMarkers, GisSystemStatic, priorityConfig); // GSM-Modem
|
||||
}
|
||||
}, [GisSystemStatic, map, priorityConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && gsmModemMarkers.length) {
|
||||
gsmModemMarkers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
|
||||
// Popup beim Überfahren mit der Maus öffnen und schließen
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
});
|
||||
// Disable map context menu
|
||||
map.options.contextmenu = false;
|
||||
map.options.contextmenuItems = [];
|
||||
|
||||
oms.map.options.contextmenu = false;
|
||||
oms.map.options.contextmenuItems = [];
|
||||
|
||||
// Call the function to check for overlapping markers
|
||||
checkOverlappingMarkers(oms, map);
|
||||
}
|
||||
}, [map, gsmModemMarkers]);
|
||||
|
||||
return gsmModemMarkers;
|
||||
};
|
||||
export default useGsmModemMarkersLayer;
|
||||
49
hooks/layers/useLteModemMarkersLayer.js
Normal file
49
hooks/layers/useLteModemMarkersLayer.js
Normal file
@@ -0,0 +1,49 @@
|
||||
// hooks/useLteModemMarkersLayer.js
|
||||
import { useEffect, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import { createAndSetDevices } from "../../utils/createAndSetDevices";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
import { checkOverlappingMarkers } from "../../utils/mapUtils";
|
||||
|
||||
const useLteModemMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
|
||||
const [lteModemMarkers, setLteModemMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (GisSystemStatic && GisSystemStatic.length && map) {
|
||||
createAndSetDevices(10, setLteModemMarkers, GisSystemStatic, priorityConfig); // LTE Modems
|
||||
}
|
||||
}, [GisSystemStatic, map, priorityConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && lteModemMarkers.length) {
|
||||
lteModemMarkers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
|
||||
// Popup on mouseover and mouseout
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
});
|
||||
|
||||
// Disable map context menu
|
||||
map.options.contextmenu = false;
|
||||
map.options.contextmenuItems = [];
|
||||
|
||||
oms.map.options.contextmenu = false;
|
||||
oms.map.options.contextmenuItems = [];
|
||||
|
||||
// Call the function to check for overlapping markers
|
||||
checkOverlappingMarkers(oms, map);
|
||||
}
|
||||
}, [map, lteModemMarkers]);
|
||||
|
||||
return lteModemMarkers;
|
||||
};
|
||||
|
||||
export default useLteModemMarkersLayer;
|
||||
38
hooks/layers/useMessstellenMarkersLayer.js
Normal file
38
hooks/layers/useMessstellenMarkersLayer.js
Normal file
@@ -0,0 +1,38 @@
|
||||
// /hooks/layers/useMessstellenMarkersLayer.js
|
||||
import { useEffect, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
import { createAndSetDevices } from "../../utils/createAndSetDevices";
|
||||
|
||||
const useMessstellenMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
|
||||
const [messstellenMarkers, setMessstellenMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (GisSystemStatic && GisSystemStatic.length && map) {
|
||||
createAndSetDevices(13, setMessstellenMarkers, GisSystemStatic, priorityConfig); // Messstellen
|
||||
}
|
||||
}, [GisSystemStatic, map, priorityConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && messstellenMarkers.length) {
|
||||
messstellenMarkers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
|
||||
// Popup on mouseover and mouseout
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
});
|
||||
}
|
||||
}, [map, messstellenMarkers, oms]);
|
||||
|
||||
return messstellenMarkers;
|
||||
};
|
||||
|
||||
export default useMessstellenMarkersLayer;
|
||||
45
hooks/layers/useOtdrMarkersLayer.js
Normal file
45
hooks/layers/useOtdrMarkersLayer.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// hooks/useOtdrMarkersLayer.js
|
||||
import { useEffect, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
import { createAndSetDevices } from "../../utils/createAndSetDevices"; // Assuming this function is in poiUtils
|
||||
|
||||
const useOtdrMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
|
||||
const [otdrMarkers, setOtdrMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (GisSystemStatic && GisSystemStatic.length && map) {
|
||||
createAndSetDevices(9, setOtdrMarkers, GisSystemStatic, priorityConfig); // OTDR
|
||||
}
|
||||
}, [GisSystemStatic, map, priorityConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && otdrMarkers.length) {
|
||||
otdrMarkers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
|
||||
// Popup on mouseover and mouseout
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
});
|
||||
|
||||
// Disable map context menu
|
||||
map.options.contextmenu = false;
|
||||
map.options.contextmenuItems = [];
|
||||
|
||||
oms.map.options.contextmenu = false;
|
||||
oms.map.options.contextmenuItems = [];
|
||||
}
|
||||
}, [map, otdrMarkers, oms]);
|
||||
|
||||
return otdrMarkers;
|
||||
};
|
||||
|
||||
export default useOtdrMarkersLayer;
|
||||
49
hooks/layers/useSiemensMarkersLayer.js
Normal file
49
hooks/layers/useSiemensMarkersLayer.js
Normal file
@@ -0,0 +1,49 @@
|
||||
// hooks/useSiemensMarkersLayer.js
|
||||
import { useState, useEffect } from "react";
|
||||
import L from "leaflet";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
import { createAndSetDevices } from "../../utils/createAndSetDevices";
|
||||
import { checkOverlappingMarkers } from "../../utils/mapUtils";
|
||||
|
||||
const useSiemensMarkersLayer = (map, oms, gisSystemStatic, priorityConfig) => {
|
||||
const [siemensMarkers, setSiemensMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (gisSystemStatic && gisSystemStatic.length && map) {
|
||||
createAndSetDevices(8, setSiemensMarkers, gisSystemStatic, priorityConfig); // Siemens-System
|
||||
}
|
||||
}, [gisSystemStatic, map, priorityConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && siemensMarkers.length) {
|
||||
siemensMarkers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
|
||||
// Popup on mouseover and mouseout
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
});
|
||||
|
||||
// Disable map context menu
|
||||
map.options.contextmenu = false;
|
||||
map.options.contextmenuItems = [];
|
||||
|
||||
oms.map.options.contextmenu = false;
|
||||
oms.map.options.contextmenuItems = [];
|
||||
|
||||
// Call the function to check for overlapping markers
|
||||
checkOverlappingMarkers(oms, map);
|
||||
}
|
||||
}, [map, siemensMarkers, oms]);
|
||||
|
||||
return siemensMarkers;
|
||||
};
|
||||
|
||||
export default useSiemensMarkersLayer;
|
||||
54
hooks/layers/useSmsfunkmodemMarkersLayer.js
Normal file
54
hooks/layers/useSmsfunkmodemMarkersLayer.js
Normal file
@@ -0,0 +1,54 @@
|
||||
// hooks/useSmsfunkmodemMarkersLayer.js
|
||||
import { useEffect, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import "leaflet-contextmenu";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
|
||||
const useSmsfunkmodemMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
|
||||
const [smsfunkmodemMarkers, setSmsfunkmodemMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && GisSystemStatic) {
|
||||
const markers = GisSystemStatic.filter((station) => station.System === 111).map((station) => {
|
||||
const marker = L.marker([station.Latitude, station.Longitude], {
|
||||
icon: L.icon({
|
||||
iconUrl: "/img/icons/pois/sms-funkmodem.png",
|
||||
iconSize: [25, 41],
|
||||
iconAnchor: [12, 41],
|
||||
popupAnchor: [1, -34],
|
||||
}),
|
||||
id: station.id,
|
||||
areaName: station.Area_Name,
|
||||
draggable: false,
|
||||
}).bindPopup(`
|
||||
<div>
|
||||
<b class="text-xl text-black-700">${station.Area_Name || "Unbekannt"}</b><br>
|
||||
${station.Description || "No Description"}<br>
|
||||
</div>
|
||||
`);
|
||||
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
|
||||
return marker;
|
||||
});
|
||||
|
||||
setSmsfunkmodemMarkers(markers);
|
||||
markers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
});
|
||||
}
|
||||
}, [map, GisSystemStatic, priorityConfig]);
|
||||
|
||||
return smsfunkmodemMarkers;
|
||||
};
|
||||
|
||||
export default useSmsfunkmodemMarkersLayer;
|
||||
45
hooks/layers/useSonstigeMarkersLayer.js
Normal file
45
hooks/layers/useSonstigeMarkersLayer.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// hooks/useSonstigeMarkersLayer.js
|
||||
import { useEffect, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
import { createAndSetDevices } from "../../utils/createAndSetDevices";
|
||||
|
||||
const useSonstigeMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
|
||||
const [sonstigeMarkers, setSonstigeMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (GisSystemStatic && GisSystemStatic.length && map) {
|
||||
createAndSetDevices(200, setSonstigeMarkers, GisSystemStatic, priorityConfig); // Sonstige
|
||||
}
|
||||
}, [GisSystemStatic, map, priorityConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && sonstigeMarkers.length) {
|
||||
sonstigeMarkers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
|
||||
// Popup on mouseover and mouseout
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
});
|
||||
|
||||
// Disable map context menu
|
||||
map.options.contextmenu = false;
|
||||
map.options.contextmenuItems = [];
|
||||
|
||||
oms.map.options.contextmenu = false;
|
||||
oms.map.options.contextmenuItems = [];
|
||||
}
|
||||
}, [map, sonstigeMarkers, oms]);
|
||||
|
||||
return sonstigeMarkers;
|
||||
};
|
||||
|
||||
export default useSonstigeMarkersLayer;
|
||||
102
hooks/layers/useTalasMarkers.js
Normal file
102
hooks/layers/useTalasMarkers.js
Normal file
@@ -0,0 +1,102 @@
|
||||
// /hooks/useTalasMarkers.js
|
||||
import { useEffect, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import "leaflet-contextmenu";
|
||||
import { useRecoilValue } from "recoil";
|
||||
import { mapLayersState } from "../../store/atoms/mapLayersState.js";
|
||||
import { selectedAreaState } from "../../store/atoms/selectedAreaState.js";
|
||||
import { zoomTriggerState } from "../../store/atoms/zoomTriggerState.js";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker.js";
|
||||
import { checkOverlappingMarkers } from "../../utils/mapUtils.js";
|
||||
import plusRoundIcon from "../../components/PlusRoundIcon.js";
|
||||
import { gisStationsStaticDistrictState } from "../../store/atoms/gisStationState.js";
|
||||
|
||||
const useTalasMarkers = (map, oms, layers, priorityConfig) => {
|
||||
const [talasMarkers, setTalasMarkers] = useState([]);
|
||||
const mapLayersVisibility = useRecoilValue(mapLayersState);
|
||||
const selectedArea = useRecoilValue(selectedAreaState);
|
||||
const zoomTrigger = useRecoilValue(zoomTriggerState);
|
||||
const GisStationsStaticDistrict = useRecoilValue(gisStationsStaticDistrictState);
|
||||
|
||||
// Funktion zum Erstellen und Setzen der Marker
|
||||
const createAndSetDevices = (systemId, setMarkers, GisSystemStatic, priorityConfig) => {
|
||||
const markers = GisSystemStatic.filter((station) => station.System === systemId).map((station) => {
|
||||
const marker = L.marker([station.Latitude, station.Longitude], {
|
||||
title: station.Name,
|
||||
contextmenu: true,
|
||||
contextmenuItems: [],
|
||||
});
|
||||
|
||||
marker.bindPopup(`<b>${station.Name}</b><br>${station.Description}`);
|
||||
|
||||
if (priorityConfig.includes(station.Priority)) {
|
||||
marker.setIcon(
|
||||
L.icon({
|
||||
iconUrl: `/icons/priority_${station.Priority}.png`,
|
||||
iconSize: [25, 41],
|
||||
iconAnchor: [12, 41],
|
||||
popupAnchor: [1, -34],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return marker;
|
||||
});
|
||||
|
||||
setMarkers(markers);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (map && talasMarkers.length) {
|
||||
talasMarkers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
});
|
||||
|
||||
map.addLayer(layers.TALAS);
|
||||
checkOverlappingMarkers(oms, map, plusRoundIcon);
|
||||
}
|
||||
}, [map, talasMarkers]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!map || !talasMarkers) return;
|
||||
|
||||
const toggleLayer = (isVisible) => {
|
||||
if (isVisible) {
|
||||
talasMarkers.forEach((marker) => marker.addTo(map));
|
||||
} else {
|
||||
talasMarkers.forEach((marker) => map.removeLayer(marker));
|
||||
}
|
||||
};
|
||||
|
||||
toggleLayer(mapLayersVisibility.TALAS);
|
||||
}, [map, talasMarkers, mapLayersVisibility.TALAS]);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedArea && map) {
|
||||
const station = GisStationsStaticDistrict.find((s) => s.Area_Name === selectedArea);
|
||||
if (station) {
|
||||
map.flyTo([station.X, station.Y], 14);
|
||||
}
|
||||
}
|
||||
}, [selectedArea, map, GisStationsStaticDistrict]);
|
||||
|
||||
useEffect(() => {
|
||||
if (zoomTrigger && map) {
|
||||
map.flyTo([51.41321407879154, 7.739617925303934], 7);
|
||||
}
|
||||
}, [zoomTrigger, map]);
|
||||
|
||||
return [talasMarkers, setTalasMarkers, createAndSetDevices];
|
||||
};
|
||||
|
||||
export default useTalasMarkers;
|
||||
35
hooks/layers/useTalasMarkersLayer.js
Normal file
35
hooks/layers/useTalasMarkersLayer.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { createAndSetDevices } from "../../utils/createAndSetDevices";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
|
||||
const useTalasMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
|
||||
const [talasMarkers, setTalasMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (GisSystemStatic && GisSystemStatic.length && map) {
|
||||
createAndSetDevices(1, setTalasMarkers, GisSystemStatic, priorityConfig); // TALAS-System
|
||||
}
|
||||
}, [GisSystemStatic, map, priorityConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && talasMarkers.length && oms) {
|
||||
talasMarkers.forEach((marker) => {
|
||||
oms.addMarker(marker); // Erst zu OMS hinzufügen
|
||||
marker.addTo(map); // Dann zum Map hinzufügen
|
||||
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker); // Kontextmenü-Event hinzufügen
|
||||
});
|
||||
}
|
||||
}, [map, talasMarkers, oms]);
|
||||
|
||||
return talasMarkers;
|
||||
};
|
||||
|
||||
export default useTalasMarkersLayer;
|
||||
45
hooks/layers/useTalasiclMarkersLayer.js
Normal file
45
hooks/layers/useTalasiclMarkersLayer.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// hooks/useTalasiclMarkersLayer.js
|
||||
import { useEffect, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
import { createAndSetDevices } from "../../utils/createAndSetDevices";
|
||||
|
||||
const useTalasiclMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
|
||||
const [talasiclMarkers, setTalasiclMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (GisSystemStatic && GisSystemStatic.length && map) {
|
||||
createAndSetDevices(100, setTalasiclMarkers, GisSystemStatic, priorityConfig); // TALASICL
|
||||
}
|
||||
}, [GisSystemStatic, map, priorityConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && talasiclMarkers.length) {
|
||||
talasiclMarkers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
|
||||
// Popup on mouseover and mouseout
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
});
|
||||
|
||||
// Disable map context menu
|
||||
map.options.contextmenu = false;
|
||||
map.options.contextmenuItems = [];
|
||||
|
||||
oms.map.options.contextmenu = false;
|
||||
oms.map.options.contextmenuItems = [];
|
||||
}
|
||||
}, [map, talasiclMarkers, oms]);
|
||||
|
||||
return talasiclMarkers;
|
||||
};
|
||||
|
||||
export default useTalasiclMarkersLayer;
|
||||
76
hooks/layers/useUlafMarkersLayer.js
Normal file
76
hooks/layers/useUlafMarkersLayer.js
Normal file
@@ -0,0 +1,76 @@
|
||||
// hooks/useUlafMarkersLayer.js
|
||||
import { useEffect, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
//import { fetchDeviceNameById } from "../services/apiService";
|
||||
|
||||
const useUlafMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
|
||||
const [ulafMarkers, setUlafMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!map || !GisSystemStatic) return;
|
||||
|
||||
const markers = [];
|
||||
GisSystemStatic.forEach((station) => {
|
||||
if (station.System === 0) {
|
||||
// Adjust the condition to match ULAF system identification
|
||||
const marker = L.marker([station.Lat, station.Lon], {
|
||||
icon: L.icon({
|
||||
iconUrl: "/img/icons/ulaf.png",
|
||||
iconSize: [25, 41],
|
||||
iconAnchor: [12, 41],
|
||||
popupAnchor: [1, -34],
|
||||
}),
|
||||
id: station.id,
|
||||
name: station.name,
|
||||
description: station.description,
|
||||
});
|
||||
|
||||
marker.bindPopup(`
|
||||
<div>
|
||||
<b class="text-xl text-black-700">${station.name || "Unbekannt"}</b><br>
|
||||
${station.description || "Keine Beschreibung"}
|
||||
</div>
|
||||
`);
|
||||
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
marker.on("click", async () => {
|
||||
//const deviceName = await fetchDeviceNameById(station.idLD);
|
||||
marker
|
||||
.bindPopup(
|
||||
`
|
||||
<div>
|
||||
<b class="text-xl text-black-700">${station.name || "Unbekannt"}</b><br>
|
||||
${deviceName}<br>
|
||||
${station.description || "Keine Beschreibung"}
|
||||
</div>
|
||||
`
|
||||
)
|
||||
.openPopup();
|
||||
});
|
||||
|
||||
markers.push(marker);
|
||||
if (map) marker.addTo(map);
|
||||
if (oms) oms.addMarker(marker);
|
||||
addContextMenuToMarker(marker);
|
||||
}
|
||||
});
|
||||
|
||||
setUlafMarkers(markers);
|
||||
|
||||
return () => {
|
||||
markers.forEach((marker) => map.removeLayer(marker));
|
||||
};
|
||||
}, [map, GisSystemStatic, oms, priorityConfig]);
|
||||
|
||||
return ulafMarkers;
|
||||
};
|
||||
|
||||
export default useUlafMarkersLayer;
|
||||
49
hooks/layers/useWagoMarkersLayer.js
Normal file
49
hooks/layers/useWagoMarkersLayer.js
Normal file
@@ -0,0 +1,49 @@
|
||||
// hooks/useWagoMarkersLayer.js
|
||||
import { useState, useEffect } from "react";
|
||||
import L from "leaflet";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
import { createAndSetDevices } from "../../utils/createAndSetDevices";
|
||||
import { checkOverlappingMarkers } from "../../utils/mapUtils";
|
||||
|
||||
const useWagoMarkersLayer = (map, oms, gisSystemStatic, priorityConfig) => {
|
||||
const [wagoMarkers, setWagoMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (gisSystemStatic && gisSystemStatic.length && map) {
|
||||
createAndSetDevices(7, setWagoMarkers, gisSystemStatic, priorityConfig); // WAGO-System
|
||||
}
|
||||
}, [gisSystemStatic, map, priorityConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && wagoMarkers.length) {
|
||||
wagoMarkers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
|
||||
// Popup on mouseover and mouseout
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
});
|
||||
|
||||
// Disable map context menu
|
||||
map.options.contextmenu = false;
|
||||
map.options.contextmenuItems = [];
|
||||
|
||||
oms.map.options.contextmenu = false;
|
||||
oms.map.options.contextmenuItems = [];
|
||||
|
||||
// Call the function to check for overlapping markers
|
||||
checkOverlappingMarkers(oms, map);
|
||||
}
|
||||
}, [map, wagoMarkers, oms]);
|
||||
|
||||
return wagoMarkers;
|
||||
};
|
||||
|
||||
export default useWagoMarkersLayer;
|
||||
45
hooks/layers/useWdmMarkersLayer.js
Normal file
45
hooks/layers/useWdmMarkersLayer.js
Normal file
@@ -0,0 +1,45 @@
|
||||
// hooks/useWdmMarkersLayer.js
|
||||
import { useEffect, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import { addContextMenuToMarker } from "../../utils/addContextMenuToMarker";
|
||||
import { createAndSetDevices } from "../../utils/createAndSetDevices";
|
||||
|
||||
const useWdmMarkersLayer = (map, oms, GisSystemStatic, priorityConfig) => {
|
||||
const [wdmMarkers, setWdmMarkers] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (GisSystemStatic && GisSystemStatic.length && map) {
|
||||
createAndSetDevices(10, setWdmMarkers, GisSystemStatic, priorityConfig); // WDM
|
||||
}
|
||||
}, [GisSystemStatic, map, priorityConfig]);
|
||||
|
||||
useEffect(() => {
|
||||
if (map && wdmMarkers.length) {
|
||||
wdmMarkers.forEach((marker) => {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
|
||||
// Popup on mouseover and mouseout
|
||||
marker.on("mouseover", function () {
|
||||
this.openPopup();
|
||||
});
|
||||
marker.on("mouseout", function () {
|
||||
this.closePopup();
|
||||
});
|
||||
|
||||
addContextMenuToMarker(marker);
|
||||
});
|
||||
|
||||
// Disable map context menu
|
||||
map.options.contextmenu = false;
|
||||
map.options.contextmenuItems = [];
|
||||
|
||||
oms.map.options.contextmenu = false;
|
||||
oms.map.options.contextmenuItems = [];
|
||||
}
|
||||
}, [map, wdmMarkers, oms]);
|
||||
|
||||
return wdmMarkers;
|
||||
};
|
||||
|
||||
export default useWdmMarkersLayer;
|
||||
15
hooks/useCreateAndSetDevices.js
Normal file
15
hooks/useCreateAndSetDevices.js
Normal file
@@ -0,0 +1,15 @@
|
||||
// /hooks/useCreateAndSetDevices.js
|
||||
import { useEffect } from "react";
|
||||
import { useRecoilState } from "recoil";
|
||||
import { polylineEventsDisabledState } from "../store/atoms/polylineEventsDisabledState";
|
||||
import { createAndSetDevices } from "../utils/createAndSetDevices";
|
||||
|
||||
const useCreateAndSetDevices = (systemId, setMarkersFunction, GisSystemStatic, priorityConfig) => {
|
||||
const [polylineEventsDisabled, setPolylineEventsDisabled] = useRecoilState(polylineEventsDisabledState);
|
||||
|
||||
useEffect(() => {
|
||||
createAndSetDevices(systemId, setMarkersFunction, GisSystemStatic, priorityConfig, setPolylineEventsDisabled);
|
||||
}, [systemId, setMarkersFunction, GisSystemStatic, priorityConfig, setPolylineEventsDisabled]);
|
||||
};
|
||||
|
||||
export default useCreateAndSetDevices;
|
||||
25
hooks/useFetchPoiData.js
Normal file
25
hooks/useFetchPoiData.js
Normal file
@@ -0,0 +1,25 @@
|
||||
// hooks/useFetchPoiData.js
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
const useFetchPoiData = (url) => {
|
||||
const [poiData, setPoiData] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchPoiData = async () => {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error("Network response was not ok");
|
||||
const data = await response.json();
|
||||
setPoiData(data);
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Abrufen der poiData:", error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchPoiData();
|
||||
}, [url]);
|
||||
|
||||
return poiData;
|
||||
};
|
||||
|
||||
export default useFetchPoiData;
|
||||
26
hooks/useLayerVisibility.js
Normal file
26
hooks/useLayerVisibility.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// hooks/useLayerVisibility.js
|
||||
import { useEffect } from "react";
|
||||
import { addContextMenuToMarker } from "../utils/addContextMenuToMarker";
|
||||
|
||||
const useLayerVisibility = (map, markers, mapLayersVisibility, layerKey, oms) => {
|
||||
useEffect(() => {
|
||||
if (!map || !markers || !oms) return;
|
||||
|
||||
const toggleLayer = (isVisible) => {
|
||||
markers.forEach((marker) => {
|
||||
if (isVisible) {
|
||||
marker.addTo(map);
|
||||
oms.addMarker(marker);
|
||||
addContextMenuToMarker(marker); // Kontextmenü hinzufügen
|
||||
} else {
|
||||
map.removeLayer(marker);
|
||||
oms.removeMarker(marker);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
toggleLayer(mapLayersVisibility[layerKey]);
|
||||
}, [map, markers, mapLayersVisibility, layerKey, oms]);
|
||||
};
|
||||
|
||||
export default useLayerVisibility;
|
||||
124
hooks/useLineData-back.js
Normal file
124
hooks/useLineData-back.js
Normal file
@@ -0,0 +1,124 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { SERVER_URL } from "../config/urls";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
const useLineData = (webserviceGisLinesStatusUrl, setLineStatusData) => {
|
||||
const dispatch = useDispatch();
|
||||
const messages = useSelector((state) => state.messages);
|
||||
const [lineColors, setLineColors] = useState({});
|
||||
const [tooltipContents, setTooltipContents] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
let isCancelled = false;
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const response1 = await fetch(webserviceGisLinesStatusUrl);
|
||||
const data1 = await response1.json();
|
||||
|
||||
const response2 = await fetch(`${SERVER_URL}:3000/api/talas_v5_DB/gisLines/readGisLines`);
|
||||
const data2 = await response2.json();
|
||||
|
||||
const response3 = await fetch(`${SERVER_URL}:3000/api/talas_v5_DB/device/getAllStationsNames`);
|
||||
const namesData = await response3.json();
|
||||
|
||||
if (!isCancelled) {
|
||||
const colorsByModule = {};
|
||||
const newTooltipContents = {};
|
||||
const valueMap = {};
|
||||
|
||||
const sortedStatis = [...data1.Statis].sort((a, b) => a.Level - b.Level);
|
||||
|
||||
sortedStatis.forEach((statis) => {
|
||||
const key = `${statis.IdLD}-${statis.Modul}`;
|
||||
|
||||
if (!valueMap[key]) {
|
||||
valueMap[key] = {
|
||||
messages: [],
|
||||
messwert: undefined,
|
||||
schleifenwert: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
if (statis.DpName.endsWith("_Messwert") && statis.Value !== "True" && !valueMap[key].messwert) {
|
||||
valueMap[key].messwert = statis.Value;
|
||||
}
|
||||
if (statis.DpName.endsWith("_Schleifenwert") && !valueMap[key].schleifenwert) {
|
||||
valueMap[key].schleifenwert = statis.Value;
|
||||
}
|
||||
|
||||
if (statis.Message && statis.Message !== "?") {
|
||||
valueMap[key].messages.push({
|
||||
message: statis.Message,
|
||||
prioColor: statis.PrioColor && statis.PrioColor !== "#ffffff" ? statis.PrioColor : "green",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
sortedStatis.forEach((statis) => {
|
||||
const key = `${statis.IdLD}-${statis.Modul}`;
|
||||
const matchingLine = data2.find((item) => item.idLD === statis.IdLD && item.idModul === statis.Modul);
|
||||
|
||||
if (matchingLine) {
|
||||
const values = valueMap[key];
|
||||
|
||||
const messageDisplay = values.messages.map((msg) => `<span class="inline-block text-gray-800"><span class="inline-block w-2 h-2 rounded-full mr-2" style="background-color: ${msg.prioColor};"></span>${msg.message}</span><br>`).join("");
|
||||
|
||||
const prioNameDisplay = statis.PrioName && statis.PrioName !== "?" ? `(${statis.PrioName})` : "";
|
||||
|
||||
colorsByModule[key] = values.messages.length > 0 ? values.messages[0].prioColor : "green";
|
||||
|
||||
newTooltipContents[key] = `
|
||||
<div class="bg-white rounded-lg m-0 p-2 w-[210px]">
|
||||
<span class="text-lg font-semibold text-gray-900">${statis.ModulName || "Unknown"}</span>
|
||||
<br>
|
||||
<span class="text-md font-bold text-gray-800">${statis.ModulTyp || "N/A"}</span>
|
||||
<br>
|
||||
<span class="text-md font-bold text-gray-800">Slot: ${statis.Modul || "N/A"}</span>
|
||||
<br>
|
||||
<span class="text-md font-bold text-gray-800">Station: ${namesData[matchingLine.idLD] || "N/A"}</span>
|
||||
<br>
|
||||
<div style="max-width: 100%; overflow-wrap: break-word; word-break: break-word; white-space: normal;">
|
||||
${messageDisplay}
|
||||
</div>
|
||||
<br>
|
||||
${values.messwert ? `<span class="inline-block text-gray-800">Messwert: ${values.messwert}</span><br>` : ""}
|
||||
${values.schleifenwert ? `<span class="inline-block text-gray-800">Schleifenwert: ${values.schleifenwert}</span>` : ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
});
|
||||
|
||||
setLineColors(colorsByModule);
|
||||
setTooltipContents(newTooltipContents);
|
||||
setLineStatusData(data1.Statis);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Abrufen der Daten:", error);
|
||||
try {
|
||||
window.location.reload();
|
||||
} catch (reloadError) {
|
||||
console.error("Fehler beim Neuladen der Seite:", reloadError);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const scheduleNextFetch = () => {
|
||||
if (!isCancelled) {
|
||||
fetchData();
|
||||
setTimeout(scheduleNextFetch, 30000);
|
||||
}
|
||||
};
|
||||
|
||||
fetchData();
|
||||
scheduleNextFetch();
|
||||
|
||||
return () => {
|
||||
isCancelled = true;
|
||||
};
|
||||
}, [webserviceGisLinesStatusUrl, setLineStatusData]);
|
||||
|
||||
return { lineColors, tooltipContents };
|
||||
};
|
||||
|
||||
export default useLineData;
|
||||
133
hooks/useLineData.js
Normal file
133
hooks/useLineData.js
Normal file
@@ -0,0 +1,133 @@
|
||||
// hooks/useLineData.js
|
||||
import { useEffect, useState } from "react";
|
||||
import { SERVER_URL } from "../config/urls";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
const useLineData = (webserviceGisLinesStatusUrl, setLineStatusData) => {
|
||||
const dispatch = useDispatch();
|
||||
const messages = useSelector((state) => state.messages);
|
||||
const [lineColors, setLineColors] = useState({});
|
||||
const [tooltipContents, setTooltipContents] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
let isCancelled = false;
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const response1 = await fetch(webserviceGisLinesStatusUrl);
|
||||
const data1 = await response1.json();
|
||||
|
||||
const response2 = await fetch(`${SERVER_URL}:3000/api/talas_v5_DB/gisLines/readGisLines`);
|
||||
const data2 = await response2.json();
|
||||
|
||||
const response3 = await fetch(`${SERVER_URL}:3000/api/talas_v5_DB/device/getAllStationsNames`);
|
||||
const namesData = await response3.json();
|
||||
|
||||
if (!isCancelled) {
|
||||
const colorsByModule = {};
|
||||
const newTooltipContents = {};
|
||||
const valueMap = {};
|
||||
|
||||
const sortedStatis = [...data1.Statis].sort((a, b) => a.Level - b.Level);
|
||||
|
||||
sortedStatis.forEach((statis) => {
|
||||
const key = `${statis.IdLD}-${statis.Modul}`;
|
||||
|
||||
if (!valueMap[key]) {
|
||||
valueMap[key] = {
|
||||
messages: [],
|
||||
messwert: undefined,
|
||||
schleifenwert: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
if (statis.DpName.endsWith("_Messwert") && statis.Value !== "True" && !valueMap[key].messwert) {
|
||||
valueMap[key].messwert = statis.Value;
|
||||
}
|
||||
if (statis.DpName.endsWith("_Schleifenwert") && !valueMap[key].schleifenwert) {
|
||||
valueMap[key].schleifenwert = statis.Value;
|
||||
}
|
||||
|
||||
if (statis.Message && statis.Message !== "?") {
|
||||
valueMap[key].messages.push({
|
||||
message: statis.Message,
|
||||
prioColor: statis.PrioColor && statis.PrioColor !== "#ffffff" ? statis.PrioColor : "green",
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
sortedStatis.forEach((statis) => {
|
||||
const key = `${statis.IdLD}-${statis.Modul}`;
|
||||
const matchingLine = data2.find((item) => item.idLD === statis.IdLD && item.idModul === statis.Modul);
|
||||
|
||||
if (matchingLine) {
|
||||
const values = valueMap[key];
|
||||
|
||||
const messageDisplay = values.messages.map((msg) => `<span class="inline-block text-gray-800"><span class="inline-block w-2 h-2 rounded-full mr-2" style="background-color: ${msg.prioColor};"></span>${msg.message}</span><br>`).join("");
|
||||
|
||||
const prioNameDisplay = statis.PrioName && statis.PrioName !== "?" ? `(${statis.PrioName})` : "";
|
||||
|
||||
colorsByModule[key] = values.messages.length > 0 ? values.messages[0].prioColor : "green";
|
||||
|
||||
newTooltipContents[key] = `
|
||||
<div class="bg-white rounded-lg m-0 p-2 w-[210px]">
|
||||
<span class="text-lg font-semibold text-gray-900">${statis.ModulName || "Unknown"}</span>
|
||||
<br>
|
||||
<span class="text-md font-bold text-gray-800">${statis.ModulTyp || "N/A"}</span>
|
||||
<br>
|
||||
<span class="text-md font-bold text-gray-800">Slot: ${statis.Modul || "N/A"}</span>
|
||||
<br>
|
||||
<span class="text-md font-bold text-gray-800">Station: ${namesData[matchingLine.idLD] || "N/A"}</span>
|
||||
<br>
|
||||
<div style="max-width: 100%; overflow-wrap: break-word; word-break: break-word; white-space: normal;">
|
||||
${messageDisplay}
|
||||
</div>
|
||||
<br>
|
||||
${values.messwert ? `<span class="inline-block text-gray-800">Messwert: ${values.messwert}</span><br>` : ""}
|
||||
${values.schleifenwert ? `<span class="inline-block text-gray-800">Schleifenwert: ${values.schleifenwert}</span>` : ""}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
});
|
||||
|
||||
setLineColors(colorsByModule);
|
||||
setTooltipContents(newTooltipContents);
|
||||
setLineStatusData(data1.Statis);
|
||||
|
||||
// Setze den Timeout für die Kontextmenü-Überwachung
|
||||
const countdownDuration = 30000; // 30 Sekunden für den Countdown
|
||||
setTimeout(() => {
|
||||
console.log("Setting contextMenuExpired to true");
|
||||
localStorage.setItem("contextMenuExpired", "true");
|
||||
}, countdownDuration);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Abrufen der Daten:", error);
|
||||
try {
|
||||
window.location.reload();
|
||||
} catch (reloadError) {
|
||||
console.error("Fehler beim Neuladen der Seite:", reloadError);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const scheduleNextFetch = () => {
|
||||
if (!isCancelled) {
|
||||
fetchData();
|
||||
setTimeout(scheduleNextFetch, 30000);
|
||||
}
|
||||
};
|
||||
|
||||
fetchData();
|
||||
scheduleNextFetch();
|
||||
|
||||
return () => {
|
||||
isCancelled = true;
|
||||
localStorage.removeItem("contextMenuExpired"); // Flagge entfernen, wenn das Hook unmounted wird
|
||||
};
|
||||
}, [webserviceGisLinesStatusUrl, setLineStatusData]);
|
||||
|
||||
return { lineColors, tooltipContents };
|
||||
};
|
||||
|
||||
export default useLineData;
|
||||
48
hooks/useMapComponentState.js
Normal file
48
hooks/useMapComponentState.js
Normal file
@@ -0,0 +1,48 @@
|
||||
// hooks/useMapComponentState.js
|
||||
import { useState, useEffect } from "react";
|
||||
import usePoiTypData from "./usePoiTypData";
|
||||
import { useRecoilValue } from "recoil";
|
||||
import { poiLayerVisibleState } from "../store/atoms/poiLayerVisibleState";
|
||||
|
||||
export const useMapComponentState = () => {
|
||||
const { poiTypData, isPoiTypLoaded } = usePoiTypData("/api/talas_v5_DB/poiTyp/readPoiTyp");
|
||||
const [deviceName, setDeviceName] = useState("");
|
||||
const [locationDeviceData, setLocationDeviceData] = useState([]);
|
||||
const [priorityConfig, setPriorityConfig] = useState([]);
|
||||
const [menuItemAdded, setMenuItemAdded] = useState(false);
|
||||
const poiLayerVisible = useRecoilValue(poiLayerVisibleState);
|
||||
|
||||
// Fetch devices when the component is mounted
|
||||
useEffect(() => {
|
||||
const fetchDeviceData = async () => {
|
||||
try {
|
||||
const response = await fetch("/api/talas5/location_device"); // API call to get devices
|
||||
const data = await response.json();
|
||||
setLocationDeviceData(data); // Set the device data
|
||||
|
||||
// Optional: set a default deviceName if needed
|
||||
if (data.length > 0) {
|
||||
setDeviceName(data[0].name); // Set the first device's name
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching device data:", error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchDeviceData();
|
||||
}, []); // Runs only once when the component is mounted
|
||||
|
||||
return {
|
||||
poiTypData,
|
||||
isPoiTypLoaded,
|
||||
deviceName,
|
||||
setDeviceName,
|
||||
locationDeviceData,
|
||||
setLocationDeviceData,
|
||||
priorityConfig,
|
||||
setPriorityConfig,
|
||||
menuItemAdded,
|
||||
setMenuItemAdded,
|
||||
poiLayerVisible,
|
||||
};
|
||||
};
|
||||
26
hooks/useMarkerLayers.js
Normal file
26
hooks/useMarkerLayers.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// hooks/useMarkerLayers.js
|
||||
import { useEffect } from "react";
|
||||
import { useRecoilValue } from "recoil";
|
||||
import { mapLayersState } from "../store/atoms/mapLayersState";
|
||||
|
||||
const useMarkerLayers = (map, markers, layerType) => {
|
||||
const mapLayersVisibility = useRecoilValue(mapLayersState);
|
||||
|
||||
useEffect(() => {
|
||||
if (!map || !markers) return;
|
||||
|
||||
const toggleLayer = (isVisible) => {
|
||||
markers.forEach((marker) => {
|
||||
if (isVisible) {
|
||||
marker.addTo(map);
|
||||
} else {
|
||||
map.removeLayer(marker);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
toggleLayer(mapLayersVisibility[layerType]);
|
||||
}, [map, markers, mapLayersVisibility, layerType]);
|
||||
};
|
||||
|
||||
export default useMarkerLayers;
|
||||
26
hooks/usePoiTypData.js
Normal file
26
hooks/usePoiTypData.js
Normal file
@@ -0,0 +1,26 @@
|
||||
// hooks/usePoiTypData.js
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
const usePoiTypData = (url) => {
|
||||
const [poiTypData, setPoiTypData] = useState([]);
|
||||
const [isPoiTypLoaded, setIsPoiTypLoaded] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchPoiTypData = async () => {
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
setPoiTypData(data);
|
||||
setIsPoiTypLoaded(true);
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Abrufen der poiTyp-Daten:", error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchPoiTypData();
|
||||
}, [url]);
|
||||
|
||||
return { poiTypData, isPoiTypLoaded };
|
||||
};
|
||||
|
||||
export default usePoiTypData;
|
||||
@@ -1,12 +1,10 @@
|
||||
module.exports = {
|
||||
setupFilesAfterEnv: ["<rootDir>/setupTests.js"],
|
||||
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
|
||||
testEnvironment: "jest-environment-jsdom",
|
||||
testPathIgnorePatterns: ["<rootDir>/.next/", "<rootDir>/node_modules/"],
|
||||
transform: {
|
||||
"^.+\\.(js|jsx)$": "babel-jest",
|
||||
"^.+\\.(js|jsx|ts|tsx)$": "babel-jest",
|
||||
},
|
||||
transformIgnorePatterns: [
|
||||
"/node_modules/(?!(@react-leaflet|react-leaflet|leaflet)/)",
|
||||
],
|
||||
testEnvironment: "jsdom",
|
||||
moduleNameMapper: {
|
||||
"\\.(css|less|scss|sass)$": "identity-obj-proxy",
|
||||
},
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
import "@testing-library/jest-dom";
|
||||
// jest.setup.js
|
||||
global.fetch = require("jest-fetch-mock");
|
||||
jest.setMock("node-fetch", fetch);
|
||||
|
||||
4501
package-lock.json
generated
4501
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
50
package.json
50
package.json
@@ -1,48 +1,56 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@heroicons/react": "^2.1.3",
|
||||
"express": "^4.19.2",
|
||||
"@emotion/react": "^11.13.3",
|
||||
"@emotion/styled": "^11.13.0",
|
||||
"@heroicons/react": "^2.1.5",
|
||||
"@mui/icons-material": "^6.0.2",
|
||||
"@reduxjs/toolkit": "^2.2.7",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"dotenv": "^16.4.5",
|
||||
"http-proxy-middleware": "^3.0.0",
|
||||
"leaflet": "^1.9.4",
|
||||
"leaflet-contextmenu": "^1.4.0",
|
||||
"leaflet.smooth_marker_bouncing": "^3.0.3",
|
||||
"lodash": "^4.17.21",
|
||||
"leaflet.smooth_marker_bouncing": "^3.1.0",
|
||||
"mysql": "^2.18.1",
|
||||
"mysql2": "^3.10.1",
|
||||
"next": "^14.2.3",
|
||||
"mysql2": "^3.11.0",
|
||||
"next": "^14.2.5",
|
||||
"nextjs-cors": "^2.2.0",
|
||||
"overlapping-marker-spiderfier-leaflet": "^0.2.7",
|
||||
"postcss": "^8.4.40",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-leaflet": "^4.2.1",
|
||||
"react-redux": "^9.1.2",
|
||||
"react-select": "^5.8.0",
|
||||
"react-toastify": "^10.0.5",
|
||||
"recoil": "^0.7.7"
|
||||
"recoil": "^0.7.7",
|
||||
"redux": "^5.0.1",
|
||||
"redux-thunk": "^3.1.0",
|
||||
"tailwindcss": "^3.4.7",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"export": "next export",
|
||||
"test": "jest"
|
||||
"test": "jest",
|
||||
"cypress": "cypress open",
|
||||
"cypress:run": "cypress run"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.7",
|
||||
"@babel/preset-env": "^7.24.7",
|
||||
"@babel/core": "^7.25.2",
|
||||
"@babel/preset-env": "^7.25.2",
|
||||
"@babel/preset-react": "^7.24.7",
|
||||
"@testing-library/jest-dom": "^6.4.6",
|
||||
"@testing-library/jest-dom": "^6.4.8",
|
||||
"@testing-library/react": "^16.0.0",
|
||||
"@types/leaflet": "^1.9.12",
|
||||
"@types/leaflet-contextmenu": "^1.4.3",
|
||||
"@types/react": "^18.3.1",
|
||||
"@types/react-dom": "^18.3.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"@testing-library/user-event": "^14.5.2",
|
||||
"babel-jest": "^29.7.0",
|
||||
"cypress": "^13.14.2",
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^29.7.0",
|
||||
"jest-css-modules-transform": "^4.4.2",
|
||||
"jest-environment-jsdom": "^29.7.0",
|
||||
"postcss": "^8.4.39",
|
||||
"prettier": "^3.2.5",
|
||||
"tailwindcss": "^3.4.3"
|
||||
"jest-fetch-mock": "^3.0.3",
|
||||
"node-fetch": "^3.3.2",
|
||||
"raw-loader": "^4.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
// Pfad: pages/_app.js
|
||||
import React from "react";
|
||||
import { RecoilRoot } from "recoil";
|
||||
import { Provider } from "react-redux";
|
||||
import store from "../redux/store";
|
||||
import "../styles/global.css";
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return (
|
||||
<RecoilRoot>
|
||||
<Component {...pageProps} />
|
||||
</RecoilRoot>
|
||||
<Provider store={store}>
|
||||
<RecoilRoot>
|
||||
<Component {...pageProps} />
|
||||
</RecoilRoot>
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
20
pages/api - Kopie/[...path].js
Normal file
20
pages/api - Kopie/[...path].js
Normal file
@@ -0,0 +1,20 @@
|
||||
// pages/api/[...path].js
|
||||
import { createProxyMiddleware } from "http-proxy-middleware";
|
||||
//import { SERVER_URL } from "../config/urls.js";
|
||||
//console.log("SERVER_URL:", SERVER_URL); // Debug-Ausgabe
|
||||
|
||||
export default createProxyMiddleware({
|
||||
//target: "http://192.168.10.58:3001",
|
||||
// Stationen bekommen
|
||||
//target: "http://10.10.0.13", // Ziel-URL des Proxys // API Aufruf zum mapGisStationsStaticDistrictUrl, mapGisStationsStatusDistrictUrl, mapGisStationsMeasurementsUrl, mapGisSystemStaticUrl und mapDataIconUrl
|
||||
target: `${process.env.NEXT_PUBLIC_SERVER_URL}`, //
|
||||
//target: urls.PROXY_TARGET,
|
||||
//target: "http://localhost:3000", // Ziel-URL des Proxys
|
||||
//target: "http://192.168.10.187:3000", // Ziel-URL des Proxys
|
||||
//target: "http://192.168.10.14",
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
"^/api": "/", // Optional: Entfernt /api aus dem Pfad, wenn das Backend dies nicht erfordert
|
||||
},
|
||||
logLevel: "debug", // Setzt das Logging-Level auf "debug" für detaillierte Ausgaben
|
||||
});
|
||||
20
pages/api - Kopie/get-talasIP.js
Normal file
20
pages/api - Kopie/get-talasIP.js
Normal file
@@ -0,0 +1,20 @@
|
||||
// pages/api/get-talasIP.js
|
||||
|
||||
export default function handler(req, res) {
|
||||
// Der x-forwarded-for Header könnte mehrere IP-Adressen enthalten, getrennt durch Kommas
|
||||
let clientIp =
|
||||
req.headers["x-forwarded-for"]?.split(",").map((ip) => ip.trim())[0] ||
|
||||
req.socket.remoteAddress;
|
||||
|
||||
// Entfernen möglicher IPv6 "mapped" IPv4 Adressen
|
||||
if (clientIp?.includes("::ffff:")) {
|
||||
clientIp = clientIp.split("::ffff:")[1];
|
||||
}
|
||||
|
||||
// Nur IPv4 Adressen weitergeben, IPv6 Adressen ausschließen
|
||||
if (clientIp && clientIp.includes(":")) {
|
||||
clientIp = ""; // Dies setzt die IP auf leer, wenn es sich um eine IPv6-Adresse handelt
|
||||
}
|
||||
|
||||
res.status(200).json({ ip: clientIp });
|
||||
}
|
||||
34
pages/api - Kopie/gis-proxy.js
Normal file
34
pages/api - Kopie/gis-proxy.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// /pages/api/gis-proxy.js
|
||||
// Importieren der erforderlichen Module
|
||||
import httpProxy from "http-proxy";
|
||||
import Cookies from "cookies";
|
||||
|
||||
// Erstellen eines Proxy-Servers
|
||||
const proxy = httpProxy.createProxyServer();
|
||||
|
||||
export default (req, res) => {
|
||||
return new Promise((resolve) => {
|
||||
// CORS-Headers einstellen
|
||||
res.setHeader("Access-Control-Allow-Credentials", true);
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
|
||||
// Cookies initialisieren
|
||||
const cookies = new Cookies(req, res);
|
||||
const targetUrl = `${process.env.NEXT_PUBLIC_SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic`;
|
||||
|
||||
// Proxy-Konfiguration und Event-Listener
|
||||
req.on("data", () => {});
|
||||
req.on("end", () => {
|
||||
proxy.web(req, res, { target: targetUrl, changeOrigin: true, selfHandleResponse: false }, (e) => {
|
||||
if (e) {
|
||||
console.error(e);
|
||||
res.status(500).json({ error: "Proxy-Fehler", e });
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
// Weiterleitung der Headers
|
||||
req.headers.cookie = cookies.get("cookie-name") || "";
|
||||
});
|
||||
};
|
||||
64
pages/api - Kopie/linesColorApi.js
Normal file
64
pages/api - Kopie/linesColorApi.js
Normal file
@@ -0,0 +1,64 @@
|
||||
// /pages/api/linesColorApi.js
|
||||
// http://10.10.0.13/talas5/ClientData/WebServiceMap.asmx/GisStationsStatusDistrict
|
||||
//In DB gis_lines idLD und idModul anpassen entsprechend
|
||||
|
||||
// /pages/api/linesColorApi.js
|
||||
import NextCors from "nextjs-cors";
|
||||
|
||||
export default async function handler(req, res) {
|
||||
// Run the cors middleware
|
||||
await NextCors(req, res, {
|
||||
// Options
|
||||
methods: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"],
|
||||
origin: "*", // Erlauben Sie alle Ursprünge, oder geben Sie spezifische Ursprünge an
|
||||
optionsSuccessStatus: 200, // Legacy-Browser-Unterstützung für 204
|
||||
});
|
||||
|
||||
const response = {
|
||||
Name: "Liste aller Statis der Linien",
|
||||
Zeitstempel: new Date().toISOString(), // Aktuellen Zeitstempel hinzufügen
|
||||
IdMap: "10",
|
||||
Statis: [
|
||||
/* {
|
||||
IdLD: 50922,
|
||||
Modul: 1,
|
||||
DpName: "KUE01_Ausfall",
|
||||
ModulName: "42 Wippershain Sender",
|
||||
// ModulTyp: "nicht vorhanden",
|
||||
ModulTyp: "KÜ705-FO",
|
||||
Message: "KUEG 01: 42 Wippershain Sender Messwerkausfall kommend",
|
||||
Level: 4,
|
||||
PrioColor: "#FFFF00",
|
||||
PrioName: "system",
|
||||
Value: "10 MOhm",
|
||||
},
|
||||
{
|
||||
IdLD: 25440,
|
||||
Modul: 3,
|
||||
DpName: "KUE03_Ausfall",
|
||||
ModulName: "42 Solz Sender",
|
||||
//ModulTyp: "nicht vorhanden",
|
||||
ModulTyp: "KÜSS V2",
|
||||
Message: "KUEG 03: 42 Solz Sender Messwerkausfall kommend",
|
||||
Level: 4,
|
||||
PrioColor: "#FF0000",
|
||||
PrioName: "system",
|
||||
Value: "10 MOhm",
|
||||
},
|
||||
{
|
||||
IdLD: 25440,
|
||||
Modul: 4,
|
||||
DpName: "KUE04_Ausfall",
|
||||
ModulName: "42/13 Bad Hersfeld Gaswerk",
|
||||
ModulTyp: "Kue705-FO",
|
||||
Message: "KUEG 04: 42/13 Bad Hersfeld Gaswerk Messwerkausfall kommend",
|
||||
Level: 4,
|
||||
PrioColor: "#FF00FF",
|
||||
PrioName: "system",
|
||||
Value: "10 MOhm",
|
||||
}, */
|
||||
],
|
||||
};
|
||||
|
||||
res.status(200).json(response);
|
||||
}
|
||||
29
pages/api - Kopie/rights.js
Normal file
29
pages/api - Kopie/rights.js
Normal file
@@ -0,0 +1,29 @@
|
||||
// pages/api/rights.js
|
||||
|
||||
export default function handler(req, res) {
|
||||
const { idMap, idUser } = req.query;
|
||||
|
||||
// Beispielhafte Rechte, die je nach idMap und idUser variieren können
|
||||
const rights = {
|
||||
'10': [
|
||||
{ IdRight: 1, Name: "Zugriff auf Dashboard" },
|
||||
{ IdRight: 56, Name: "Erweiterte Berechtigungen" }
|
||||
],
|
||||
'2': [
|
||||
{ IdRight: 2, Name: "Zugriff auf Einstellungen" }
|
||||
],
|
||||
'1': [
|
||||
{ IdRight: 10, Name: "Admin-Zugriff" },
|
||||
{ IdRight: 11, Name: "Zugriff auf alle Daten" }
|
||||
]
|
||||
};
|
||||
|
||||
// Prüfung, ob eine gültige idMap und idUser vorhanden sind
|
||||
if (rights[idMap] && idUser === '484') {
|
||||
// Rückgabe der spezifischen Rechte basierend auf der idMap und idUser
|
||||
res.status(200).json({ Rights: rights[idMap] });
|
||||
} else {
|
||||
// Rückgabe leerer Rechte für ungültige idMap oder andere Benutzer
|
||||
res.status(200).json({ Rights: [] });
|
||||
}
|
||||
}
|
||||
40
pages/api - Kopie/talas5/area.js
Normal file
40
pages/api - Kopie/talas5/area.js
Normal file
@@ -0,0 +1,40 @@
|
||||
// pages/api/talas_v5/area.js
|
||||
// Lesen von talas_v5 MySQL-Datenbank -> area Tabelle enthält DAUZ Geräte
|
||||
// Wenn gebraucht wird, dann nutzen ansonsten löschen
|
||||
|
||||
import mysql from "mysql";
|
||||
|
||||
const dbConfig = {
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
port: process.env.DB_PORT,
|
||||
};
|
||||
//console.log("my dbconfig: ", dbConfig);
|
||||
export default function handler(req, res) {
|
||||
const connection = mysql.createConnection(dbConfig);
|
||||
|
||||
connection.connect((err) => {
|
||||
if (err) {
|
||||
console.error("Fehler beim Verbinden:", err.stack);
|
||||
res.status(500).json({ error: "Verbindungsfehler zur Datenbank" });
|
||||
return;
|
||||
}
|
||||
|
||||
//console.log("Verbunden als ID", connection.threadId);
|
||||
//Fehler weil, existiertdie Tabelle auf localhost:3000 nicht
|
||||
connection.query("SELECT ..., ..., ..., ... FROM ... WHERE ... = ...", (error, results) => {
|
||||
if (error) {
|
||||
console.error("Fehler beim Abrufen der API", error);
|
||||
res.status(500).json({ error: "Fehler bei der Abfrage" });
|
||||
return;
|
||||
}
|
||||
|
||||
// Wichtig: Senden Sie die Antwort zurück
|
||||
res.status(200).json(results);
|
||||
|
||||
connection.end();
|
||||
});
|
||||
});
|
||||
}
|
||||
42
pages/api - Kopie/talas5/location_device.js
Normal file
42
pages/api - Kopie/talas5/location_device.js
Normal file
@@ -0,0 +1,42 @@
|
||||
// Importieren des mysql2 Pakets
|
||||
import mysql from "mysql2";
|
||||
|
||||
// Erstellen eines Pools von Datenbankverbindungen
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
port: process.env.DB_PORT,
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
queueLimit: 0,
|
||||
});
|
||||
|
||||
// Ein Hilfsfunktion, um Anfragen zu vereinfachen
|
||||
function queryDatabase(query, params) {
|
||||
return new Promise((resolve, reject) => {
|
||||
pool.query(query, params, (error, results) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
resolve(results);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// API-Handler
|
||||
export default async function handler(req, res) {
|
||||
try {
|
||||
// Dein SQL-Query und die Parameter
|
||||
const sql = "SELECT idLD, iddevice, name FROM location_device WHERE iddevice = ?";
|
||||
const params = [160]; // Beispielparameter
|
||||
|
||||
// Ausführen der Datenbankabfrage
|
||||
const results = await queryDatabase(sql, params);
|
||||
res.status(200).json(results);
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Abrufen der API", error);
|
||||
res.status(500).json({ error: "Fehler bei der Abfrage" });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
// /pages/api/talas5/webserviceMap/GisStationsMeasurements.js
|
||||
const GisStationsMeasurements = {
|
||||
"Name": "Liste aller Messungen der Geraete",
|
||||
"Zeitstempel": "2024-05-31T15:25:32.5047629+02:00",
|
||||
"IdMap": "10",
|
||||
"Statis": [
|
||||
{
|
||||
"IdLD": 50004,
|
||||
"IdL": 18624,
|
||||
"IdDP": 3,
|
||||
"Na": "FBT",
|
||||
"Val": "20.5",
|
||||
"Unit": "°C",
|
||||
"Gr": "GMA",
|
||||
"Area_Name": "Renzenhof (RG)"
|
||||
},
|
||||
{
|
||||
"IdLD": 50004,
|
||||
"IdL": 18624,
|
||||
"IdDP": 10,
|
||||
"Na": "GT",
|
||||
"Val": "nicht ermittelbar",
|
||||
"Unit": "°C",
|
||||
"Gr": "GMA",
|
||||
"Area_Name": "Renzenhof (RG)"
|
||||
},
|
||||
{
|
||||
"IdLD": 50004,
|
||||
"IdL": 18624,
|
||||
"IdDP": 2,
|
||||
"Na": "LT",
|
||||
"Val": "Datenlücke",
|
||||
"Unit": "°C",
|
||||
"Gr": "GMA",
|
||||
"Area_Name": "Renzenhof (RG)"
|
||||
},
|
||||
{
|
||||
"IdLD": 50004,
|
||||
"IdL": 18624,
|
||||
"IdDP": 6,
|
||||
"Na": "RLF",
|
||||
"Val": "100.0",
|
||||
"Unit": "%",
|
||||
"Gr": "GMA",
|
||||
"Area_Name": "Renzenhof (RG)"
|
||||
},
|
||||
{
|
||||
"IdLD": 50004,
|
||||
"IdL": 18624,
|
||||
"IdDP": 11,
|
||||
"Na": "TPT",
|
||||
"Val": "8.3",
|
||||
"Unit": "°C",
|
||||
"Gr": "GMA",
|
||||
"Area_Name": "Renzenhof (RG)"
|
||||
},
|
||||
{
|
||||
"IdLD": 50004,
|
||||
"IdL": 18624,
|
||||
"IdDP": 12,
|
||||
"Na": "TT1",
|
||||
"Val": "---",
|
||||
"Unit": "°C",
|
||||
"Gr": "GMA",
|
||||
"Area_Name": "Renzenhof (RG)"
|
||||
},
|
||||
{
|
||||
"IdLD": 50004,
|
||||
"IdL": 18624,
|
||||
"IdDP": 16,
|
||||
"Na": "WFD",
|
||||
"Val": "0.12",
|
||||
"Unit": "mm",
|
||||
"Gr": "GMA",
|
||||
"Area_Name": "Renzenhof (RG)"
|
||||
},
|
||||
{
|
||||
"IdLD": 50004,
|
||||
"IdL": 18624,
|
||||
"IdDP": 8,
|
||||
"Na": "WGM",
|
||||
"Val": "---",
|
||||
"Unit": "m/s",
|
||||
"Gr": "GMA",
|
||||
"Area_Name": "Renzenhof (RG)"
|
||||
},
|
||||
{
|
||||
"IdLD": 50004,
|
||||
"IdL": 18624,
|
||||
"IdDP": 9,
|
||||
"Na": "WGS",
|
||||
"Val": "---",
|
||||
"Unit": "m/s",
|
||||
"Gr": "GMA",
|
||||
"Area_Name": "Renzenhof (RG)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// Export an async function handler for the API route.
|
||||
export default async function handler(req, res) {
|
||||
// Initialize an empty params object to store query parameters.
|
||||
const params = {
|
||||
idMap: req.query.idMap,
|
||||
|
||||
};
|
||||
|
||||
// Check if the requested ID map and user match certain conditions.
|
||||
if (params.idMap === '10') {
|
||||
// If the conditions are met, return the GisStationsMeasurements object with a 200 status code.
|
||||
res.status(200).json(GisStationsMeasurements);
|
||||
} else {
|
||||
// If not, return a 404 error with the message "Not Found".
|
||||
res.status(404).send('Not Found');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,281 @@
|
||||
// /pages/api/talas5/webserviceMap/GisStationsStaticDistrict.js
|
||||
const GisStationsStaticDistrict = {
|
||||
"Name": "Liste aller Geraete einer bestimmten Karte",
|
||||
"Zeitstempel": "2024-05-31T15:26:56.9235766+02:00",
|
||||
"IdMap": "10",
|
||||
"Points": [
|
||||
{
|
||||
"LD_Name": "CPL Bentheim",
|
||||
"IdLD": 50017,
|
||||
"Device": "CPL V3.5 mit 16 Kü",
|
||||
"Link": "cpl.aspx?ver=35&kue=16&id=50017",
|
||||
"Location_Name": "Technikraum",
|
||||
"Location_Short": "BEHE",
|
||||
"IdLocation": 17448,
|
||||
"Area_Name": "Bad-Bentheim",
|
||||
"Area_Short": "BEHE--00",
|
||||
"IdArea": 16418,
|
||||
"X": 51.5728,
|
||||
"Y": 9.00056,
|
||||
"Icon": 20,
|
||||
"System": 1,
|
||||
"Active": 0
|
||||
},
|
||||
{
|
||||
"LD_Name": "Drucker",
|
||||
"IdLD": 50084,
|
||||
"Device": "Basisgerät",
|
||||
"Link": "basis.aspx?ver=1&id=50084",
|
||||
"Location_Name": "Technikraum",
|
||||
"Location_Short": "SLUE",
|
||||
"IdLocation": 17776,
|
||||
"Area_Name": "Schlüchtern II",
|
||||
"Area_Short": "SLUE--00",
|
||||
"IdArea": 14688,
|
||||
"X": 53.2455,
|
||||
"Y": 8.1614,
|
||||
"Icon": 14,
|
||||
"System": 200,
|
||||
"Active": 0
|
||||
},
|
||||
{
|
||||
"LD_Name": "Türkontakt",
|
||||
"IdLD": 50666,
|
||||
"Device": "ECI",
|
||||
"Link": "eci.aspx?ver=1&id=50666",
|
||||
"Location_Name": "Technikraum",
|
||||
"Location_Short": "SLUE",
|
||||
"IdLocation": 17776,
|
||||
"Area_Name": "Schlüchtern II",
|
||||
"Area_Short": "SLUE--00",
|
||||
"IdArea": 14688,
|
||||
"X": 53.2455,
|
||||
"Y": 8.1614,
|
||||
"Icon": 17,
|
||||
"System": 2,
|
||||
"Active": 0
|
||||
},
|
||||
{
|
||||
"LD_Name": "Triptis",
|
||||
"IdLD": 50888,
|
||||
"Device": "CPL 200",
|
||||
"Link": "cpl.aspx?ver=30&kue=16&id=50888",
|
||||
"Location_Name": "Technikraum",
|
||||
"Location_Short": "SLUE",
|
||||
"IdLocation": 17776,
|
||||
"Area_Name": "Schlüchtern II",
|
||||
"Area_Short": "SLUE--00",
|
||||
"IdArea": 14688,
|
||||
"X": 53.2455,
|
||||
"Y": 8.1614,
|
||||
"Icon": 20,
|
||||
"System": 1,
|
||||
"Active": 0
|
||||
},
|
||||
{
|
||||
"LD_Name": "Rodaborn I",
|
||||
"IdLD": 50889,
|
||||
"Device": "cpl.mio V>6",
|
||||
"Link": "cplmio.aspx?ver=1&id=50889",
|
||||
"Location_Name": "Technikraum",
|
||||
"Location_Short": "SLUE",
|
||||
"IdLocation": 17776,
|
||||
"Area_Name": "Schlüchtern II",
|
||||
"Area_Short": "SLUE--00",
|
||||
"IdArea": 14688,
|
||||
"X": 53.2455,
|
||||
"Y": 8.1614,
|
||||
"Icon": 20,
|
||||
"System": 1,
|
||||
"Active": 0
|
||||
},
|
||||
{
|
||||
"LD_Name": "Rodaborn II",
|
||||
"IdLD": 50900,
|
||||
"Device": "cpl.mio V>6",
|
||||
"Link": "cplmio.aspx?ver=1&id=50900",
|
||||
"Location_Name": "Technikraum",
|
||||
"Location_Short": "SLUE",
|
||||
"IdLocation": 17776,
|
||||
"Area_Name": "Schlüchtern II",
|
||||
"Area_Short": "SLUE--00",
|
||||
"IdArea": 14688,
|
||||
"X": 53.2455,
|
||||
"Y": 8.1614,
|
||||
"Icon": 20,
|
||||
"System": 1,
|
||||
"Active": 0
|
||||
},
|
||||
{
|
||||
"LD_Name": "Hermsdorf",
|
||||
"IdLD": 50901,
|
||||
"Device": "CPL V3.5 mit 24 Kü",
|
||||
"Link": "cpl.aspx?ver=35&kue=24&id=50901",
|
||||
"Location_Name": "Technikraum",
|
||||
"Location_Short": "SLUE",
|
||||
"IdLocation": 17776,
|
||||
"Area_Name": "Schlüchtern II",
|
||||
"Area_Short": "SLUE--00",
|
||||
"IdArea": 14688,
|
||||
"X": 53.2455,
|
||||
"Y": 8.1614,
|
||||
"Icon": 20,
|
||||
"System": 1,
|
||||
"Active": 1
|
||||
},
|
||||
{
|
||||
"LD_Name": "GMA Littwin (TEST)",
|
||||
"IdLD": 50004,
|
||||
"Device": "Glättemeldeanlage",
|
||||
"Link": "gma.aspx?ver=1&id=50004",
|
||||
"Location_Name": "RG Relaisraum",
|
||||
"Location_Short": "REZR",
|
||||
"IdLocation": 18624,
|
||||
"Area_Name": "Renzenhof (RG)",
|
||||
"Area_Short": "REZHRG00",
|
||||
"IdArea": 16570,
|
||||
"X": 53.246036,
|
||||
"Y": 8.163293,
|
||||
"Icon": 1,
|
||||
"System": 11,
|
||||
"Active": 0
|
||||
},
|
||||
{
|
||||
"LD_Name": "NRS Testserver",
|
||||
"IdLD": 50005,
|
||||
"Device": "Notruf Server",
|
||||
"Link": "nrs_server.aspx?ver=1&id=50005",
|
||||
"Location_Name": "(EV Ammersricht BZR REL)",
|
||||
"Location_Short": "AMME",
|
||||
"IdLocation": 21118,
|
||||
"Area_Name": "Ammersricht BZR (FGN)",
|
||||
"Area_Short": "AMMER--00",
|
||||
"IdArea": 15958,
|
||||
"X": 52.52726,
|
||||
"Y": 12.165488,
|
||||
"Icon": 19,
|
||||
"System": 8,
|
||||
"Active": 0
|
||||
},
|
||||
{
|
||||
"LD_Name": "Gateway 2",
|
||||
"IdLD": 50007,
|
||||
"Device": "Notruf Server",
|
||||
"Link": "nrs_server.aspx?ver=1&id=50007",
|
||||
"Location_Name": "(EV Ammersricht BZR REL)",
|
||||
"Location_Short": "AMME",
|
||||
"IdLocation": 21118,
|
||||
"Area_Name": "Ammersricht BZR (FGN)",
|
||||
"Area_Short": "AMMER--00",
|
||||
"IdArea": 15958,
|
||||
"X": 52.52726,
|
||||
"Y": 12.165488,
|
||||
"Icon": 19,
|
||||
"System": 8,
|
||||
"Active": 0
|
||||
},
|
||||
{
|
||||
"LD_Name": "Basisgerät mit SNMP MVP",
|
||||
"IdLD": 50669,
|
||||
"Device": "Basisgerät + SNMP",
|
||||
"Link": "basisSNMP.aspx?&ver=1&id=50669",
|
||||
"Location_Name": "Mylinghauserstraße Engelbert",
|
||||
"Location_Short": "G-GEVELSBE-1",
|
||||
"IdLocation": 24012,
|
||||
"Area_Name": "Gevelsberg",
|
||||
"Area_Short": "GMA-GEVELSBE",
|
||||
"IdArea": 20919,
|
||||
"X": 51.316799,
|
||||
"Y": 7.33281,
|
||||
"Icon": 14,
|
||||
"System": 200,
|
||||
"Active": 1
|
||||
},
|
||||
{
|
||||
"LD_Name": "Server 3",
|
||||
"IdLD": 50009,
|
||||
"Device": "Notruf Server",
|
||||
"Link": "nrs_server.aspx?ver=1&id=50009",
|
||||
"Location_Name": "Militärringstraße Militärringstraße",
|
||||
"Location_Short": "G-KÖLN-1",
|
||||
"IdLocation": 24015,
|
||||
"Area_Name": "Köln",
|
||||
"Area_Short": "GMA-KÖLN",
|
||||
"IdArea": 20921,
|
||||
"X": 50.898399,
|
||||
"Y": 6.92278,
|
||||
"Icon": 19,
|
||||
"System": 8,
|
||||
"Active": 0
|
||||
},
|
||||
{
|
||||
"LD_Name": "ICL Test 5",
|
||||
"IdLD": 50054,
|
||||
"Device": "ICL",
|
||||
"Link": "icl.aspx?ver=1&id=50054",
|
||||
"Location_Name": "Recheder Mühlenweg Dortmund-Ems-Kanal",
|
||||
"Location_Short": "G-OLFEN-SE-1",
|
||||
"IdLocation": 24022,
|
||||
"Area_Name": "Olfen-Selm",
|
||||
"Area_Short": "GMA-OLFEN-SE",
|
||||
"IdArea": 20926,
|
||||
"X": 51.702202,
|
||||
"Y": 7.40822,
|
||||
"Icon": 23,
|
||||
"System": 100,
|
||||
"Active": 0
|
||||
},
|
||||
{
|
||||
"LD_Name": "ICL Test 3",
|
||||
"IdLD": 50052,
|
||||
"Device": "ICL",
|
||||
"Link": "icl.aspx?ver=1&id=50052",
|
||||
"Location_Name": "Weidenstraße Hestenberg",
|
||||
"Location_Short": "G-PLETTENB-1",
|
||||
"IdLocation": 24024,
|
||||
"Area_Name": "Plettenberg",
|
||||
"Area_Short": "GMA-PLETTENB",
|
||||
"IdArea": 20928,
|
||||
"X": 51.224098,
|
||||
"Y": 7.86969,
|
||||
"Icon": 23,
|
||||
"System": 100,
|
||||
"Active": 0
|
||||
},
|
||||
{
|
||||
"LD_Name": "Test Februar Kai",
|
||||
"IdLD": 50912,
|
||||
"Device": "Dauerzählstelle DZ",
|
||||
"Link": "dauz.aspx?ver=1&id=50912",
|
||||
"Location_Name": "In der Hoffnung Kiesberg - BG Ost",
|
||||
"Location_Short": "G-WUPPERTA-4",
|
||||
"IdLocation": 24039,
|
||||
"Area_Name": "Wuppertal",
|
||||
"Area_Short": "GMA-WUPPERTA",
|
||||
"IdArea": 20937,
|
||||
"X": 51.238899,
|
||||
"Y": 7.12715,
|
||||
"Icon": 14,
|
||||
"System": 110,
|
||||
"Active": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// Export an async function handler for the API route.
|
||||
export default async function handler(req, res) {
|
||||
// Initialize an empty params object to store query parameters.
|
||||
const params = {
|
||||
idMap: req.query.idMap,
|
||||
idUser: req.query.idUser
|
||||
};
|
||||
|
||||
// Check if the requested ID map and user match certain conditions.
|
||||
if (params.idMap === '10' && params.idUser === '484') {
|
||||
// If the conditions are met, return the GisStationsStaticDistrict object with a 200 status code.
|
||||
res.status(200).json(GisStationsStaticDistrict);
|
||||
} else {
|
||||
// If not, return a 404 error with the message "Not Found".
|
||||
res.status(404).send('Not Found');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
// /pages/api/talas5/webserviceMap/gisStationsMeasurementsSQL.js
|
||||
import mysql from "mysql2/promise";
|
||||
|
||||
// Erstellen eines Verbindungspools anstelle einer einzelnen Verbindung
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
port: process.env.DB_PORT,
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
queueLimit: 0,
|
||||
});
|
||||
|
||||
export default async function handler(req, res) {
|
||||
const { idMap, idUser } = req.query;
|
||||
|
||||
if (!idMap || !idUser) {
|
||||
return res.status(400).json({ error: "idMap and idUser are required" });
|
||||
}
|
||||
|
||||
try {
|
||||
let onlySystem = -1;
|
||||
let districtCounter = 0;
|
||||
|
||||
// Get onlySystem
|
||||
const [mapResult] = await pool.query("SELECT idsystem_typ FROM maps WHERE id = ?", [idMap]);
|
||||
if (mapResult.length > 0) {
|
||||
onlySystem = mapResult[0].idsystem_typ ?? -1;
|
||||
}
|
||||
|
||||
// Get districtCounter
|
||||
if (idUser > 0) {
|
||||
const [userLayerResult] = await pool.query("SELECT count(*) as count FROM user_User_layer1 WHERE iduser = ?", [idUser]);
|
||||
districtCounter = userLayerResult[0].count;
|
||||
}
|
||||
|
||||
// Building the query
|
||||
let query = `
|
||||
SELECT ld.idLD, dc.message, p.level, p.name, p.color, ld.idDevice, de.isService, dc.idIcon
|
||||
FROM location as l
|
||||
LEFT JOIN location_coordinates AS co ON l.idLocation = co.idLocation and co.idMaps = ?
|
||||
LEFT JOIN location_device AS ld ON ld.idLocation = l.idLocation
|
||||
LEFT JOIN datapoint as d ON d.idLD = ld.idLD
|
||||
LEFT JOIN datapoint_conditions AS dc ON dc.idcondition = d.last_message_condition
|
||||
LEFT JOIN prio AS p ON p.idPrio = dc.idprio
|
||||
LEFT JOIN devices AS de ON de.idDevice = ld.idDevice
|
||||
LEFT JOIN area as a on a.idArea = l.idArea
|
||||
WHERE p.level < 100 AND co.X > 0
|
||||
`;
|
||||
|
||||
const queryParams = [idMap];
|
||||
if (districtCounter > 0) {
|
||||
query += ` AND a.iddistrict IN (SELECT iddistrict FROM user_user_layer1 WHERE iduser = ?)`;
|
||||
queryParams.push(idUser);
|
||||
}
|
||||
if (onlySystem >= 0) {
|
||||
query += ` AND de.idsystem_typ = ?`;
|
||||
queryParams.push(onlySystem);
|
||||
}
|
||||
query += ` ORDER BY p.level desc`;
|
||||
|
||||
const [results] = await pool.query(query, queryParams);
|
||||
|
||||
const mpss = {
|
||||
IdMap: idMap.toString(),
|
||||
Statis: results.map((row) => ({
|
||||
IdLD: row.idLD ?? -1,
|
||||
Le: row.level ?? -1,
|
||||
Me: row.message ?? "?",
|
||||
Na: row.name ?? "?",
|
||||
Co: row.color ?? "#ffffff",
|
||||
Feld: row.idDevice ?? -1,
|
||||
Icon: row.idIcon ?? 0,
|
||||
})),
|
||||
};
|
||||
|
||||
res.status(200).json(mpss);
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Laden der Daten:", error);
|
||||
res.status(500).json({ error: "Interner Serverfehler" });
|
||||
}
|
||||
}
|
||||
273
pages/api - Kopie/talas5/webserviceMap/GisSystemStatic.js
Normal file
273
pages/api - Kopie/talas5/webserviceMap/GisSystemStatic.js
Normal file
@@ -0,0 +1,273 @@
|
||||
// /pages/api/webServiceMap.js
|
||||
const gisSystemStatic = {
|
||||
"Name": "Liste aller angezeigten Systeme",
|
||||
"Zeitstempel": "2024-05-31T15:08:49.8599542+02:00",
|
||||
"IdMap": "10",
|
||||
"Systems": [
|
||||
{
|
||||
"IdSystem": 1,
|
||||
"Name": "TALAS",
|
||||
"Longname": "Talas Meldestationen",
|
||||
"Allow": 1,
|
||||
"Icon": 1
|
||||
},
|
||||
{
|
||||
"IdSystem": 2,
|
||||
"Name": "ECI",
|
||||
"Longname": "ECI Geräte",
|
||||
"Allow": 1,
|
||||
"Icon": 2
|
||||
},
|
||||
{
|
||||
"IdSystem": 5,
|
||||
"Name": "GSM Modem",
|
||||
"Longname": "LR77 GSM Modems",
|
||||
"Allow": 1,
|
||||
"Icon": 5
|
||||
},
|
||||
{
|
||||
"IdSystem": 6,
|
||||
"Name": "Cisco Router",
|
||||
"Longname": "Cisco Router",
|
||||
"Allow": 1,
|
||||
"Icon": 6
|
||||
},
|
||||
{
|
||||
"IdSystem": 7,
|
||||
"Name": "WAGO",
|
||||
"Longname": "WAGO I/O Systeme",
|
||||
"Allow": 1,
|
||||
"Icon": 7
|
||||
},
|
||||
{
|
||||
"IdSystem": 8,
|
||||
"Name": "Siemens",
|
||||
"Longname": "Siemens Notrufsystem",
|
||||
"Allow": 0,
|
||||
"Icon": 8
|
||||
},
|
||||
{
|
||||
"IdSystem": 9,
|
||||
"Name": "OTDR",
|
||||
"Longname": "Glasfaserüberwachung OTU",
|
||||
"Allow": 0,
|
||||
"Icon": 9
|
||||
},
|
||||
{
|
||||
"IdSystem": 10,
|
||||
"Name": "WDM",
|
||||
"Longname": " Wavelength Division Multiplexing",
|
||||
"Allow": 0,
|
||||
"Icon": 10
|
||||
},
|
||||
{
|
||||
"IdSystem": 11,
|
||||
"Name": "GMA",
|
||||
"Longname": "Glättemeldeanlagen",
|
||||
"Allow": 1,
|
||||
"Icon": 11
|
||||
},
|
||||
{
|
||||
"IdSystem": 13,
|
||||
"Name": "Messstellen",
|
||||
"Longname": "Messstellen",
|
||||
"Allow": 0,
|
||||
"Icon": 13
|
||||
},
|
||||
{
|
||||
"IdSystem": 100,
|
||||
"Name": "TALAS ICL",
|
||||
"Longname": "Talas ICL Unterstationen",
|
||||
"Allow": 1,
|
||||
"Icon": 100
|
||||
},
|
||||
{
|
||||
"IdSystem": 110,
|
||||
"Name": "DAUZ",
|
||||
"Longname": "Dauerzählstellen",
|
||||
"Allow": 1,
|
||||
"Icon": 110
|
||||
},
|
||||
{
|
||||
"IdSystem": 111,
|
||||
"Name": "SMS-Funkmodem",
|
||||
"Longname": "SMS-Funkmodem",
|
||||
"Allow": 0,
|
||||
"Icon": 111
|
||||
},
|
||||
{
|
||||
"IdSystem": 200,
|
||||
"Name": "Sonstige",
|
||||
"Longname": "Sonstige",
|
||||
"Allow": 1,
|
||||
"Icon": 200
|
||||
}
|
||||
],
|
||||
"Rights": [
|
||||
{
|
||||
"IdRight": 1
|
||||
},
|
||||
{
|
||||
"IdRight": 2
|
||||
},
|
||||
{
|
||||
"IdRight": 3
|
||||
},
|
||||
{
|
||||
"IdRight": 5
|
||||
},
|
||||
{
|
||||
"IdRight": 6
|
||||
},
|
||||
{
|
||||
"IdRight": 7
|
||||
},
|
||||
{
|
||||
"IdRight": 8
|
||||
},
|
||||
{
|
||||
"IdRight": 10
|
||||
},
|
||||
{
|
||||
"IdRight": 11
|
||||
},
|
||||
{
|
||||
"IdRight": 12
|
||||
},
|
||||
{
|
||||
"IdRight": 20
|
||||
},
|
||||
{
|
||||
"IdRight": 22
|
||||
},
|
||||
{
|
||||
"IdRight": 23
|
||||
},
|
||||
{
|
||||
"IdRight": 25
|
||||
},
|
||||
{
|
||||
"IdRight": 30
|
||||
},
|
||||
{
|
||||
"IdRight": 40
|
||||
},
|
||||
{
|
||||
"IdRight": 41
|
||||
},
|
||||
{
|
||||
"IdRight": 42
|
||||
},
|
||||
{
|
||||
"IdRight": 43
|
||||
},
|
||||
{
|
||||
"IdRight": 44
|
||||
},
|
||||
{
|
||||
"IdRight": 45
|
||||
},
|
||||
{
|
||||
"IdRight": 46
|
||||
},
|
||||
{
|
||||
"IdRight": 47
|
||||
},
|
||||
{
|
||||
"IdRight": 48
|
||||
},
|
||||
{
|
||||
"IdRight": 49
|
||||
},
|
||||
{
|
||||
"IdRight": 50
|
||||
},
|
||||
{
|
||||
"IdRight": 51
|
||||
},
|
||||
{
|
||||
"IdRight": 52
|
||||
},
|
||||
{
|
||||
"IdRight": 55
|
||||
},
|
||||
{
|
||||
"IdRight": 56
|
||||
},
|
||||
{
|
||||
"IdRight": 60
|
||||
},
|
||||
{
|
||||
"IdRight": 61
|
||||
},
|
||||
{
|
||||
"IdRight": 62
|
||||
},
|
||||
{
|
||||
"IdRight": 63
|
||||
},
|
||||
{
|
||||
"IdRight": 64
|
||||
},
|
||||
{
|
||||
"IdRight": 65
|
||||
},
|
||||
{
|
||||
"IdRight": 68
|
||||
},
|
||||
{
|
||||
"IdRight": 69
|
||||
},
|
||||
{
|
||||
"IdRight": 70
|
||||
},
|
||||
{
|
||||
"IdRight": 71
|
||||
},
|
||||
{
|
||||
"IdRight": 72
|
||||
},
|
||||
{
|
||||
"IdRight": 73
|
||||
},
|
||||
{
|
||||
"IdRight": 79
|
||||
},
|
||||
{
|
||||
"IdRight": 80
|
||||
},
|
||||
{
|
||||
"IdRight": 90
|
||||
},
|
||||
{
|
||||
"IdRight": 93
|
||||
},
|
||||
{
|
||||
"IdRight": 94
|
||||
},
|
||||
{
|
||||
"IdRight": 95
|
||||
},
|
||||
{
|
||||
"IdRight": 96
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// Export an async function handler for the API route.
|
||||
export default async function handler(req, res) {
|
||||
// Initialize an empty params object to store query parameters.
|
||||
const params = {
|
||||
idMap: req.query.idMap,
|
||||
idUser: req.query.idUser
|
||||
};
|
||||
|
||||
// Check if the requested ID map and user match certain conditions.
|
||||
if (params.idMap === '10' && params.idUser === '484') {
|
||||
// If the conditions are met, return the gisSystemStatic object with a 200 status code.
|
||||
res.status(200).json(gisSystemStatic);
|
||||
} else {
|
||||
// If not, return a 404 error with the message "Not Found".
|
||||
res.status(404).send('Not Found');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,74 @@
|
||||
// /pages/api/talas5/webserviceMap/gisStationsMeasurementsSQL.js
|
||||
import mysql from "mysql2";
|
||||
|
||||
// Erstellen eines Pools von Datenbankverbindungen
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
port: process.env.DB_PORT,
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
queueLimit: 0,
|
||||
});
|
||||
|
||||
pool.on("connection", function (connection) {
|
||||
console.log("Database connected successfully.");
|
||||
});
|
||||
|
||||
pool.on("error", function (err) {
|
||||
console.error("Fehler beim Verbinden:", err);
|
||||
});
|
||||
|
||||
export default function handler(req, res) {
|
||||
const idMap = req.query.idMap;
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Nur GET Methode erlaubt" });
|
||||
}
|
||||
|
||||
const sqlQuery = `
|
||||
SELECT
|
||||
ld.idLD,
|
||||
dp.idDP,
|
||||
dp.name AS Na,
|
||||
dp.value AS Val,
|
||||
dp.unit AS Unit,
|
||||
mg.name AS Gr,
|
||||
ld.idLocation,
|
||||
area.Name AS Area_Name
|
||||
FROM location_device as ld
|
||||
LEFT JOIN location_coordinates AS co ON ld.idLocation = co.idLocation and co.idMaps = ?
|
||||
LEFT JOIN devices AS de ON de.idDevice = ld.idDevice
|
||||
LEFT JOIN datapoint AS dp ON ld.idLD = dp.idLD
|
||||
LEFT JOIN message_group AS mg ON dp.idmessage_group = mg.idmessage_group
|
||||
LEFT JOIN location AS loc ON ld.idLocation = loc.idLocation
|
||||
LEFT JOIN area AS area ON loc.idArea = area.idArea
|
||||
WHERE co.X > 0 AND dp.idmessage_group>0 AND length(dp.unit)> 0 AND length(dp.value)> 0
|
||||
`;
|
||||
|
||||
pool.query(sqlQuery, [idMap], (error, results) => {
|
||||
if (error) {
|
||||
console.error("Fehler beim Abrufen der gis_lines:", error);
|
||||
return res.status(500).json({ error: "Fehler beim Abrufen der gis_lines" });
|
||||
}
|
||||
|
||||
const response = {
|
||||
Name: "Liste aller Messungen der Geraete",
|
||||
Zeitstempel: new Date().toISOString(),
|
||||
IdMap: idMap,
|
||||
Statis: results.map((row) => ({
|
||||
IdLD: row.idLD,
|
||||
IdDP: row.idDP,
|
||||
Na: row.Na,
|
||||
Val: row.Val,
|
||||
Unit: row.Unit,
|
||||
Gr: row.Gr,
|
||||
IdLocation: row.idLocation,
|
||||
Area_Name: row.Area_Name,
|
||||
})),
|
||||
};
|
||||
|
||||
res.json(response);
|
||||
});
|
||||
}
|
||||
34
pages/api - Kopie/talas_v5_DB/gisLines/readGisLines.js
Normal file
34
pages/api - Kopie/talas_v5_DB/gisLines/readGisLines.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// /pages/api/talas_v5_DB/gisLines/readGisLines.js
|
||||
import mysql from "mysql2/promise";
|
||||
|
||||
// Erstellen eines Pools von Datenbankverbindungen
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
port: process.env.DB_PORT,
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
queueLimit: 0,
|
||||
});
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Nur GET Methode erlaubt" });
|
||||
}
|
||||
|
||||
const query = "SELECT * FROM talas_v5.gis_lines;";
|
||||
|
||||
try {
|
||||
const [results] = await pool.query(query);
|
||||
if (results.length > 0) {
|
||||
res.status(200).json(results);
|
||||
} else {
|
||||
res.status(404).json({ error: "Gerät nicht gefunden" });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Abrufen der gis_lines:", error);
|
||||
res.status(500).json({ error: "Fehler beim Abrufen der gis_lines" });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import mysql from "mysql2/promise";
|
||||
|
||||
// Erstellen eines Pools von Datenbankverbindungen
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
port: process.env.DB_PORT,
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
queueLimit: 0,
|
||||
});
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method !== "POST") {
|
||||
return res.status(405).json({ error: "Nur POST Methode erlaubt" });
|
||||
}
|
||||
|
||||
const { idLD, idModul, newCoordinates } = req.body;
|
||||
if (!idLD || !idModul || !newCoordinates) {
|
||||
return res.status(400).json({ error: "Fehlende Daten" });
|
||||
}
|
||||
|
||||
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 = ?;";
|
||||
|
||||
let connection;
|
||||
|
||||
try {
|
||||
// Hole eine Verbindung aus dem Pool
|
||||
connection = await pool.getConnection();
|
||||
|
||||
// Beginne eine Transaktion
|
||||
await connection.beginTransaction();
|
||||
|
||||
// Führe die Abfrage aus
|
||||
const [results] = await connection.query(query, [newLineString, idLD, idModul]);
|
||||
|
||||
// Commit der Transaktion
|
||||
await connection.commit();
|
||||
|
||||
console.log("Transaction Complete.");
|
||||
res.status(200).json({
|
||||
success: "Updated successfully.",
|
||||
affectedRows: results.affectedRows,
|
||||
});
|
||||
} catch (error) {
|
||||
// Rollback im Falle eines Fehlers
|
||||
if (connection) await connection.rollback();
|
||||
console.error("Fehler beim Aktualisieren der gis_lines:", error);
|
||||
res.status(500).json({ error: "Fehler beim Aktualisieren der gis_lines" });
|
||||
} finally {
|
||||
// Stelle sicher, dass die Verbindung zurückgegeben wird
|
||||
if (connection) connection.release();
|
||||
}
|
||||
}
|
||||
41
pages/api - Kopie/talas_v5_DB/locationDevice/getDeviceId.js
Normal file
41
pages/api - Kopie/talas_v5_DB/locationDevice/getDeviceId.js
Normal file
@@ -0,0 +1,41 @@
|
||||
// API in /api/talas_v5_DB/locationDevice/getDeviceId.js
|
||||
import mysql from "mysql2/promise";
|
||||
|
||||
// Erstellen eines Pools von Datenbankverbindungen
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
port: process.env.DB_PORT,
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
queueLimit: 0,
|
||||
});
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Nur GET Methode erlaubt" });
|
||||
}
|
||||
|
||||
const { deviceName } = req.query;
|
||||
|
||||
if (!deviceName) {
|
||||
return res.status(400).json({ error: "deviceName ist erforderlich" });
|
||||
}
|
||||
|
||||
const query = "SELECT idLD FROM location_device WHERE name = ?";
|
||||
|
||||
try {
|
||||
// Ausführen der Abfrage mit dem Pool
|
||||
const [results] = await pool.query(query, [deviceName]);
|
||||
if (results.length > 0) {
|
||||
res.status(200).json({ idLD: results[0].idLD });
|
||||
} else {
|
||||
res.status(404).json({ error: "Gerät nicht gefunden" });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Abrufen der Geräte-ID:", error);
|
||||
res.status(500).json({ error: "Fehler beim Abrufen der Geräte-ID" });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
// API in /api/talas_v5_DB/locationDevice/locationDeviceNameById.js
|
||||
import mysql from "mysql2/promise";
|
||||
|
||||
// Erstellen eines Pools von Datenbankverbindungen
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
port: process.env.DB_PORT,
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
queueLimit: 0,
|
||||
});
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Nur GET Methode erlaubt" });
|
||||
}
|
||||
|
||||
const { idLD } = req.query;
|
||||
|
||||
if (!idLD) {
|
||||
return res.status(400).json({ error: "idLD ist erforderlich" });
|
||||
}
|
||||
|
||||
try {
|
||||
const query = "SELECT name FROM location_device WHERE idLD = ?";
|
||||
const [results] = await pool.query(query, [idLD]);
|
||||
|
||||
if (results.length > 0) {
|
||||
res.status(200).json({ name: results[0].name });
|
||||
} else {
|
||||
res.status(404).json({ error: "Gerät nicht gefunden", idLD });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Abrufen des Gerätenamens:", error);
|
||||
res.status(500).json({ error: "Fehler beim Abrufen des Gerätenamens" });
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
// API in /api/talas_v5_DB/locationDevice/locationDevices.js
|
||||
import mysql from "mysql2/promise";
|
||||
|
||||
// Erstellen eines Pools von Datenbankverbindungen
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASSWORD,
|
||||
database: process.env.DB_NAME,
|
||||
port: process.env.DB_PORT,
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
queueLimit: 0,
|
||||
});
|
||||
|
||||
export default async function handler(req, res) {
|
||||
if (req.method !== "GET") {
|
||||
return res.status(405).json({ error: "Nur GET Methode erlaubt" });
|
||||
}
|
||||
|
||||
const query = "SELECT * FROM location_device WHERE iddevice = 160";
|
||||
|
||||
try {
|
||||
// Ausführen der Abfrage mit dem Verbindungspool
|
||||
const [results] = await pool.query(query);
|
||||
|
||||
res.status(200).json(results);
|
||||
} catch (error) {
|
||||
console.error("Fehler beim Abrufen der Geräteinformationen:", error);
|
||||
res.status(500).json({ error: "Fehler beim Abrufen der Geräteinformationen" });
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user