diff --git a/.env.local b/.env.local index 47b80a1b6..3b762466f 100644 --- a/.env.local +++ b/.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/ \ No newline at end of file + +######################### +#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" \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..0b2f36155 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "printWidth": 250 +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1 @@ +{} diff --git a/Jenkinsfile b/Jenkinsfile index 3e8762fab..5633ee135 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -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 ... } } diff --git a/NodeMap.pdf b/NodeMap.pdf new file mode 100644 index 000000000..423f61acf Binary files /dev/null and b/NodeMap.pdf differ diff --git a/Wiki.md b/Wiki.md index 8b157b905..49c6ae9aa 100644 --- a/Wiki.md +++ b/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 diff --git a/__mocks__/leaflet.js b/__mocks__/leaflet.js index 9a04eb751..2ef6e4a0a 100644 --- a/__mocks__/leaflet.js +++ b/__mocks__/leaflet.js @@ -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: ` + + + + + `, + iconSize: [18, 18], + iconAnchor: [9, 10], + }; + }, }; + +L.DivIcon.prototype = { + constructor: L.DivIcon, +}; + +module.exports = L; diff --git a/__tests__/unit/components/DataSheet.test.js b/__tests__/unit/components/DataSheet.test.js new file mode 100644 index 000000000..f390de883 --- /dev/null +++ b/__tests__/unit/components/DataSheet.test.js @@ -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( + + + + ); + + // 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( + + + + ); + 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( + + + + ); + 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(); + }); + + //-------------------------------------------------------------------------------- +}); diff --git a/__tests__/unit/components/MapComponent.test.js b/__tests__/unit/components/MapComponent.test.js new file mode 100644 index 000000000..ea9be1af6 --- /dev/null +++ b/__tests__/unit/components/MapComponent.test.js @@ -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. +*/ diff --git a/__tests__/unit/components/gisPolylines/icons/CircleIcon.test.js b/__tests__/unit/components/gisPolylines/icons/CircleIcon.test.js new file mode 100644 index 000000000..efc9e485e --- /dev/null +++ b/__tests__/unit/components/gisPolylines/icons/CircleIcon.test.js @@ -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: '
', + iconSize: [25, 25], + iconAnchor: [5, 5], + }), + }) + ); + expect(CircleIcon.options.className).toContain("custom-circle-icon"); + expect(CircleIcon.options.html).toContain(" { + 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("
"); + expect(EndIcon.options.iconSize).toEqual([14, 14]); + expect(EndIcon.options.iconAnchor).toEqual([7, 7]); + }); +}); diff --git a/__tests__/unit/components/gisPolylines/icons/StartIcon.test.js b/__tests__/unit/components/gisPolylines/icons/StartIcon.test.js new file mode 100644 index 000000000..2769119ea --- /dev/null +++ b/__tests__/unit/components/gisPolylines/icons/StartIcon.test.js @@ -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(" { + 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 + ); + }); +}); diff --git a/__tests__/unit/pois/AddPoiModalWindow.test.js b/__tests__/unit/pois/AddPoiModalWindow.test.js new file mode 100644 index 000000000..5a95b654f --- /dev/null +++ b/__tests__/unit/pois/AddPoiModalWindow.test.js @@ -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( + + + + ); + }); + + // Ü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 + }); + }); +}); diff --git a/__tests__/unit/pois/AddPoiModalWindowPopup.test.js b/__tests__/unit/pois/AddPoiModalWindowPopup.test.js new file mode 100644 index 000000000..e55327219 --- /dev/null +++ b/__tests__/unit/pois/AddPoiModalWindowPopup.test.js @@ -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 }) => ( +
+ + +
+ Coordinates: {latlng.lat}, {latlng.lng} +
+
+)); + +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(); + + 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(); + + expect(screen.queryByTestId("add-poi-modal-window")).not.toBeInTheDocument(); + }); + + test("closes the popup when the top right close button is clicked", () => { + render(); + + // 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(); + + 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(); + + // Click the "Close Modal" button inside the mock + fireEvent.click(screen.getByText("Close Modal")); + expect(closePopupMock).toHaveBeenCalledTimes(0); // Should not call the popup close + }); +}); diff --git a/__tests__/unit/pois/AddPoiModalWindowWrapper.test.js b/__tests__/unit/pois/AddPoiModalWindowWrapper.test.js new file mode 100644 index 000000000..c8fddf41b --- /dev/null +++ b/__tests__/unit/pois/AddPoiModalWindowWrapper.test.js @@ -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 }) => ( +
+ + +
+ Mocked Coordinates: {latlng.lat}, {latlng.lng} +
+
+)); + +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(); + + // 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(); + + // 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(); + + // Click the close button + fireEvent.click(screen.getByRole("button", { name: "Close" })); + expect(onCloseMock).toHaveBeenCalledTimes(1); + }); + + test("calls onClose when the background is clicked", () => { + render(); + + // 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(); + + // Click the modal content + fireEvent.click(screen.getByRole("dialog")); + expect(onCloseMock).toHaveBeenCalledTimes(0); + }); + + test("calls handleAddStation when the submit button is clicked", () => { + render(); + + // Click the submit button + fireEvent.click(screen.getByText("Mocked Submit")); + expect(handleAddStationMock).toHaveBeenCalledTimes(1); + }); +}); diff --git a/__tests__/unit/pois/PoiUpdateModal.test.js b/__tests__/unit/pois/PoiUpdateModal.test.js new file mode 100644 index 000000000..b99db4dfd --- /dev/null +++ b/__tests__/unit/pois/PoiUpdateModal.test.js @@ -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(); + }); + + 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(); + }); + + 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(); + }); + + 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(); + }); + + fireEvent.click(screen.getByLabelText("Close")); + + expect(mockOnClose).toHaveBeenCalledTimes(1); + }); +}); diff --git a/__tests__/unit/pois/PoiUpdateModalWindow.test.js b/__tests__/unit/pois/PoiUpdateModalWindow.test.js new file mode 100644 index 000000000..8ad912330 --- /dev/null +++ b/__tests__/unit/pois/PoiUpdateModalWindow.test.js @@ -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 }) => ( +
+ +
POI Data: {poiData ? poiData.name : "No Data"}
+
LatLng: {latlng ? `${latlng.lat}, ${latlng.lng}` : "No Coordinates"}
+
+)); + +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(); + + // 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(); + + // 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(); + + // Click the close button + screen.getByText("Close").click(); + expect(closePoiUpdateModalMock).toHaveBeenCalledTimes(1); + }); +}); diff --git a/__tests__/unit/pois/PoiUpdateModalWrapper.test.js b/__tests__/unit/pois/PoiUpdateModalWrapper.test.js new file mode 100644 index 000000000..034550342 --- /dev/null +++ b/__tests__/unit/pois/PoiUpdateModalWrapper.test.js @@ -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(); + }); + + // 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(); + + // 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(); + }); + + // Simulate closing the modal + fireEvent.click(screen.getByLabelText("Close")); + expect(mockOnClose).toHaveBeenCalledTimes(1); + }); +}); diff --git a/__tests__/unit/pois/PoiUtils.test.js b/__tests__/unit/pois/PoiUtils.test.js new file mode 100644 index 000000000..85bafff99 --- /dev/null +++ b/__tests__/unit/pois/PoiUtils.test.js @@ -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"); + }); + }); +}); diff --git a/__tests__/unit/utils/mapUtils.test.js b/__tests__/unit/utils/mapUtils.test.js new file mode 100644 index 000000000..b72a59f6f --- /dev/null +++ b/__tests__/unit/utils/mapUtils.test.js @@ -0,0 +1,6 @@ +// __tests__/utils/mapUtils.test.js +describe("Dummy test suite", () => { + test("dummy test", () => { + expect(true).toBe(true); + }); +}); diff --git a/components/DataSheet.js b/components/DataSheet.js index b3181a7d5..c707c7e33 100644 --- a/components/DataSheet.js +++ b/components/DataSheet.js @@ -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 ( -
+
-
- {stationListing.map((station) => ( ))} - Expand +
+ + Expand +
-
+ + {/* Checkboxen in einem gemeinsamen Container */} +
{systemListing.map((system) => ( - handleCheckboxChange(system.name, e)} - /> - -
+
+ handleCheckboxChange(system.name, e)} id={`system-${system.id}`} /> + +
))} - { - const checked = e.target.checked; - setPoiVisible(checked); - console.log( - `POIs sind jetzt ${checked ? "sichtbar" : "nicht sichtbar"}.` - ); - }} - /> - + +
+ + +
+ +
+ + +
diff --git a/components/EditModeToggle.js b/components/EditModeToggle.js new file mode 100644 index 000000000..289a5e8fc --- /dev/null +++ b/components/EditModeToggle.js @@ -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 ( +
+ {editMode ? ( + + + + ) : ( + + + + )} +
+ ); +} + +export default EditModeToggle; diff --git a/components/MapComponent.js b/components/MapComponent.js index 4b88cfd0f..99460c2ec 100644 --- a/components/MapComponent.js +++ b/components/MapComponent.js @@ -1,22 +1,11 @@ -// components/MapComponent.js -// test für Jenkins -import React, { - useEffect, - useRef, - useState, - useMemo, - useCallback, - use, -} from "react"; -import { MapContainer, TileLayer, Polyline, LayerGroup } from "react-leaflet"; - +// components/MapComponent.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 dynamic from "next/dynamic"; import "leaflet.smooth_marker_bouncing"; import OverlappingMarkerSpiderfier from "overlapping-marker-spiderfier-leaflet"; import DataSheet from "./DataSheet.js"; @@ -27,62 +16,175 @@ 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 ShowAddStationPopup from "./ShowAddStationPopup.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 "./PoiUpdateModal.js"; +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 { has, set } from "lodash"; -import { poiLayerVisibleState } from "../store/atoms/poiLayerVisible.js"; -import { data } from "autoprefixer"; +import { poiLayerVisibleState } from "../store/atoms/poiLayerVisibleState.js"; import plusRoundIcon from "./PlusRoundIcon.js"; -import {} from //parsePoint, -//handleEditPoi, -//insertNewMarker, -//redrawPolyline, -//saveLineData, -"../utils/utils.js"; import { parsePoint, findClosestPoints } from "../utils/geometryUtils.js"; -import { - //handleEditPoi, - insertNewMarker, - removeMarker, -} from "../utils/markerUtils.js"; -import { - saveLineData, - redrawPolyline, - restoreMapSettings, - checkOverlappingMarkers, -} from "../utils/mapUtils.js"; -import circleIcon from "./CircleIcon"; -import startIcon from "./StartIcon"; -import endIcon from "./EndIcon"; -import { - fetchGisStatusStations, - fetchPriorityConfig, - fetchPoiData, - updateLocationInDatabase, - checkInternet, - fetchUserRights, - fetchDeviceNameById, -} from "../services/apiService.js"; -import { - addContextMenuToMarker, - openInNewTab, -} from "../utils/contextMenuUtils.js"; -import { MAP_VERSION } from "../config/settings"; +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 useMapContextMenu from "./useMapContextMenu.js"; -import { openInSameWindow } from "../utils/openInSameWindow"; import { zoomIn, zoomOut, centerHere } from "../utils/zoomAndCenterUtils.js"; -//--------------------------------------------------------------------- -//-------------------- MapComponent ----------------------------------- +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 useLteModemMarkersLayer from "../hooks/layers/useLteModemMarkersLayer"; + +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"; +import useCreateAndSetDevices from "../hooks/useCreateAndSetDevices"; +//import { useCreateAndSetDevices } from "../hooks/useCreateAndSetDevices"; +import { useMapComponentState } from "../hooks/useMapComponentState"; +import { polylineEventsDisabledState } from "../store/atoms/polylineEventsDisabledState"; +import { disablePolylineEvents, enablePolylineEvents } from "../utils/setupPolylines"; +import { polylineLayerVisibleState } from "../store/atoms/polylineLayerVisibleState"; + const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { - const [loading, setLoading] = useState(true); // Ladezustand hinzufügen + const polylineVisible = useRecoilValue(polylineLayerVisibleState); + const [editMode, setEditMode] = useState(false); // editMode Zustand + const { deviceName, setDeviceName } = 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); + const [isRightsLoaded, setIsRightsLoaded] = useState(false); + const [hasRights, setHasRights] = useState(false); + const [mapId, setMapId] = useRecoilState(mapIdState); + const [userId, setUserId] = useRecoilState(userIdState); + const [AddPoiModalWindowState, setAddPoiModalWindowState] = useState(false); + const [userRights, setUserRights] = useState(null); + const setSelectedPoi = useSetRecoilState(selectedPoiState); + const [showPoiUpdateModal, setShowPoiUpdateModal] = useState(false); + const [currentPoiData, setCurrentPoiData] = useState(null); + const setCurrentPoi = useSetRecoilState(currentPoiState); + const [showVersionInfoModal, setShowVersionInfoModal] = useState(false); + const zoomTrigger = useRecoilValue(zoomTriggerState); + const [gisSystemStaticLoaded, setGisSystemStaticLoaded] = useState(false); + const [poiTypMap, setPoiTypMap] = useState(new Map()); + const [showPopup, setShowPopup] = useState(false); + const poiReadTrigger = useRecoilValue(poiReadFromDbTriggerAtom); + const poiLayerRef = useRef(null); // Referenz auf die Layer-Gruppe für Datenbank-Marker + const mapRef = useRef(null); // Referenz auf das DIV-Element der Karte + const [map, setMap] = useState(null); // Zustand der Karteninstanz + const [oms, setOms] = useState(null); // State für OMS-Instanz + const [GisStationsStaticDistrict, setGisStationsStaticDistrict] = useRecoilState(gisStationsStaticDistrictState); + const [GisStationsStatusDistrict, setGisStationsStatusDistrict] = useState([]); // Zustand für Statusdaten + const [GisStationsMeasurements, setGisStationsMeasurements] = useState([]); // Zustand für Messdaten + const [GisSystemStatic, setGisSystemStatic] = useRecoilState(gisSystemStaticState); // Zustand für Systemdaten + // Konstanten für die URLs + const mapGisStationsStaticDistrictUrl = config.mapGisStationsStaticDistrictUrl; + const mapGisStationsStatusDistrictUrl = config.mapGisStationsStatusDistrictUrl; + const mapGisStationsMeasurementsUrl = config.mapGisStationsMeasurementsUrl; + const mapGisSystemStaticUrl = config.mapGisSystemStaticUrl; + const webserviceGisLinesStatusUrl = config.webserviceGisLinesStatusUrl; + //console.log("priorityConfig in MapComponent1: ", priorityConfig); + /* + const talasMarkers = useTalasMarkersLayer(map, oms, GisSystemStatic, priorityConfig); // Use the new custom hook + const eciMarkers = useEciMarkersLayer(map, eciMarkers, oms, layers.MAP_LAYERS.ECI); + const gsmModemMarkers = useGsmModemMarkersLayer(map, oms, GisSystemStatic, priorityConfig); // Use the new custom hook + const ciscoRouterMarkers = useCiscoRouterMarkersLayer(map, oms, GisSystemStatic, priorityConfig); // Use the new custom hook + const wagoMarkers = useWagoMarkersLayer(map, oms, GisSystemStatic, priorityConfig); + const siemensMarkers = useSiemensMarkersLayer(map, oms, GisSystemStatic, priorityConfig); + const otdrMarkers = useOtdrMarkersLayer(map, oms, GisSystemStatic, priorityConfig); // Use the new custom hook + const wdmMarkers = useWdmMarkersLayer(map, oms, GisSystemStatic, priorityConfig); // Use the new custom hook + const messstellenMarkers = useMessstellenMarkersLayer(map, oms, GisSystemStatic, priorityConfig); // Use the new custom hook + const talasiclMarkers = useTalasiclMarkersLayer(map, oms, GisSystemStatic, priorityConfig); + const dauzMarkers = useDauzMarkersLayer(map, oms, GisSystemStatic, priorityConfig); // Use the new custom hook + const smsfunkmodemMarkers = useSmsfunkmodemMarkersLayer(map, oms, GisSystemStatic, priorityConfig); // Use the new custom hook + const ulafMarkers = useUlafMarkersLayer(map, oms, GisSystemStatic, priorityConfig); + const sonstigeMarkers = useSonstigeMarkersLayer(map, oms, GisSystemStatic, priorityConfig); // Use the new custom hook + */ + + const [gmaMarkers, setGmaMarkers] = useState([]); //--------------------station.System === 11 alle sind untetschiedlich Nummern + const [talasMarkers, setTalasMarkers] = useState([]); + const [eciMarkers, setEciMarkers] = useState([]); + const [gsmModemMarkers, setGsmModemMarkers] = useState([]); + const [ciscoRouterMarkers, setCiscoRouterMarkers] = useState([]); + const [wagoMarkers, setWagoMarkers] = useState([]); + const [siemensMarkers, setSiemensMarkers] = useState([]); + const [otdrMarkers, setOtdrMarkers] = useState([]); + const [wdmMarkers, setWdmMarkers] = useState([]); + const [messstellenMarkers, setMessstellenMarkers] = useState([]); + const [talasiclMarkers, setTalasiclMarkers] = useState([]); + const [dauzMarkers, setDauzMarkers] = useState([]); + const [smsfunkmodemMarkers, setSmsfunkmodemMarkers] = useState([]); + const [ulafMarkers, setUlafMarkers] = useState([]); + const [sonstigeMarkers, setSonstigeMarkers] = useState([]); + //const [lteModemMarkers, setLteModemMarkers] = useState([]); + + const [lineStatusData, setLineStatusData] = useState([]); + const [linesData, setLinesData] = useState([]); + const mapLayersVisibility = useRecoilValue(mapLayersState); + const selectedArea = useRecoilValue(selectedAreaState); + const poiData = useFetchPoiData("/api/talas_v5_DB/pois/poi-icons"); + const [linePositions, setLinePositions] = useState([]); + const { lineColors, tooltipContents } = useLineData(webserviceGisLinesStatusUrl, setLineStatusData); + const [polylines, setPolylines] = useState([]); + const [markers, setMarkers] = useState([]); + const closePopup = () => setShowPopup(false); + const [newPoint, setNewPoint] = useState(null); + const [newCoords, setNewCoords] = useState(null); + const [tempMarker, setTempMarker] = useState(null); + + const [popupCoordinates, setPopupCoordinates] = useState({ + lat: 52.52, + lng: 13.405, + }); + + const handleAddStation = (stationData) => { + setAddPoiModalWindowState(false); + closePopup(); // Schließt das Popup nach dem Hinzufügen + }; + + const openVersionInfoModal = () => { + setShowVersionInfoModal(true); + }; + + const closeVersionInfoModal = () => { + setShowVersionInfoModal(false); + }; + const [currentZoom, setCurrentZoom] = useState(() => { const storedZoom = localStorage.getItem("mapZoom"); return storedZoom ? parseInt(storedZoom, 10) : 12; @@ -97,264 +199,23 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { return [53.111111, 8.4625]; } }); + const [polylineEventsDisabled, setPolylineEventsDisabled] = useRecoilState(polylineEventsDisabledState); // Recoil State - const [priorityConfig, setPriorityConfig] = useState([]); + //--------------------------------------------------------------- - useEffect(() => { - fetchPriorityConfig(); - }, []); - - /* useEffect(() => { - console.log("Aktualisierte Prioritätskonfiguration:", priorityConfig); - }, [priorityConfig]); */ - //--------------------------------------------------------------------- - - useEffect(() => { + /* useEffect(() => { fetchGisStatusStations(12, 484); // Beispielaufruf mit idMap = 10 und idUser = 484 - }, []); - - //--------------------------------------------------------------------- - const [menuItemAdded, setMenuItemAdded] = useState(false); - - const poiLayerVisible = useRecoilValue(poiLayerVisibleState); - - const [contextMenuItems, setContextMenuItems] = useState([]); - const [isRightsLoaded, setIsRightsLoaded] = useState(false); - const [hasRights, setHasRights] = useState(false); - const [mapId, setMapId] = useRecoilState(mapIdState); - const [userId, setUserId] = useRecoilState(userIdState); - - const [showAddStationPopup, setShowAddStationPopup] = useState(false); - const [userRights, setUserRights] = useState(null); - const setSelectedPoi = useSetRecoilState(selectedPoiState); - const openPoiUpdateModal = () => setShowPoiUpdateModal(true); - const closePoiUpdateModal = () => setShowPoiUpdateModal(false); - const [showPoiUpdateModal, setShowPoiUpdateModal] = useState(false); - const [currentPoiData, setCurrentPoiData] = useState(null); - const setCurrentPoi = useSetRecoilState(currentPoiState); - const currentPoi = useRecoilValue(currentPoiState); - const handlePoiSelect = (poiData) => { - setSelectedPoi(poiData); // poiData should be the data of the selected POI - // Open the modal or any other logic - }; + }, []); */ useEffect(() => { const params = new URL(window.location.href).searchParams; setMapId(params.get("m")); setUserId(params.get("u")); }, [setMapId, setUserId]); - /* useEffect(() => { - fetchUserRights().then(() => { - setIsRightsLoaded(true); - console.log("Benutzerrechte in useEffect in MapComponent:", userRights); - }); - }, [urls.SERVER_URL]); // Lade die Berechtigungen beim Initialisieren der Komponente */ - - const [showVersionInfoModal, setShowVersionInfoModal] = useState(false); - const zoomTrigger = useRecoilValue(zoomTriggerState); - const offlineTileLayer = urls.OFFLINE_TILE_LAYER; - const onlineTileLayer = urls.ONLINE_TILE_LAYER; //Talas_v5 Server - - // Create map layers - const TALAS = layers.MAP_LAYERS.TALAS; - const ECI = layers.MAP_LAYERS.ECI; - const ULAF = layers.MAP_LAYERS.ULAF; - const GSMModem = layers.MAP_LAYERS.GSMModem; - const CiscoRouter = layers.MAP_LAYERS.CiscoRouter; - const WAGO = layers.MAP_LAYERS.WAGO; - const Siemens = layers.MAP_LAYERS.Siemens; - const OTDR = layers.MAP_LAYERS.OTDR; - const WDM = layers.MAP_LAYERS.WDM; - const GMA = layers.MAP_LAYERS.GMA; - const Sonstige = layers.MAP_LAYERS.Sonstige; - const TALASICL = layers.MAP_LAYERS.TALASICL; - const lineLayer = layers.MAP_LAYERS.lineLayer; - - const [gisSystemStaticLoaded, setGisSystemStaticLoaded] = useState(false); - - const baseUrl = urls.BASE_URL; // für Station öffnen in neuer tab und gleicher tab, im localhost gab es keine Probleme mit der Frame - - const [isPoiTypLoaded, setIsPoiTypLoaded] = useState(false); - const [poiTypMap, setPoiTypMap] = useState(new Map()); - const [showPopup, setShowPopup] = useState(false); - const [popupCoordinates, setPopupCoordinates] = useState({ - lat: 52.52, - lng: 13.405, - }); // Beispielkoordinaten - const openPopup = () => setShowPopup(true); - const closePopup = () => setShowPopup(false); - - const handleAddStation = (stationData) => { - // Station-Daten speichern oder API-Aufruf durchführen - //console.log("Neue Station:", userRights.includes(56)); - - //console.log("Neue Station:", stationData); - setShowAddStationPopup(false); - closePopup(); // Schließt das Popup nach dem Hinzufügen - }; - // Beispiel zum Öffnen des Popups mit bestimmten Koordinaten - const openAddStationPopupWithCoordinates = (lat, lng) => { - setPopupCoordinates({ lat, lng }); - setShowPopup(true); - }; - - const poiReadTrigger = useRecoilValue(poiReadFromDbTriggerAtom); - const [poiTypData, setPoiTypData] = useState(poiTypState); // Recoil State verwenden - const poiLayerRef = useRef(null); // Referenz auf die Layer-Gruppe für Datenbank-Marker - const mapRef = useRef(null); // Referenz auf das DIV-Element der Karte - const [map, setMap] = useState(null); // Zustand der Karteninstanz - const [oms, setOms] = useState(null); // State für OMS-Instanz - const [online, setOnline] = useState(navigator.onLine); // Zustand der Internetverbindung - const [GisStationsStaticDistrict, setGisStationsStaticDistrict] = - useRecoilState(gisStationsStaticDistrictState); - const [GisStationsStatusDistrict, setGisStationsStatusDistrict] = useState( - [] - ); // Zustand für Statusdaten - const [GisStationsMeasurements, setGisStationsMeasurements] = useState([]); // Zustand für Messdaten - const [GisSystemStatic, setGisSystemStatic] = - useRecoilState(gisSystemStaticState); // Zustand für Systemdaten - const [DataIcons, setDataIcons] = useState([]); // Zustand für Icon-Daten - - // Konstanten für die URLs - const mapGisStationsStaticDistrictUrl = - config.mapGisStationsStaticDistrictUrl; - const mapGisStationsStatusDistrictUrl = - config.mapGisStationsStatusDistrictUrl; - const mapGisStationsMeasurementsUrl = config.mapGisStationsMeasurementsUrl; - const mapGisSystemStaticUrl = config.mapGisSystemStaticUrl; - const mapDataIconUrl = config.mapDataIconUrl; - const webserviceGisLinesStatusUrl = config.webserviceGisLinesStatusUrl; - - const openVersionInfoModal = () => { - setShowVersionInfoModal(true); - }; - - const closeVersionInfoModal = () => { - setShowVersionInfoModal(false); - }; - //---------------------------------------------------- - //---------------------------------------------------- - // Kontextmenü Callback für "Reinzoomen" - const zoomInCallback = (e, map) => { - zoomIn(e, map); - }; - - // Kontextmenü Callback für "Rauszoomen" - const zoomOutCallback = (map) => { - zoomOut(map); - }; - - // Kontextmenü Callback für "Hier zentrieren" - const centerHereCallback = (e, map) => { - centerHere(e, map); - }; - //---------------------------------------------------- - //-----Kontextmenu---------------- - // Funktion zum Anzeigen der Koordinaten - const showCoordinates = (e) => { - alert( - "Breitengrad: " + - e.latlng.lat.toFixed(5) + - "\nLängengrad: " + - e.latlng.lng.toFixed(5) - ); - }; - const showData = (e) => {}; - const showTalas = (e) => { - map.addLayer(TALAS); - loadData(); - }; - const hideTalas = (e) => { - map.removeLayer(TALAS); - loadData(); - }; - const showGSM = (e) => { - map.addLayer(GMA); - loadData(); - }; - const hideGSM = (e) => { - map.removeLayer(GMA); - loadData(); - }; - - // Kontextmenü Callback für "POI hinzufügen" - const addStationCallback = useCallback((event, hasRights) => { - console.log( - "Überprüfung der Berechtigung in addStationCallback: ", - hasRights - ); - 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, - }); - console.error("Benutzer hat keine Berechtigung zum Hinzufügen."); - } - }); - - //-----Kontextmenu----ende------------ - - const addItemsToMapContextMenu = (hasRights) => { - if (!menuItemAdded && map) { - map.contextmenu.addItem({ - text: "Koordinaten anzeigen", - icon: "img/not_listed_location.png", - callback: showCoordinates, - }); - - map.contextmenu.addItem({ separator: true }); // Divider - - 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), - }); - - map.contextmenu.addItem({ separator: true }); // Another Divider - - map.contextmenu.addItem({ - text: "POI hinzufügen", - icon: "img/add_station.png", - className: "background-red", - callback: (event) => addStationCallback(event, hasRights), - }); - - setMenuItemAdded(true); // Menüpunkt wurde hinzugefült, Zustand aktualisieren - } - }; useEffect(() => { - if ( - map && - poiLayerRef.current && - isPoiTypLoaded && - !menuItemAdded && - isRightsLoaded - ) { - console.log( - "Überprüfung der Berechtigung vor addItemsToMapContextMenu: ", - hasRights - ); + if (map && poiLayerRef.current && isPoiTypLoaded && !menuItemAdded && isRightsLoaded) { + //console.log("Überprüfung der Berechtigung vor addItemsToMapContextMenu: ", hasRights); addItemsToMapContextMenu(hasRights); } }, [ @@ -369,614 +230,102 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { useEffect(() => { const fetchAndSetUserRights = async () => { const rights = await fetchUserRights(); - //console.log("Benutzerrechte in server URL:", rights); setUserRights(rights); setIsRightsLoaded(true); - setHasRights(rights && rights.includes(56)); // Prüfen, ob Benutzer die Rechte hat - //console.log("Benutzerrechte in useEffect in MapComponent:", rights); + + // Sicherstellen, dass `rights` ein Array ist, bevor `.includes()` aufgerufen wird + setHasRights(localStorage.getItem("editMode") && Array.isArray(rights) && rights.includes(56)); }; fetchAndSetUserRights(); - }, [urls.SERVER_URL]); // Lade die Berechtigungen beim Initialisieren der Komponente + }, []); - //---------------------------------------------------- - //------------------------------------------ */ - const layerNames = { - "GSM Modem": "GSMMODEM", - "Cisco Router": "CiscoRouter", - "TALAS ICL": "TALASICL", - "SMS-Funkmodem": "GSMModem", - }; - //------------------------------------------ */ - function fly(stationValue) { - var x = 51.41321407879154; - var y = 7.739617925303934; - var zoom = 7; + useGmaMarkersLayer(map, gmaMarkers, GisStationsMeasurements, layers.MAP_LAYERS.GMA, oms); // Verwende den ausgelagerten Hook - initMap.flyTo([x, y], zoom); - } - //------------------------------------------ - //------------------------------------------ - let initMap = []; - //----------------------------------------------------------------- - // TALAS Marker hinzufügen - //----------------------------------------------------------------- - // Reihenfolge nach API sortiert mit der Attribute "System" - const [talasVisible, setTalasVisible] = useRecoilState(mapLayersState); - const [eciVisible, setEciVisible] = useRecoilState(mapLayersState); - const [gsmModemVisible, setGsmModemVisible] = useRecoilState(mapLayersState); - const [ciscoRouterVisible, setCiscoRouterVisible] = - useRecoilState(mapLayersState); - const [wagoVisible, setWagoVisible] = useRecoilState(mapLayersState); - const [siemensVisible, setSiemensVisible] = useRecoilState(mapLayersState); - const [otdrVisible, setOtdrVisible] = useRecoilState(mapLayersState); - const [wdmVisible, setWdmVisible] = useRecoilState(mapLayersState); - const [gmaVisible, setGmaVisible] = useRecoilState(mapLayersState); - const [messstellenVisible, setMessstellenVisible] = - useRecoilState(mapLayersState); - const [talasiclVisible, setTalasiclVisible] = useRecoilState(mapLayersState); - const [dauzVisible, setDauzVisible] = useRecoilState(mapLayersState); - const [smsfunkmodemVisible, setSmsfunkmodemVisible] = - useRecoilState(mapLayersState); - const [sonstigeVisible, setSonstigeVisible] = useRecoilState(mapLayersState); - const [ulafVisible, setUlafVisible] = useRecoilState(mapLayersState); + useEffect(() => { + const fetchWebServiceMap = async () => { + try { + // Zähler für externe API-Aufrufe in localStorage speichern + let requestCount = localStorage.getItem("fetchWebServiceMap") || 0; + requestCount = parseInt(requestCount, 10); - const [talasMarkers, setTalasMarkers] = useState([]); //----------------station.System === 1 - const [eciMarkers, setEciMarkers] = useState([]); //--------------------station.System === 2 - const [gsmModemMarkers, setGsmModemMarkers] = useState([]); //----------station.System === 5 - const [ciscoRouterMarkers, setCiscoRouterMarkers] = useState([]); //----station.System === 6 - const [wagoMarkers, setWagoMarkers] = useState([]); //------------------station.System === 7 - const [siemensMarkers, setSiemensMarkers] = useState([]); //------------station.System === 8 - const [otdrMarkers, setOtdrMarkers] = useState([]); //------------------station.System === 9 - const [wdmMarkers, setWdmMarkers] = useState([]); //--------------------station.System === 10 - const [gmaMarkers, setGmaMarkers] = useState([]); //--------------------station.System === 11 - const [messstellenMarkers, setMessstellenMarkers] = useState([]); //----station.System === 13 - const [talasiclMarkers, setTalasiclMarkers] = useState([]); //----------station.System === 100 - const [dauzMarkers, setDauzMarkers] = useState([]); //------------------station.System === 110 - const [smsfunkmodemMarkers, setSmsfunkmodemMarkers] = useState([]); //--station.System === 111 - const [sonstigeMarkers, setSonstigeMarkers] = useState([]); //----------station.System === 200 - const [ulafMarkers, setUlafMarkers] = useState([]); //------------------ no exist - //-------------------------------------------------------------------------------- - const determinePriority = (iconPath) => { - for (let priority of priorityConfig) { - if (iconPath.includes(priority.name.toLowerCase())) { - return priority.level; + const fetchOptions = { + method: "GET", + headers: { + Connection: "close", // Keep-Alive-Header hinzufügen + }, + }; + + /* +await fetchGisStationsStaticDistrict(mapGisStationsStaticDistrictUrl, setGisStationsStaticDistrict, fetchOptions); +await fetchGisStationsStatusDistrict(mapGisStationsStatusDistrictUrl, setGisStationsStatusDistrict, fetchOptions); + await fetchGisStationsMeasurements(mapGisStationsMeasurementsUrl, setGisStationsMeasurements, fetchOptions); + await fetchGisSystemStatic(mapGisSystemStaticUrl, setGisSystemStatic, setGisSystemStaticLoaded, fetchOptions); + */ + // Fetch GIS Stations Static District + await fetchGisStationsStaticDistrict(mapGisStationsStaticDistrictUrl, setGisStationsStaticDistrict, fetchOptions); + requestCount++; // Zähler erhöhen + localStorage.setItem("fetchWebServiceMap", requestCount); + //console.log(`fetchWebServiceMap in MapComponent wurde ${requestCount} Mal aufgerufen.`); + + // Fetch GIS Stations Status District + await fetchGisStationsStatusDistrict(mapGisStationsStatusDistrictUrl, setGisStationsStatusDistrict, fetchOptions); + requestCount++; // Zähler erhöhen + localStorage.setItem("fetchWebServiceMap", requestCount); + //console.log(`fetchWebServiceMap in MapComponent wurde ${requestCount} Mal aufgerufen.`); + + // Fetch GIS Stations Measurements + await fetchGisStationsMeasurements(mapGisStationsMeasurementsUrl, setGisStationsMeasurements, fetchOptions); + requestCount++; // Zähler erhöhen + localStorage.setItem("fetchWebServiceMap", requestCount); + //console.log(`fetchWebServiceMap in MapComponent wurde ${requestCount} Mal aufgerufen.`); + + // Fetch GIS System Static + await fetchGisSystemStatic(mapGisSystemStaticUrl, setGisSystemStatic, setGisSystemStaticLoaded, fetchOptions); + requestCount++; // Zähler erhöhen + localStorage.setItem("fetchWebServiceMap", requestCount); + //console.log(`fetchWebServiceMap in MapComponent wurde ${requestCount} Mal aufgerufen.`); + } catch (error) { + console.error("Error fetching data:", error); } - } - return 5; // Default priority (lowest) - }; + }; - // Daten von einer externen Quelle laden - const createAndSetMarkers = async (systemId, setMarkersFunction) => { - try { - const response1 = await fetch(config.mapGisStationsStaticDistrictUrl); - const jsonResponse = await response1.json(); - const response2 = await fetch(config.mapGisStationsStatusDistrictUrl); - const statusResponse = await response2.json(); + fetchWebServiceMap(); + }, []); - const getIdSystemAndAllowValueMap = new Map( - GisSystemStatic.map((system) => [system.IdSystem, system.Allow]) - ); - //console.log("getIdSystemAndAllowValueMap:", getIdSystemAndAllowValueMap); + //-------------------------------------------------------- + useEffect(() => { + const endpoint = "/api/talas_v5_DB/gisLines/readGisLines"; + //const endpoint = "http://localhost/talas5/ClientData/WebServiceMap.asmx/GisLinesStatus?idMap=10"; + fetch(endpoint) + .then((response) => { + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + return response.json(); + }) + .then((data) => { + const newLinePositions = data.map((item) => { + //console.log("item.idLD", item.idLD); + //console.log("item.idModul", item.idModul); - if (jsonResponse.Points && statusResponse.Statis) { - const statisMap = new Map( - statusResponse.Statis.map((s) => [s.IdLD, s]) - ); - let markersData = jsonResponse.Points.filter( - (station) => - station.System === systemId && - getIdSystemAndAllowValueMap.get(station.System) === 1 - ).map((station) => { - const statis = statisMap.get(station.IdLD); - const iconPath = statis - ? `img/icons/${statis.Na}-marker-icon-${station.Icon}.png` - : `img/icons/marker-icon-${station.Icon}.png`; - - const priority = determinePriority(iconPath); - const zIndexOffset = 100 * (5 - priority); // Adjusted for simplicity and positive values - - /* console.log( - `Icon Path: ${iconPath}, Priority: ${priority}, zIndexOffset: ${zIndexOffset}` - ); */ - - const marker = L.marker([station.X, station.Y], { - icon: L.icon({ - iconUrl: iconPath, - iconSize: [25, 41], - iconAnchor: [12, 41], - popupAnchor: [1, -34], - }), - areaName: station.Area_Name, // Stelle sicher, dass dieser Bereich gesetzt wird - link: station.Link, - zIndexOffset: zIndexOffset, - bounceOnAdd: !!statis, - }); - - if (statis) { - marker.on("add", () => marker.bounce(3)); + if (item.points && Array.isArray(item.points)) { + return { + coordinates: item.points.map((point) => [point.x, point.y]), + idModul: item.idModul, + idLD: item.idLD, + }; + } else { + throw new Error("Points missing or not an array"); } - - const statusInfo = statusResponse.Statis.filter( - (status) => status.IdLD === station.IdLD - ) - .reverse() - .map( - (status) => ` -
-
- ${status.Me} (${status.Na}) -
- ` - ) - .join(""); - - marker.bindPopup(` -
- ${station.LD_Name} - ${station.Device}
- ${station.Area_Short} (${station.Area_Name})
- ${station.Location_Short} (${station.Location_Name}) -
${statusInfo}
-
- `); - - return marker; }); - - setMarkersFunction(markersData); - } - } catch (error) { - console.error("Error fetching data: ", error); - } - }; - //-------------------------------------------------------------------------------- - - const mapLayersVisibility = useRecoilValue(mapLayersState); - //---------------------------------------------- - const handleEditPoi = (selectedPoi) => { - // Prüfung, ob der Benutzer die notwendigen Rechte hat - if (!userRights || !userRights.includes(56)) { - toast.error("Benutzer hat keine Berechtigung zum Bearbeiten.", { - position: "top-center", - autoClose: 5000, - hideProgressBar: false, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - progress: undefined, + setLinePositions(newLinePositions); + }) + .catch((error) => { + console.error("Error fetching data:", error.message); }); - console.log("Benutzer hat keine Berechtigung zum Bearbeiten."); - return; // Beendet die Funktion frühzeitig, wenn keine Berechtigung vorliegt - } - - //console.log("Selected Marker ID (idPoi):", marker.options.idPoi); - console.log( - "Selected Marker Description:", - selectedPoi.options.description - ); - console.log("Selected Marker :", selectedPoi.options); - - setCurrentPoiData({ - idPoi: selectedPoi.options.id, - name: selectedPoi.options.name, - description: selectedPoi.options.description, - }); - //console.log("POI-Daten1:", currentPoiData); - - fetchPoiData(selectedPoi.options.id); - fetchPoiData(selectedPoi.options.name); - //fetchPoiData(selectedPoi.options); - - setShowPoiUpdateModal(true); - }; - //---------------------------------------------- - - //------------------------------------------ - //------------------------------------------ */ - const selectedArea = useRecoilValue(selectedAreaState); - const setSelectedArea = useSetRecoilState(selectedAreaState); - - // Combine all markers into a single array - const allMarkers = [ - ...talasMarkers, - ...eciMarkers, - ...gsmModemMarkers, - ...ciscoRouterMarkers, - ...wagoMarkers, - ...siemensMarkers, - ...otdrMarkers, - ...wdmMarkers, - ...gmaMarkers, - ...messstellenMarkers, - ...talasiclMarkers, - ...dauzMarkers, - ...smsfunkmodemMarkers, - ...sonstigeMarkers, - ...ulafMarkers, - ]; - - // Function to find a marker by areaName across all groups - const findMyMarker = (areaName) => { - return allMarkers.find((marker) => marker.options.areaName === areaName); - }; - //-------------------------------------------------------------- - //--------------------------------------------------------- - /* const handleMarkerClick = (markerData) => { - // Setze die aktuellen Daten im State, um sie im Formular vorzubelegen - setCurrentMarkerData(markerData); - setShowEditModal(true); - }; */ - // In der Marker-Erstellungsfunktion - //--------------------------------------------------------- - //----------------------------------------------------------- - // Funktion um die Benutzerrechte zu überprüfen - // serverIP 10.10.0.13 idMap=10 idUser=485 - - const url = new URL(window.location.href); - //const hostname = url.hostname; // Gibt den Hostnamen (IP oder Domain) zurück - //const port = url.port; // Gibt den Port zurück, leer wenn Standardport verwendet wird - //const protocol = url.protocol; // "http:" oder "https:" - - const serverURL = urls.SERVER_URL; // weil ich keine API habe, ansonsten serverURL ist localhost(IP-Adresse) für GisSystemStatic für die Benutzerrechte - - const params = new URL(window.location.href).searchParams; - - const c = params.get("m"); // Beispielwert für idMap - const user = params.get("u"); // Beispielwert für idUser - //console.log("serverURL:", serverURL); - useEffect(() => { - //console.log("Aktualisierter Status von hasRights: ", hasRights); - }, [hasRights]); // Dieser Effekt läuft jedes Mal, wenn sich `hasRights` ändert. - - // Überprüfen der Benutzerrechte beim Initialisieren der Komponente - /* useEffect(() => { - fetchUserRights(); - }, []); */ - /* useEffect(() => { - console.log( - "Server URL ist verfügbar:", - config.url.origin, - "idMap:", - config.idMap, - "idUser:", - config.idUser - ); - fetchUserRights().then((rights) => { - // console.log("Benutzerrechte in server URL:", rights); - setUserRights(rights); - setIsRightsLoaded(true); - setHasRights(rights && rights.includes(56)); // Prüfen, ob Benutzer die Rechte hat - console.log("Benutzerrechte in useEffect in MapComponent:", hasRights); - }); - }, []); */ - - // Anzeigen von Modals basierend auf Benutzerrechten - useEffect(() => { - if (userRights !== 56) { - setShowPoiUpdateModal(false); - setShowAddStationPopup(false); - } - }, [userRights]); - //----------------------------------------------------------- - //--------------------------------------------------------- - useEffect(() => { - //console.log("useEffect current Data:", currentPoiData); - }, [currentPoiData]); - //--------------------------------------------------------- - //------------------------------------------ - // API-Daten laden für GisStationsStaticDistrict - //http://10.10.0.13/talas5/ClientData/WebServiceMap.asmx/GisStationsStaticDistrict?idMap=10&idUser=485 - useEffect(() => { - const fetchData = async () => { - try { - const response = await fetch(mapGisStationsStaticDistrictUrl); - const jsonResponse = await response.json(); - - // Prüfen, ob die Antwort das erwartete Format hat und Daten enthält - if (jsonResponse && jsonResponse.Points) { - setGisStationsStaticDistrict(jsonResponse.Points); // Direkter Zugriff auf 'Points' - } else { - console.error( - 'Erwartete Daten im "Points"-Array nicht gefunden', - jsonResponse - ); - setGisStationsStaticDistrict([]); - } - } catch (error) { - console.error("Fehler beim Laden der Daten 1: ", error); - setGisStationsStaticDistrict([]); - } - }; - - fetchData(); - }, []); // Dependency-Array ist leer, um den Effekt nur beim Mount auszuführen - - //GisStationsStaticDistrict Daten laden - useEffect(() => { - const fetchData = async () => { - try { - const response = await fetch(mapGisStationsStaticDistrictUrl); - const jsonResponse = await response.json(); - - // Prüfen, ob die Antwort das erwartete Format hat und Daten enthält - if (jsonResponse && jsonResponse.Points) { - setGisStationsStaticDistrict(jsonResponse.Points); // Direkter Zugriff auf 'Points' - } else { - console.error( - 'Erwartete Daten im "Points"-Array nicht gefunden', - jsonResponse - ); - setGisStationsStaticDistrict([]); - } - } catch (error) { - console.error("Fehler beim Laden der Daten 1: ", error); - setGisStationsStaticDistrict([]); - } - }; - - fetchData(); - }, []); // Dependency-Array ist leer, um den Effekt nur beim Mount auszuführen - //------------------------------------------ - //GisStationsStatusDistrict Daten laden - useEffect(() => { - const fetchData = async () => { - try { - const response = await fetch(mapGisStationsStatusDistrictUrl); - const jsonResponse = await response.json(); - - // Prüfen, ob die Antwort das erwartete Format hat und Daten enthält - if (jsonResponse && jsonResponse.Statis) { - setGisStationsStatusDistrict(jsonResponse.Statis); // Direkter Zugriff auf 'Statis' - } else { - console.error( - 'Erwartete Daten im "Statis"-Array nicht gefunden', - jsonResponse - ); - setGisStationsStatusDistrict([]); - } - } catch (error) { - console.error("Fehler beim Laden der Daten 2: ", error); - setGisStationsStatusDistrict([]); - } - }; - - fetchData(); - }, []); // Dependency-Array ist leer, um den Effekt nur beim Mount auszuführen - //------------------------------------------ - //GisStationsMeasurements Daten laden - - useEffect(() => { - const fetchData = async () => { - try { - const response = await fetch(mapGisStationsMeasurementsUrl); - const jsonResponse = await response.json(); - - // Prüfen, ob die Antwort das erwartete Format hat und Daten enthält - if (jsonResponse && jsonResponse.Statis) { - setGisStationsMeasurements(jsonResponse.Statis); // Direkter Zugriff auf 'Statis' - } else { - console.error( - 'Erwartete Daten im "Statis"-Array nicht gefunden', - - jsonResponse - ); - setGisStationsMeasurements([]); - } - } catch (error) { - console.error("Fehler beim Laden der Daten 3: ", error); - setGisStationsMeasurements([]); - } - }; - - fetchData(); - }, []); // Dependency-Array ist leer, um den Effekt nur beim Mount auszuführen - //------------------------------------------ - - //GisSystemStatic Daten laden - useEffect(() => { - const fetchData = async () => { - try { - const response = await fetch(mapGisSystemStaticUrl); - const jsonResponse = await response.json(); - - if (jsonResponse && jsonResponse.Systems) { - setGisSystemStatic(jsonResponse.Systems); - setGisSystemStaticLoaded(true); // Setze den Zustand auf geladen - } else { - console.error( - 'Erwartete Daten im "Systems"-Array nicht gefunden', - jsonResponse - ); - setGisSystemStatic([]); - } - } catch (error) { - console.error("Fehler beim Laden der Daten 4: ", error); - setGisSystemStatic([]); - } - }; - - fetchData(); }, []); - //------------------------------------------ - - useEffect(() => { - if (typeof window !== "undefined") { - //console.log("Window height from config:", config.windowHeight); - } - }, []); - - // Initialisierung der karte und hinzuügen der Layers - useEffect(() => { - if (mapRef.current && !map) { - initMap = L.map(mapRef.current, { - //center: [53.111111, 8.4625], - center: currentCenter, - //zoom: 8, - zoom: currentZoom, - layers: [ - TALAS, - ECI, - ULAF, - GSMModem, - CiscoRouter, - WAGO, - Siemens, - OTDR, - WDM, - GMA, - Sonstige, - TALASICL, - ], - minZoom: 5, // Minimale Zoomstufe - maxZoom: 15, // Maximale Zoomstufe - zoomControl: false, - contextmenu: true, - contextmenuItems: [ - { - text: "Station öffnen (Tab)", - icon: "/img/screen_new.png", - callback: (e) => { - const clickedMarker = e.relatedTarget; // Zugriff auf den Marker, der das Event ausgelöst hat - openInNewTab(e, clickedMarker); - }, - }, - "-", // Divider - /* - { - text: "Koordinaten anzeigen", - icon: "img/not_listed_location.png", - callback: showCoordinates, - }, - "-", // Divider - { text: "Reinzoomen", icon: "img/zoom_in.png", callback: zoomIn }, - { - text: "Rauszoomen", - icon: "img/zoom_out.png", - callback: () => zoomOutCallback(map), - }, - { - text: "Hier zentrieren", - icon: "img/center_focus.png", - callback: (e) => centerHere(e, map), - }, - "-", // Divider */ - ], - }); - - L.tileLayer(online ? onlineTileLayer : offlineTileLayer, { - attribution: - '© OpenStreetMap contributors', - //tileSize: 250, // oder 512, je nach Kachelgröße - //detectRetina: true, - }).addTo(initMap); - - const overlappingMarkerSpiderfier = - new window.OverlappingMarkerSpiderfier(initMap, { - nearbyDistance: 20, - }); - - setMap(initMap); - setOms(overlappingMarkerSpiderfier); - - initMap.on("zoomend", function () { - // Überprüfen, ob der aktuelle Zoom außerhalb der Grenzen liegt - if (initMap.getZoom() > 15) { - initMap.setZoom(15); - } else if (initMap.getZoom() < 5) { - initMap.setZoom(5); - } - }); - - // Nach der Initialisierung der Map und Setzen im State kannst du Funktionen aufrufen, die `map` benötigen. - initMap.whenReady(() => { - console.log("Karte ist jetzt bereit und initialisiert."); - // Rufe hier Funktionen auf, die eine initialisierte Karte benötigen. - }); - } - //console.log("trigger in MapComponent.js:", poiReadTrigger); - }, [mapRef, map, poiReadTrigger, contextMenuItems]); // Prüfe die Abhängigkeiten sorgfältig - - /* const zoomIn = (e) => { - initMap.flyTo(e.latlng, 12); - //console.log("ZoomIn koordinaten in MapComponent", e.latlng); - }; - - const zoomOut = (e) => { - fly(); - }; - const centerHere = (e) => { - initMap.panTo(e.latlng); - }; */ - - /* useEffect(() => { - if (map) { - map.on("contextmenu", (e) => { - const contextMenuItems = [ - { - text: "Reinzoomen", - icon: "img/zoom_in.png", - callback: (e) => zoomIn(e, map), - }, - { - text: "Rauszoomen", - icon: "img/zoom_out.png", - callback: () => zoomOut(map), - }, - { - text: "Hier zentrieren", - icon: "img/center_focus.png", - callback: (e) => centerHere(e, map), - }, - "-", - ]; - L.DomEvent.stopPropagation(e); - const contextMenu = L.popup() - .setLatLng(e.latlng) - .setContent( - '
' + - contextMenuItems - .map( - (item) => - `${item.text}` - ) - .join("
") + - "
" - ) - .openOn(map); - }); - } - }, [map]); */ - - // poiTyp Daten hinzufügen - //------------------------------------------ - // Funktion zum Abrufen der poiTyp Daten - - useEffect(() => { - const fetchPoiTypData = async () => { - try { - const response = await fetch("/api/talas_v5_DB/poiTyp/readPoiTyp"); - const data = await response.json(); - setPoiTypData(data); // Daten im Recoil State speichern - } catch (error) { - console.error("Fehler beim Abrufen der poiTyp Daten:", error); - } - }; - /* console.log( - "trigger in MapComponent.js in fetchPoiTypData:", - poiReadTrigger - ); */ - fetchPoiTypData(); - }, []); - - // Effekt zum Loggen der poiTypData, wenn sie sich ändern - useEffect(() => { - //console.log("poiTypData aktualisiert:", poiTypData); - }, [poiTypData]); - - //--------------------------------------- - - // Funktion, um die name und idPoiTyp von `poiTyp` MySQL DB Tabelle in einer Map zu speichern + //-------------------------------------------- useEffect(() => { const fetchPoiTypData = async () => { try { @@ -985,98 +334,11 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { const map = new Map(); data.forEach((item) => map.set(item.idPoiTyp, item.name)); setPoiTypMap(map); - setIsPoiTypLoaded(true); // Daten wurden erfolgreich geladen - //console.log("poiTypMap:", map); - const poiTypName = poiTypMap.get(0) || "Unbekannt"; - //console.log("poiTypName:", poiTypName); } catch (error) { - console.error("Fehler beim Abrufen der poiTyp-Daten:", error); + console.error("Fehler beim Abrufen der poiTyp-Daten-1:", error); } }; - - fetchPoiTypData(); - }, []); - //------------------------------------------ - let dbLayer = null; - useEffect(() => { - if (map) { - // Schicht für Datenbank-Marker, sicherstellen, dass map nicht null ist - dbLayer = new L.LayerGroup().addTo(map); - - // Fügen Sie Ihre Marker hier innerhalb dieser useEffect hinzu, da map nicht null ist - - return () => { - // Bereinigung, entfernt dbLayer, wenn die Komponente unmountet - dbLayer.remove(); - }; - } - }, [map]); - - //------------------------------------------ - - useEffect(() => { - // Initialisierung der dbLayer, wenn die Karte verfügbar ist - if (map && !poiLayerRef.current) { - poiLayerRef.current = new L.LayerGroup().addTo(map); - } - - return () => { - if (map && poiLayerRef.current) { - // Entfernen der dbLayer bei Unmount - map.removeLayer(poiLayerRef.current); - poiLayerRef.current = new L.LayerGroup().addTo(map); - } - locations.forEach((location) => { - // Fügen Sie hier die Logik hinzu, um Marker zu erstellen und zu konfigurieren - }); - }; - //console.log("trigger in MapComponent.js:", poiReadTrigger); - }, [map, locations, poiReadTrigger]); // Dieser Effekt läuft nur, wenn sich `map` ändert - //------------------------------------------ - function editPoi(marker) { - // Zugriff auf die Markerdaten - const markerId = marker.options.id; - //console.log("Bearbeiten des POI mit ID:", markerId); - - // Hier könnte ein Modal mit Formular geöffnet werden - // Beispiel: openEditModal(markerId); - } - - //------------------------------------------ - //-------------------------------------------------- - - /* const addItemsToMapContextMenu = () => { - if (!menuItemAdded) { - //console.log("contextMenuItems hasRights:", hasRights); - - map.contextmenu.addItem({ - text: "POI hinzufügen", - icon: "img/add_station.png", - className: "background-red", - callback: (event) => addStationCallback(event, hasRights), - }); - - setMenuItemAdded(true); // Menüpunkt wurde hinzugefült, Zustand aktualisieren - } - }; */ - - /* useEffect(() => { - if (map && poiLayerRef.current && isPoiTypLoaded && !menuItemAdded) { - addItemsToMapContextMenu(); - } - }, [ - map, - poiLayerRef, - isPoiTypLoaded, - menuItemAdded, // Hinzufügen zu den Abhängigkeiten, um den Effekt korrekt zu steuern - ]); */ - //------------------------------------------ - - // poiLayerRef(poiDbLayer) POI hinzufügen - //-------------------------------------------- - const [poiData, setPoiData] = useState([]); - - useEffect(() => { + //-------------------------------------------- const fetchPoiData = async () => { try { const response = await fetch("/api/talas_v5_DB/pois/poi-icons"); @@ -1084,812 +346,92 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { throw new Error("Network response was not ok"); } const data = await response.json(); - setPoiData(data); - //console.log("poiData data:", data); - //console.log("poiData icons:", poiData); } catch (error) { - console.error("Fehler beim Abrufen der poiData:", error); + console.error("Fehler beim Abrufen der poiData-2:", error); } }; + //-------------------------------------------- + fetchPoiTypData(); fetchPoiData(); }, []); + + useEffect(() => { + if (map) { + const dbLayer = new L.LayerGroup().addTo(map); // Define dbLayer here + + return () => { + dbLayer.remove(); + }; + } + }, [map]); + + useEffect(() => { + if (map && !poiLayerRef.current) { + poiLayerRef.current = new L.LayerGroup().addTo(map); + } + + return () => { + if (map && poiLayerRef.current) { + map.removeLayer(poiLayerRef.current); + poiLayerRef.current = new L.LayerGroup().addTo(map); + } + locations.forEach((location) => {}); + }; + //console.log("trigger in MapComponent.js:", poiReadTrigger); + }, [map, locations, poiReadTrigger]); + //-------------------------------------------- useEffect(() => { if (poiData.length === 0) return; - try { - if (map && poiLayerRef.current && isPoiTypLoaded) { - map.removeLayer(poiLayerRef.current); - poiLayerRef.current = new L.LayerGroup().addTo(map); - - locations.forEach(async (location) => { - try { - const { latitude, longitude } = parsePoint(location.position); - const poiTypName = poiTypMap.get(location.idPoiTyp) || "Unbekannt"; - const deviceName = await fetchDeviceNameById(location.idLD); - //console.log("deviceName:", deviceName); // Das ist in Modal POI hinzufügen - - const canDrag = userRights ? userRights.includes(56) : false; - const matchingIcon = poiData.find( - (poi) => poi.idPoi === location.idPoi - ); - const iconUrl = matchingIcon - ? `/img/icons/pois/${matchingIcon.path}` - : "/img/icons/pois/default-icon.png"; - - const marker = L.marker([latitude, longitude], { - icon: L.icon({ - iconUrl: iconUrl, - iconSize: [25, 41], - iconAnchor: [12, 41], - popupAnchor: [1, -34], - }), - draggable: canDrag, - id: location.idPoi, - name: location.name, - description: location.description, - }).bindContextMenu({ - contextmenu: true, - contextmenuWidth: 140, - contextmenuItems: [ - { - text: "POI Bearbeiten", - icon: "/img/poi-edit.png", - callback: () => - handleEditPoi( - marker, - userRights, - setCurrentPoiData, - setShowPoiUpdateModal, - fetchPoiData, - toast - ), - }, - ], - }); - - marker.bindPopup(` -
- ${location.description || "Unbekannt"}
- ${deviceName}
- ${poiTypName}
-
- `); - - marker.on("mouseover", function () { - this.openPopup(); - handlePoiSelect({ - id: location.idPoi, - deviceId: location.idLD, - typ: poiTypName, - description: location.description, - }); - setCurrentPoi(location); - }); - - marker.on("mouseout", function () { - this.closePopup(); - }); - - marker.on("dragend", (e) => { - if (canDrag) { - const newLat = e.target.getLatLng().lat; - const newLng = e.target.getLatLng().lng; - const markerId = e.target.options.id; - updateLocationInDatabase(markerId, newLat, newLng).then(() => { - onLocationUpdate(markerId, newLat, newLng); - }); - } else { - console.error("Drag operation not allowed"); - } - }); - - if (poiLayerVisible) { - marker.addTo(poiLayerRef.current); - } - } catch (innerError) { - console.error("Error processing a location:", innerError); - } - }); - } - } catch (error) { - console.error("Error in useEffect:", error); - } - }, [ - map, - locations, - onLocationUpdate, - poiReadTrigger, - isPoiTypLoaded, - userRights, - poiLayerVisible, - poiData, // Add poiData as a dependency - ]); + setupPOIs(map, locations, poiData, poiTypMap, userRights, poiLayerRef, setSelectedPoi, setLocationDeviceData, setDeviceName, setCurrentPoi, poiLayerVisible, fetchPoiData, toast, setShowPoiUpdateModal, setCurrentPoiData, deviceName); + }, [map, locations, onLocationUpdate, poiReadTrigger, isPoiTypLoaded, userRights, poiLayerVisible, poiData, poiTypMap]); //--------------------------------------------- - - //------------------------------------------------------------------------------- + //console.log("priorityConfig in MapComponent2: ", priorityConfig); useEffect(() => { if (gisSystemStaticLoaded && map) { - createAndSetMarkers(1, setTalasMarkers); // TALAS-System - createAndSetMarkers(2, setEciMarkers); // ECI-System - createAndSetMarkers(5, setGsmModemMarkers); // GSM-Modem-System - createAndSetMarkers(6, setCiscoRouterMarkers); // Cisco-Router-System - createAndSetMarkers(7, setWagoMarkers); // WAGO-System - createAndSetMarkers(8, setSiemensMarkers); // Siemens-System - createAndSetMarkers(9, setOtdrMarkers); // OTDR-System - createAndSetMarkers(10, setWdmMarkers); // WDM-System - createAndSetMarkers(11, setGmaMarkers); // GMA-System - createAndSetMarkers(13, setMessstellenMarkers); // Messstellen-System - createAndSetMarkers(100, setTalasiclMarkers); // TALASICL-System - createAndSetMarkers(110, setDauzMarkers); // DAUZ-System - createAndSetMarkers(111, setSmsfunkmodemMarkers); // SMS-Funkmodem-System - createAndSetMarkers(200, setSonstigeMarkers); // Sonstige-System - createAndSetMarkers(0, setUlafMarkers); // ULAF-System + /* damit nich doppelt vorkommen + createAndSetDevices(11, setGmaMarkers, GisSystemStatic, priorityConfig); // GMA-System + createAndSetDevices(1, setTalasMarkers, GisSystemStatic, priorityConfig); // TALAS-System + createAndSetDevices(2, setEciMarkers, GisSystemStatic, priorityConfig); // ECI-System + createAndSetDevices(5, setGsmModemMarkers, GisSystemStatic, priorityConfig); // GSM-Modem-System---LTE Modem und GSM Modem sind gleich + //createAndSetDevices(5, setLteModemMarkers, GisSystemStatic, priorityConfig); //LTE Modem----------LTE Modem und GSM Modem sind gleich + createAndSetDevices(6, setCiscoRouterMarkers, GisSystemStatic, priorityConfig); // Cisco-Router-System + createAndSetDevices(7, setWagoMarkers, GisSystemStatic, priorityConfig); // WAGO-System + createAndSetDevices(8, setSiemensMarkers, GisSystemStatic, priorityConfig); // Siemens-System + createAndSetDevices(9, setOtdrMarkers, GisSystemStatic, priorityConfig); // OTDR-System + createAndSetDevices(10, setWdmMarkers, GisSystemStatic, priorityConfig); // WDM-System + createAndSetDevices(13, setMessstellenMarkers, GisSystemStatic, priorityConfig); // Messstellen-System + createAndSetDevices(100, setTalasiclMarkers, GisSystemStatic, priorityConfig); // TALASICL-System + createAndSetDevices(110, setDauzMarkers, GisSystemStatic, priorityConfig); // DAUZ-System + createAndSetDevices(111, setSmsfunkmodemMarkers, GisSystemStatic, priorityConfig); // SMS-Funkmodem-System + createAndSetDevices(200, setSonstigeMarkers, GisSystemStatic, priorityConfig); // Sonstige-System + createAndSetDevices(0, setUlafMarkers, GisSystemStatic, priorityConfig); // ULAF-System + */ } - }, [gisSystemStaticLoaded, map]); - //-------------------------------------------------------------------------------- - useEffect(() => { - if (map && talasMarkers.length) { - talasMarkers.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); - }); - map.addLayer(TALAS); - //console.log("map", map); - //console.log("oms", oms); - //disable map contextmenu - map.options.contextmenu = false; - map.options.contextmenuItems = []; - - oms.map.options.contextmenu = false; - oms.map.options.contextmenuItems = []; - - // Call the function here - checkOverlappingMarkers(oms, map, plusRoundIcon); - } - }, [map, talasMarkers]); // Abhängigkeiten auf `map` und `talasMarkers` beschränken - - //------------------------------------------- - //-------------------------------------------------------------------------------- - 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); - }); - map.addLayer(ECI); - } - }, [map, eciMarkers]); - - //console.log("eciMarkers", eciMarkers); - //------------------------------------------- - //-------------------------------------------------------------------------------- - 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); - }); - map.addLayer(GSMModem); - } - }, [map, gsmModemMarkers]); - - //console.log("gsmModemMarkers", gsmModemMarkers); - //------------------------------------------- - //-------------------------------------------------------------------------------- - useEffect(() => { - if (map && ciscoRouterMarkers.length) { - ciscoRouterMarkers.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); - }); - map.addLayer(CiscoRouter); - } - }, [map, ciscoRouterMarkers]); - - //console.log("ciscoRouterMarkers", ciscoRouterMarkers); - //------------------------------------------- - //-------------------------------------------------------------------------------- - useEffect(() => { - if (map && wagoMarkers.length) { - wagoMarkers.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); - }); - map.addLayer(WAGO); - - //toggleLayer(mapLayersVisibility.WAGO); - } - // }, [map, wagoMarkers, mapLayersVisibility.WAGO]); - }, [map, wagoMarkers]); - //console.log("wagoMarkers", wagoMarkers); - //------------------------------------------- - //-------------------------------------------------------------------------------- - useEffect(() => { - if (map && siemensMarkers.length) { - siemensMarkers.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); - }); - map.addLayer(Siemens); - } - }, [map, siemensMarkers]); - - //console.log("siemensMarkers", siemensMarkers); - //------------------------------------------- - //-------------------------------------------------------------------------------- - useEffect(() => { - if (map && otdrMarkers.length) { - otdrMarkers.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); - }); - map.addLayer(OTDR); - } - }, [map, otdrMarkers]); - - //console.log("otdrMarkers", otdrMarkers); - //------------------------------------------- - //-------------------------------------------------------------------------------- - useEffect(() => { - if (map && wdmMarkers.length) { - wdmMarkers.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); - }); - map.addLayer(WDM); - } - }, [map, wdmMarkers]); - - //console.log("wdmMarkers", wdmMarkers); - //------------------------------------------- - //-------------------------------------------------------------------------------- - useEffect(() => { - if (map && gmaMarkers.length) { - // Filtern des Arrays um nur "GMA" Messungen zu erhalten - const gmaMeasurements = GisStationsMeasurements.filter( - (m) => m.Gr === "GMA" - ); - let area_name = ""; - let measurements = {}; - - gmaMeasurements.forEach((m) => { - //console.log(`Messung: ${m.Area_Name}, Na: ${m.Na}, Wert: ${m.Val}`); - area_name = m.Area_Name; // Dies überschreibt area_name mit dem letzten Area_Name im Array - measurements[m.Na] = m.Val; // Speichert den Wert von Val unter dem Code Na in einem Objekt - }); - - // Zugriff auf die Werte über die Codes - let measurementLT = measurements["LT"]; - let measurementFTP = measurements["FTP"]; - let measurementGT = measurements["GT"]; - let measurementRLF = measurements["RLF"]; - - gmaMarkers.forEach((marker) => { - marker.addTo(map); - oms.addMarker(marker); - - // Tooltip beim Überfahren mit der Maus anzeigen - marker.bindTooltip( - ` -
-
- ${area_name} -
-
- LT : ${measurements.LT} °C -
-
- FBT : ${measurements.FBT} °C -
-
- GT : ${measurements.GT === "nicht ermittelbar" ? measurements.GT : `${measurements.GT} °C`} -
-
- RLF : ${measurements.RLF} % -
-
- `, - { - permanent: true, // Tooltip wird ständig angezeigt - direction: "auto", // Automatische Ausrichtung - offset: [20, 0], // Offset-Werte - } - ); - - // Popup beim Überfahren mit der Maus öffnen und schließen - marker.on("mouseover", function () { - this.openPopup(); - }); - marker.on("mouseout", function () { - this.closePopup(); - }); - addContextMenuToMarker(marker); - }); - map.addLayer(GMA); - } - }, [map, gmaMarkers]); // Abhängigkeiten auf `map` und `gmaMarkers` beschränken - - //console.log("gmaMarkers", gmaMarkers); - - //------------------------------------------- - //-------------------------------------------------------------------------------- - useEffect(() => { - if (map && messstellenMarkers.length) { - messstellenMarkers.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); - }); - map.addLayer(GMA); - } - }, [map, messstellenMarkers]); - - //console.log("messstellenMarkers", messstellenMarkers); - //------------------------------------------- - //-------------------------------------------------------------------------------- - useEffect(() => { - if (map && talasiclMarkers.length) { - talasiclMarkers.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); - }); - map.addLayer(TALASICL); - } - }, [map, talasiclMarkers]); - - //console.log("talasiclMarkers", talasiclMarkers); - //------------------------------------------- - //-------------------------------------------------------------------------------- - useEffect(() => { - if (map && dauzMarkers.length) { - dauzMarkers.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); - }); - } - }, [map, dauzMarkers]); - - //console.log("dauzMarkers", dauzMarkers); - //------------------------------------------- - //-------------------------------------------------------------------------------- - useEffect(() => { - if (map && smsfunkmodemMarkers.length) { - smsfunkmodemMarkers.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); - }); - } - }, [map, smsfunkmodemMarkers]); - - //console.log("smsfunkmodemMarkers", smsfunkmodemMarkers); - //------------------------------------------- - //-------------------------------------------------------------------------------- - useEffect(() => { - if (map && ulafMarkers.length) { - ulafMarkers.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); - }); - } - }, [map, ulafMarkers]); - - //console.log("ulafMarkers", ulafMarkers); - //------------------------------------------- - //-------------------------------------------------------------------------------- - useEffect(() => { - if (map && sonstigeMarkers.length) { - sonstigeMarkers.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); - }); - } - }, [map, sonstigeMarkers]); - - //console.log("sonstige", sonstigeMarkers); - //------------------------------------------- - - // Funktion zum Ein- und Ausblenden der TALAS-Marker basierend auf dem Zustand von mapLayersVisibility.TALAS - - useEffect(() => { - if (!map || !talasMarkers) return; - const toggleLayer = (isVisible) => { - if (isVisible) { - talasMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - talasMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - - // Apply visibility state to the TALAS layer - toggleLayer(mapLayersVisibility.TALAS); - }, [map, talasMarkers, mapLayersVisibility.TALAS]); - - //------------------------------------------ */ - // Funktion zum Ein- und Ausblenden der ECI-Marker basierend auf dem Zustand von mapLayersVisibility.ECI - - useEffect(() => { - if (!map || !eciMarkers) return; - const toggleLayer = (isVisible) => { - if (isVisible) { - eciMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - eciMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - // Apply visibility state to the ECI layer - toggleLayer(mapLayersVisibility.ECI); - }, [map, eciMarkers, mapLayersVisibility.ECI]); - - //------------------------------------------ */ - // Funktion zum Ein- und Ausblenden der ULAF-Marker basierend auf dem Zustand von mapLayersVisibility.ULAF - - useEffect(() => { - if (!map || !ulafMarkers) return; - const toggleLayer = (isVisible) => { - if (isVisible) { - ulafMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - ulafMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - // Apply visibility - toggleLayer(mapLayersVisibility.ULAF); - }, [map, ulafMarkers, mapLayersVisibility.ULAF]); - - //------------------------------------------ */ - //------------------------------------------ */ - // Funktion zum Ein- und Ausblenden der GSMModem-Marker basierend auf dem Zustand von mapLayersVisibility.GSMModem - - useEffect(() => { - if (!map || !gsmModemMarkers) return; - const toggleLayer = (isVisible) => { - if (isVisible) { - gsmModemMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - gsmModemMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - // Apply visibility - toggleLayer(mapLayersVisibility.GSMModem); - }, [map, gsmModemMarkers, mapLayersVisibility.GSMModem]); - - //------------------------------------------ */ - - // Funktion zum Ein- und Ausblenden der CiscoRouter-Marker basierend auf dem Zustand von mapLayersVisibility.CiscoRouter - - useEffect(() => { - if (!map || !ciscoRouterMarkers) return; - const toggleLayer = (isVisible) => { - if (isVisible) { - ciscoRouterMarkers.forEach((marker) => marker.addTo(map)); - } else { - ciscoRouterMarkers.forEach((marker) => map.removeLayer(marker)); - } - }; - // Nutzt die Map, um den internen Namen zu bekommen - const internalName = layerNames["Cisco Router"] || "CiscoRouter"; - toggleLayer(mapLayersVisibility[internalName]); - //console.log("internalName Cisco Router: ", internalName); - }, [map, ciscoRouterMarkers, mapLayersVisibility]); - - //------------------------------------------ */ - //------------------------------------------ */ - // Funktion zum Ein- und Ausblenden der WAGO-Marker basierend auf dem Zustand von mapLayersVisibility.WAGO - - useEffect(() => { - if (!map || !wagoMarkers) return; - const toggleLayer = (isVisible) => { - if (isVisible) { - wagoMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - wagoMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - // Apply visibility - toggleLayer(mapLayersVisibility.WAGO); - }, [map, wagoMarkers, mapLayersVisibility.WAGO]); - - //------------------------------------------ */ - //------------------------------------------ */ - // Funktion zum Ein- und Ausblenden der Siemens-Marker basierend auf dem Zustand von mapLayersVisibility.Siemens - - useEffect(() => { - if (!map || !siemensMarkers) return; - const toggleLayer = (isVisible) => { - if (isVisible) { - siemensMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - siemensMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - // Apply visibility - toggleLayer(mapLayersVisibility.Siemens); - }, [map, siemensMarkers, mapLayersVisibility.Siemens]); - - //------------------------------------------ */ - //------------------------------------------ */ - // Funktion zum Ein- und Ausblenden der OTDR-Marker basierend auf dem Zustand von mapLayersVisibility.OTDR - - useEffect(() => { - if (!map || !otdrMarkers) return; - const toggleLayer = (isVisible) => { - if (isVisible) { - otdrMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - otdrMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - // Apply visibility - toggleLayer(mapLayersVisibility.OTDR); - }, [map, otdrMarkers, mapLayersVisibility.OTDR]); - - //------------------------------------------ */ - //------------------------------------------ */ - // Funktion zum Ein- und Ausblenden der WDM-Marker basierend auf dem Zustand von mapLayersVisibility.WDM - - useEffect(() => { - if (!map || !wdmMarkers) return; - const toggleLayer = (isVisible) => { - if (isVisible) { - wdmMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - wdmMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - // Apply visibility - toggleLayer(mapLayersVisibility.WDM); - }, [map, wdmMarkers, mapLayersVisibility.WDM]); - - //------------------------------------------ */ - // Funktion zum Ein- und Ausblenden der GMA-Marker basierend auf dem Zustand von mapLayersVisibility.GMA - - useEffect(() => { - if (!map || !gmaMarkers) return; - - const toggleLayer = (isVisible) => { - if (isVisible) { - gmaMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - gmaMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - - // Apply visibility - toggleLayer(mapLayersVisibility.GMA); - }, [map, gmaMarkers, mapLayersVisibility.GMA]); - - //------------------------------------------ */ - //------------------------------------------ */ - // Funktion zum Ein- und Ausblenden der Sonstige-Marker basierend auf dem Zustand von mapLayersVisibility.Sonstige - - useEffect(() => { - if (!map || !sonstigeMarkers) return; - const toggleLayer = (isVisible) => { - if (isVisible) { - sonstigeMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - sonstigeMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - // Apply visibility - toggleLayer(mapLayersVisibility.Sonstige); - }, [map, sonstigeMarkers, mapLayersVisibility.Sonstige]); - - //------------------------------------------ */ - //------------------------------------------ */ - // Funktion zum Ein- und Ausblenden der TALASICL-Marker basierend auf dem Zustand von mapLayersVisibility.TALASICL - - useEffect(() => { - if (!map || !talasiclMarkers) return; - //console.log("talasiclMarkers", talasiclMarkers); - const toggleLayer = (isVisible) => { - if (isVisible) { - talasiclMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - talasiclMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - - // Verwendung der Map, um den internen Namen zu bekommen, und Fallback auf "TALASICL", falls nicht gefunden - const internalName = - layerNames["TALAS ICL"] || "TALASICL || talasiclMarkers "; - toggleLayer(mapLayersVisibility[internalName]); - //console.log("internalName for TALAS ICL in MapComponent: ", internalName); - }, [map, talasiclMarkers, mapLayersVisibility]); - - //------------------------------------------ */ - //------------------------------------------ */ - // Funktion zum Ein- und Ausblenden der DAUZ-Marker basierend auf dem Zustand von mapLayersVisibility.DAUZ - - useEffect(() => { - if (!map || !dauzMarkers) return; - const toggleLayer = (isVisible) => { - if (isVisible) { - dauzMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - dauzMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - // Apply visibility - toggleLayer(mapLayersVisibility.DAUZ); - }, [map, dauzMarkers, mapLayersVisibility.DAUZ]); - - //------------------------------------------ */ - //------------------------------------------ */ - // Funktion zum Ein- und Ausblenden der SMSFunkmodem-Marker basierend auf dem Zustand von mapLayersVisibility.SMSFunkmodem - - useEffect(() => { - if (!map || !smsfunkmodemMarkers) return; - const toggleLayer = (isVisible) => { - if (isVisible) { - smsfunkmodemMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - smsfunkmodemMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - // Apply visibility - toggleLayer(mapLayersVisibility.SMSFunkmodem); - }, [map, smsfunkmodemMarkers, mapLayersVisibility.SMSFunkmodem]); - - //------------------------------------------ */ - //------------------------------------------ */ - // Funktion zum Ein- und Ausblenden der Messstellen-Marker basierend auf dem Zustand von mapLayersVisibility.Messstellen - - useEffect(() => { - if (!map || !messstellenMarkers) return; - const toggleLayer = (isVisible) => { - if (isVisible) { - messstellenMarkers.forEach((marker) => marker.addTo(map)); // Ensure markers are added - } else { - messstellenMarkers.forEach((marker) => map.removeLayer(marker)); // Remove markers individually - } - }; - // Apply visibility - toggleLayer(mapLayersVisibility.Messstellen); - }, [map, messstellenMarkers, mapLayersVisibility.Messstellen]); - - //------------------------------------------ */ - - // Effect to handle navigation to selected area - /* useEffect(() => { - if (selectedArea && map) { - const marker = findMyMarker(selectedArea); - if (marker) { - map.flyTo(marker.getLatLng(), 14); // Adjust zoom level as needed - } - } - }, [selectedArea, map, allMarkers]); // Include allMarkers in the dependencies */ - - //------------------------------------------ + }, [gisSystemStaticLoaded, map, GisSystemStatic, priorityConfig]); + + //useCreateAndSetDevices(1, talasMarkers, GisSystemStatic, priorityConfig); + + useLayerVisibility(map, talasMarkers, mapLayersVisibility, "TALAS", oms); + useLayerVisibility(map, eciMarkers, mapLayersVisibility, "ECI", oms); + useLayerVisibility(map, gsmModemMarkers, mapLayersVisibility, "GSMModem", oms); + useLayerVisibility(map, ciscoRouterMarkers, mapLayersVisibility, "CiscoRouter", oms); + //useLayerVisibility(map, lteModemMarkers, mapLayersVisibility, "LTEModem", oms); + + useLayerVisibility(map, wagoMarkers, mapLayersVisibility, "WAGO", oms); + useLayerVisibility(map, siemensMarkers, mapLayersVisibility, "Siemens", oms); + useLayerVisibility(map, otdrMarkers, mapLayersVisibility, "OTDR", oms); + useLayerVisibility(map, wdmMarkers, mapLayersVisibility, "WDM", oms); + useLayerVisibility(map, gmaMarkers, mapLayersVisibility, "GMA", oms); + useLayerVisibility(map, sonstigeMarkers, mapLayersVisibility, "Sonstige", oms); + useLayerVisibility(map, talasiclMarkers, mapLayersVisibility, "TALASICL", oms); + useLayerVisibility(map, dauzMarkers, mapLayersVisibility, "DAUZ", oms); + useLayerVisibility(map, smsfunkmodemMarkers, mapLayersVisibility, "SMSFunkmodem", oms); + useLayerVisibility(map, messstellenMarkers, mapLayersVisibility, "Messstellen", oms); + useLayerVisibility(map, ulafMarkers, mapLayersVisibility, "ULAF", oms); useEffect(() => { if (map) { @@ -1901,14 +443,14 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { map.flyTo([x, y], zoom); } else { console.error("Map object is not ready or does not have flyTo method"); - } // Ihre bereits existierende Funktion, die Zoom-Out ausführt + } } }, [map, zoomTrigger]); + //-------------------------------------------- - //--------------------------------------------------------- useEffect(() => { if (map) { - // Combine all markers from different layers + // Sammle alle Marker in einer einzigen Liste const allMarkers = [ ...talasMarkers, ...eciMarkers, @@ -1926,385 +468,113 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { ...sonstigeMarkers, ...ulafMarkers, ]; - - // Call the function to check for overlaps and add plus icons - checkOverlappingMarkers(map, allMarkers, plusRoundIcon); + // Überprüfe überlappende Marker und füge das "Plus"-Icon hinzu + // checkOverlappingMarkers(map, allMarkers, plusRoundIcon); } - }, [ - map, - talasMarkers, - eciMarkers, - gsmModemMarkers, - ciscoRouterMarkers, - wagoMarkers, - siemensMarkers, - otdrMarkers, - wdmMarkers, - gmaMarkers, - messstellenMarkers, - talasiclMarkers, - dauzMarkers, - smsfunkmodemMarkers, - sonstigeMarkers, - ulafMarkers, - ]); - //--------------------------------------------------------- - //LINESTRING (53.151257 8.190471,53.161601 8.129359,53.19802 8.092366,53.244065 8.014003,53.252539 7.954265) - const [linePositions, setLinePositions] = useState([]); - // ------------Linien zeichnen---------------- - useEffect(() => { - const endpoint = "/api/talas_v5_DB/gisLines/readGisLines"; - fetch(endpoint) - .then((response) => { - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - return response.json(); - }) - .then((data) => { - const newLinePositions = data.map((item) => { - console.log("item.idLD", item.idLD); - console.log("item.idModul", item.idModul); - - if (item.points && Array.isArray(item.points)) { - //console.log("item.points in MapComponent", item.points); - return { - coordinates: item.points.map((point) => [point.x, point.y]), - idModul: item.idModul, - idLD: item.idLD, - }; - } else { - throw new Error("Points missing or not an array"); - } - }); - setLinePositions(newLinePositions); - }) - .catch((error) => { - console.error("Error fetching data:", error.message); - }); - }, []); - //--------------------------- Linien färben ------------------------------ - const [lineColors, setLineColors] = useState({}); - const [tooltipContents, setTooltipContents] = useState({}); - const [polylines, setPolylines] = useState([]); - const [markers, setMarkers] = useState([]); - - // API-Aufruf, um Farben der Linien abzurufen + }, [map, talasMarkers, eciMarkers, gsmModemMarkers, ciscoRouterMarkers, wagoMarkers, siemensMarkers, otdrMarkers, wdmMarkers, gmaMarkers, messstellenMarkers, talasiclMarkers, dauzMarkers, smsfunkmodemMarkers, sonstigeMarkers, ulafMarkers]); + //-------------------------------------------- useEffect(() => { const fetchData = async () => { try { const response1 = await fetch(webserviceGisLinesStatusUrl); const data1 = await response1.json(); - const response2 = await fetch("/api/talas_v5_DB/gisLines/readGisLines"); - /* const response2 = await fetch( - "http://10.10.0.13/talas5/MessagesMap/mapTypC.aspx?m=10&u=484" - ); */ - const data2 = await response2.json(); - - const colorsByModule = {}; - const newTooltipContents = {}; - - data1.Statis.forEach((stat) => { - const matchingLine = data2.find( - (item) => item.idLD === stat.IdLD && item.idModul === stat.Modul - ); - if (matchingLine) { - colorsByModule[matchingLine.idModul] = stat.PrioColor; - newTooltipContents[matchingLine.idModul] = ` -
- ${stat.ModulName || "Unknown"} -
- ${stat.ModulTyp || "N/A"} -
-
- - ${stat.Message || "N/A"} -
- (${stat.PrioName || "N/A"}) -
-
- `; - } - }); - - setLineColors(colorsByModule); - setTooltipContents(newTooltipContents); - } catch (error) { - console.error("Error fetching data:", error); - } - }; - - fetchData(); - }, []); - - // Überwachen des lineColors Zustandes - useEffect(() => { - //console.log("Aktualisierte lineColors", lineColors); - }, [lineColors]); - - //--------------------------------------------------------- - //----------------------- Update lines---------------------------------- - const [lineStatusData, setLineStatusData] = useState([]); - const [linesData, setLinesData] = useState([]); - - useEffect(() => { - const fetchData = async () => { - try { - const response1 = await fetch(webserviceGisLinesStatusUrl); - const data1 = await response1.json(); - setLineStatusData(data1.Statis); + //console.log("data1.Statis", data1.Statis); + const reversedData = data1.Statis.reverse(); + setLineStatusData(reversedData); const response2 = await fetch("/api/talas_v5_DB/gisLines/readGisLines"); const data2 = await response2.json(); const colorsByModule = {}; - data1.Statis.forEach((stat) => { - const matchingLine = data2.find( - (item) => item.idLD === stat.IdLD && item.idModul === stat.Modul - ); + reversedData.forEach((stat) => { + const matchingLine = data2.find((item) => item.idLD === stat.IdLD && item.idModul === stat.Modul); if (matchingLine) { colorsByModule[matchingLine.idModul] = stat.PrioColor; //console.log("Übereinstimmung gefunden für: ", stat); setLinesData(matchingLine); } }); - setLineColors(colorsByModule); + //setLineColors(colorsByModule); } catch (error) { console.error("Error fetching data:", error); } }; fetchData(); }, []); - //--------------------------------------------------------- - /* useEffect(() => { - console.log("lineStatusData", lineStatusData); - console.log("lineData:", linesData); - }, [lineStatusData, linesData]); */ - //--------------------------------------------------------- - const [newPoint, setNewPoint] = useState(null); - const [newCoords, setNewCoords] = useState(null); - const [tempMarker, setTempMarker] = useState(null); - + //-------------------------------------------- + //Tooltip an mouse position anzeigen für die Linien useEffect(() => { if (!map) return; - // Entfernen alter Marker und Polylines + // Entferne alte Marker und Polylinien markers.forEach((marker) => marker.remove()); polylines.forEach((polyline) => polyline.remove()); - const newMarkers = []; - const newPolylines = []; + // Setze neue Marker und Polylinien mit den aktuellen Daten + const { markers: newMarkers, polylines: newPolylines } = setupPolylines( + map, + linePositions, + lineColors, + tooltipContents, + setNewCoords, + tempMarker, + polylineVisible // polylineVisible wird jetzt korrekt übergeben + ); - linePositions.forEach((lineData, lineIndex) => { - const lineMarkers = []; - lineData.coordinates.forEach((coord, index) => { - let icon = circleIcon; // Standard-Icon für mittlere Punkte - if (index === 0) { - icon = startIcon; // Start-Icon für den ersten Punkt - } else if (index === lineData.coordinates.length - 1) { - icon = endIcon; // End-Icon für den letzten Punkt - } + newPolylines.forEach((polyline, index) => { + const tooltipContent = tooltipContents[`${linePositions[index].idLD}-${linePositions[index].idModul}`] || "Standard-Tooltip-Inhalt"; - const marker = L.marker(coord, { - icon: icon, - draggable: true, - contextmenu: true, - contextmenuInheritItems: false, - contextmenuItems: [], // Starte mit einem leeren Menü - }).addTo(map); - - marker.on("dragend", () => { - const newCoords = marker.getLatLng(); - setNewCoords(newCoords); // Aktualisieren Sie den Zustand - setNewCoords(newCoords); // Aktualisieren Sie den Zustand - const newCoordinates = [...lineData.coordinates]; - newCoordinates[index] = [newCoords.lat, newCoords.lng]; - - const updatedPolyline = L.polyline(newCoordinates, { - color: lineColors[lineData.idModul] || "#000000", - }).addTo(map); - - updatedPolyline.bindTooltip( - tooltipContents[lineData.idModul] || "Standard-Tooltip-Inhalt", - { - permanent: false, - direction: "auto", - } - ); - - updatedPolyline.on("mouseover", () => { - updatedPolyline.setStyle({ weight: 10 }); - updatedPolyline.bringToFront(); - }); - updatedPolyline.on("mouseout", () => { - updatedPolyline.setStyle({ weight: 3 }); - console.log("Mouse out"); - }); - - newPolylines[lineIndex].remove(); - newPolylines[lineIndex] = updatedPolyline; - lineData.coordinates = newCoordinates; - - const requestData = { - idModul: lineData.idModul, - idLD: lineData.idLD, - newCoordinates, - }; - - console.log("Sending to API:", requestData); - // API-Aufruf, um die neuen Koordinaten zu speichern - fetch("/api/talas_v5_DB/gisLines/updateLineCoordinates", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify(requestData), - }) - .then((response) => { - if (!response.ok) { - return response.json().then((data) => { - throw new Error(data.error || "Unbekannter Fehler"); - }); - } - return response.json(); - }) - .then((data) => { - console.log("Koordinaten erfolgreich aktualisiert:", data); - }) - .catch((error) => { - console.error( - "Fehler beim Aktualisieren der Koordinaten:", - error.message - ); - }); - }); - - // Füge die Option zum Entfernen nur hinzu, wenn der Benutzer mit der Maus über dem Marker ist - marker.on("mouseover", function () { - this.bindContextMenu({ - contextmenuItems: [ - { - text: "Stützpunkt entfernen", - callback: () => { - const newCoords = marker.getLatLng(); - const newCoordinates = [...lineData.coordinates]; - newCoordinates[index] = [newCoords.lat, newCoords.lng]; - - removeMarker(marker, lineData, currentZoom, currentCenter); - newPolylines[lineIndex].remove(); - lineData.coordinates = newCoordinates; - }, - }, - ], - }); - }); - - // Entferne die Option, wenn der Benutzer den Mausbereich des Markers verlässt - marker.on("mouseout", function () { - this.unbindContextMenu(); - }); - - lineMarkers.push(marker); + polyline.bindTooltip(tooltipContent, { + permanent: false, + direction: "auto", + sticky: true, + offset: [20, 0], + pane: "tooltipPane", }); - const polyline = L.polyline(lineData.coordinates, { - color: lineColors[lineData.idModul] || "#000000", - contextmenu: true, - contextmenuItems: [ - { - text: "Stützpunkt hinzufügen", - callback: (e) => { - if (tempMarker) { - tempMarker.remove(); // Entfernen des Platzhalter-Icons - } - //------------ - if (tempMarker) { - tempMarker.remove(); // Entfernen des Platzhalter-Icons - } - //------------ - const newPoint = e.latlng; - setNewPoint(newPoint); // Aktualisieren Sie den Zustand - setNewPoint(newPoint); // Aktualisieren Sie den Zustand - const closestPoints = findClosestPoints( - lineData.coordinates, - newPoint - ); - insertNewMarker(closestPoints, newPoint, lineData, map); - redrawPolyline(lineData); - redrawPolyline(lineData); - //Browser aktualisieren - window.location.reload(); - }, - }, - ], - }).addTo(map); - polyline.on("mouseover", (e) => { - // Optional: Visualisiere, dass die Linie interaktiv ist - //polyline.setStyle({ color: "blue", weight: 10 }); - polyline.setStyle({ weight: 10 }); - }); + const tooltip = polyline.getTooltip(); + if (tooltip) { + const mousePos = e.containerPoint; + const mapSize = map.getSize(); - polyline.on("mouseout", (e) => { - //polyline.setStyle({ color: "blue", weight: 3 }); - polyline.setStyle({ weight: 3 }); + let direction = "right"; - // Setze die ursprüngliche Farbe zurück - polyline.setStyle({ color: lineColors[lineData.idModul] || "#000000" }); - }); + if (mousePos.x > mapSize.x - 100) { + direction = "left"; + } else if (mousePos.x < 100) { + direction = "right"; + } - polyline.bindTooltip( - tooltipContents[lineData.idModul] || "Standard-Tooltip-Inhalt", - { - permanent: false, - direction: "auto", + if (mousePos.y > mapSize.y - 100) { + direction = "top"; + } else if (mousePos.y < 100) { + direction = "bottom"; + } + + tooltip.options.direction = direction; + polyline.openTooltip(e.latlng); } - ); + }); - newPolylines.push(polyline); - newMarkers.push(...lineMarkers); + polyline.on("mouseout", () => { + polyline.closeTooltip(); + }); }); setMarkers(newMarkers); setPolylines(newPolylines); - }, [ - map, - linePositions, - lineColors, - tooltipContents, - newPoint, - newCoords, - tempMarker, - ]); + }, [map, linePositions, lineColors, tooltipContents, newPoint, newCoords, tempMarker, polylineVisible]); - //--------------------------------------------------------- - //-------------------------Funktionen-------------------------------- + //-------------------------------------------- - // Call restoreMapSettings when the map is initialized useEffect(() => { if (map) { restoreMapSettings(map); } }, [map]); - function findClosestPoints(coordinates, newPoint) { - let minDist = Infinity; - let closestPair = []; - for (let i = 1; i < coordinates.length; i++) { - const dist = L.LineUtil.pointToSegmentDistance( - map.latLngToLayerPoint(newPoint), - map.latLngToLayerPoint(coordinates[i - 1]), - map.latLngToLayerPoint(coordinates[i]) - ); - if (dist < minDist) { - minDist = dist; - closestPair = [coordinates[i - 1], coordinates[i], i]; - } - } - return closestPair; - } - //--------------------------------------------------------- useEffect(() => { if (map) { const handleMapMoveEnd = (event) => { @@ -2314,11 +584,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { setCurrentCenter([newCenter.lat, newCenter.lng]); setCurrentZoom(newZoom); - // Save to localStorage - localStorage.setItem( - "mapCenter", - JSON.stringify([newCenter.lat, newCenter.lng]) - ); + localStorage.setItem("mapCenter", JSON.stringify([newCenter.lat, newCenter.lng])); localStorage.setItem("mapZoom", newZoom); }; @@ -2331,26 +597,11 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { }; } }, [map]); + //-------------------------------------------- - //------------------------------------------ */hier ist das Bug - - // Effect to handle navigation to selected area - /* useEffect(() => { - if (selectedArea && map) { - const marker = findMyMarker(selectedArea); - if (marker) { - map.flyTo(marker.getLatLng(), 14); // Adjust zoom level as needed - } - } - }, [selectedArea, map, allMarkers]); // Include allMarkers in the dependencies */ - - //------------------------------------------ - //--------------------------------------------------------- Kein Bug useEffect(() => { if (selectedArea && map) { - const station = GisStationsStaticDistrict.find( - (s) => s.Area_Name === selectedArea - ); + const station = GisStationsStaticDistrict.find((s) => s.Area_Name === selectedArea); if (station) { map.flyTo([station.X, station.Y], 14); } @@ -2362,111 +613,219 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { map.flyTo([51.41321407879154, 7.739617925303934], 7); } }, [zoomTrigger, map]); - //--------------------------------------------------------- - //---------------------------------------------------------zoomen in kontextmenü - // Beispiel für die Verwendung von fetchPoiData mit Recoil Zustand - /* useEffect(() => { - if (selectedPoi) { - fetchPoiData(selectedPoi.idPoi) - .then((data) => { - console.log("Fetched POI data:", data); - }) - .catch((error) => { - console.error("Fehler beim Abrufen der POI-Daten:", error); - }); + + useEffect(() => { + if (map && poiLayerRef.current && isPoiTypLoaded && !menuItemAdded && isRightsLoaded) { + addItemsToMapContextMenu(map, menuItemAdded, setMenuItemAdded, hasRights, setShowPopup, setPopupCoordinates); } - }, [selectedPoi]); */ - //--------------------------------------------------------- - //--------------------------------------------------------- + }, [map, poiLayerRef, isPoiTypLoaded, menuItemAdded, hasRights, isRightsLoaded]); + //-------------------------------------------- + // rote Marker ganz oben wenn überlappen sind + useEffect(() => { + const fetchPriorityConfig = async () => { + try { + const res = await fetch("/api/talas_v5_DB/priorityConfig"); + if (!res.ok) { + throw new Error(`HTTP error! status: ${res.status}`); + } + const data = await res.json(); + setPriorityConfig(data); + } catch (error) { + console.error("Failed to load priority configuration:", error); + } + }; + + fetchPriorityConfig(); + }, []); + //-------------------------------------------- + useEffect(() => { + if (mapRef.current && !map) { + initializeMap(mapRef, setMap, setOms, setMenuItemAdded, addItemsToMapContextMenu, hasRights, setPolylineEventsDisabled); + } + }, [mapRef, map, hasRights, setPolylineEventsDisabled]); + + useEffect(() => { + if (map) { + if (polylineEventsDisabled) { + disablePolylineEvents(window.polylines); + } else { + enablePolylineEvents(window.polylines, window.lineColors); + } + } + }, [map, polylineEventsDisabled]); + useEffect(() => { + if (map) { + console.log("6- Karteninstanz (map) wurde jetzt erfolgreich initialisiert"); + + // Setze die Karteninstanz in den Recoil-Atom + } + }, [map]); + //-------------------------------------------- + useEffect(() => { + const initializeContextMenu = () => { + if (map) { + map.whenReady(() => { + setTimeout(() => { + if (map.contextmenu) { + //console.log("Contextmenu ist vorhanden"); + } else { + console.warn("Contextmenu ist nicht verfügbar."); + } + }, 500); + }); + } + }; + + initializeContextMenu(); + }, [map]); + //-------------------------------------------- + + useEffect(() => { + if (!map) return; // Stelle sicher, dass die Karte initialisiert ist + + const updateGmaData = async () => { + try { + const fetchOptions = { + method: "GET", + headers: { + Connection: "close", + }, + }; + + // Aktualisiere die Messdaten + await fetchGisStationsMeasurements(mapGisStationsMeasurementsUrl, setGisStationsMeasurements, fetchOptions); + + // Aktualisiere die Marker-Layer + useGmaMarkersLayer(map, gmaMarkers, GisStationsMeasurements, layers.MAP_LAYERS.GMA, oms); + } catch (error) { + console.error("Fehler beim Aktualisieren der GMA-Daten:", error); + } + }; + + // Initialer Datenabruf + updateGmaData(); + + // Setze ein Intervall, um die Daten alle 5 Sekunden zu aktualisieren + const intervalId = setInterval(() => { + updateGmaData(); + }, 5000); + + // Cleanup-Funktion, um das Intervall zu entfernen, wenn die Komponente entladen wird + return () => clearInterval(intervalId); + }, [map, gmaMarkers, layers.MAP_LAYERS.GMA, oms, mapGisStationsMeasurementsUrl]); + + //--------------------------------- + + const gmaLayerRef = useRef(null); + const talasLayerRef = useRef(null); + const eciMarkersLayerRef = useRef(null); + const gsmModemMarkersLayerRef = useRef(null); + const ciscoRouterMarkersLayerRef = useRef(null); + const wagoMarkersLayerRef = useRef(null); + const siemensMarkersLayerRef = useRef(null); + const otdrMarkersLayerRef = useRef(null); + const wdmMarkersLayerRef = useRef(null); + const messstellenMarkersLayerRef = useRef(null); + const talasiclMarkersLayerRef = useRef(null); + const dauzMarkersLayerRef = useRef(null); + const smsfunkmodemMarkersLayerRef = useRef(null); + const ulafMarkersLayerRef = useRef(null); + const sonstigeMarkersLayerRef = useRef(null); + useEffect(() => { + if (!gisSystemStaticLoaded || !map) return; // Sicherstellen, dass die Karte und Daten geladen sind + + const layerGroups = [ + { ref: gmaLayerRef, id: 11, setState: setGmaMarkers }, + { ref: talasLayerRef, id: 1, setState: setTalasMarkers }, + { ref: eciMarkersLayerRef, id: 2, setState: setEciMarkers }, + { ref: gsmModemMarkersLayerRef, id: 5, setState: setGsmModemMarkers }, + { ref: ciscoRouterMarkersLayerRef, id: 6, setState: setCiscoRouterMarkers }, + { ref: wagoMarkersLayerRef, id: 7, setState: setWagoMarkers }, + { ref: siemensMarkersLayerRef, id: 8, setState: setSiemensMarkers }, + { ref: otdrMarkersLayerRef, id: 9, setState: setOtdrMarkers }, + { ref: wdmMarkersLayerRef, id: 10, setState: setWdmMarkers }, + { ref: messstellenMarkersLayerRef, id: 13, setState: setMessstellenMarkers }, + { ref: talasiclMarkersLayerRef, id: 100, setState: setTalasiclMarkers }, + { ref: dauzMarkersLayerRef, id: 110, setState: setDauzMarkers }, + { ref: smsfunkmodemMarkersLayerRef, id: 111, setState: setSmsfunkmodemMarkers }, + { ref: ulafMarkersLayerRef, id: 0, setState: setUlafMarkers }, + { ref: sonstigeMarkersLayerRef, id: 200, setState: setSonstigeMarkers }, + ]; + + // Initialisiere LayerGroups nur einmal + layerGroups.forEach(({ ref }) => { + if (!ref.current) { + ref.current = new L.LayerGroup().addTo(map); + } + }); + + const updateMarkers = ({ ref, id, setState }) => { + if (ref.current) { + ref.current.clearLayers(); // Entferne alte Marker + } + + // Erstelle und füge neue Marker hinzu + createAndSetDevices( + id, + (newMarkers) => { + setState(newMarkers); // Zustand aktualisieren + newMarkers.forEach((marker) => ref.current.addLayer(marker)); // Marker zur LayerGroup hinzufügen + + // Überprüfe auf überlappende Marker und füge das Plus-Icon hinzu + checkOverlappingMarkers(map, newMarkers, plusRoundIcon); + }, + GisSystemStatic, + priorityConfig + ); + }; + + // Aktualisiere alle Marker-Gruppen + const updateAllMarkers = () => { + layerGroups.forEach(updateMarkers); + }; + + // Initiales Update + updateAllMarkers(); + + // Setze ein Intervall für regelmäßige Updates + const intervalId = setInterval(() => { + updateAllMarkers(); + }, 20000); // 20 Sekunden + + // Aufräumen bei Komponentenentladung + return () => { + clearInterval(intervalId); // Entferne Intervall + + // LayerGroups leeren + layerGroups.forEach(({ ref }) => { + if (ref.current) { + ref.current.clearLayers(); + } + }); + }; + }, [gisSystemStaticLoaded, map, GisSystemStatic, priorityConfig]); + + //--------------------------------------- + + //---------------------------------- + + //--------------------------------------- return ( <> -
- {/* Zeigt das Popup-Fenster nur, wenn `showPopup` wahr ist */} - {showPoiUpdateModal && ( -
-
e.stopPropagation()} // Verhindert das Schließen innerhalb des Fensters - > - {/* Schließen-Button oben rechts */} - +
{showPoiUpdateModal && setShowPoiUpdateModal(false)} poiData={currentPoiData} onSubmit={() => {}} latlng={popupCoordinates} />}
- {/* Formular-Komponente zum Hinzufügen einer Station */} - setShowPoiUpdateModal(false)} - poiData={currentPoiData} - onSubmit={handleAddStation} - latlng={popupCoordinates} - /> -
-
- )} -
- - {/* Rest of your component */}
- {/* Zeigt das Popup-Fenster nur, wenn `showPopup` wahr ist */} {showPopup && ( -
-
e.stopPropagation()} // Verhindert das Schließen innerhalb des Fensters - > - {/* Schließen-Button oben rechts */} - - - {/* Formular-Komponente zum Hinzufügen einer Station */} - +
)} @@ -2474,75 +833,23 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => { -
+
- - {" "} - TALAS.Map{" "} - - + TALAS.Map
Version {MAP_VERSION}
- {showVersionInfoModal && ( -
-
-
- TALAS V5 Logo -
-

- Littwin Systemtechnik GmbH & Co. KG -

-

- Bürgermeister-Brötje Str. 28 -

-

- D-26180 Rastede -

-
- T: +49 4402 9725 77-0 -
-
- E: kontakt@littwin-systemtechnik.de -
-
-

- TALAS.Map Version {MAP_VERSION} -

- -
-
- )} + ); }; diff --git a/components/PoiUpdateModal.js b/components/PoiUpdateModal.js index 47eebc438..d24cab7ad 100644 --- a/components/PoiUpdateModal.js +++ b/components/PoiUpdateModal.js @@ -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 (
- setDescription(e.target.value)} - placeholder="Beschreibung der Station" - className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm" - /> + setDescription(e.target.value)} placeholder="Beschreibung der Station" className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm" />
- 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), + ( + + ) + ) + )}
@@ -216,13 +198,7 @@ const PoiUpdateModal = ({ onClose, poiData }) => { - setPoiTypeId(e.target.value)} className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm"> {poiTypData.map((poiTyp, index) => (
diff --git a/components/PoiUtils.js b/components/PoiUtils.js index a66985054..065b52a65 100644 --- a/components/PoiUtils.js +++ b/components/PoiUtils.js @@ -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" }, diff --git a/components/TestScript.js b/components/TestScript.js new file mode 100644 index 000000000..c34b9f7dc --- /dev/null +++ b/components/TestScript.js @@ -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 +} diff --git a/components/VersionInfoModal.js b/components/VersionInfoModal.js new file mode 100644 index 000000000..30fd4d824 --- /dev/null +++ b/components/VersionInfoModal.js @@ -0,0 +1,30 @@ +// components/VersionInfoModal.js +import React from "react"; + +const VersionInfoModal = ({ showVersionInfoModal, closeVersionInfoModal, MAP_VERSION }) => { + return ( + <> + {showVersionInfoModal && ( +
+
+
+ TALAS V5 Logo +
+

Littwin Systemtechnik GmbH & Co. KG

+

Bürgermeister-Brötje Str. 28

+

D-26180 Rastede

+
T: +49 4402 9725 77-0
+
E: kontakt@littwin-systemtechnik.de
+
+

TALAS.Map Version {MAP_VERSION}

+ +
+
+ )} + + ); +}; + +export default VersionInfoModal; diff --git a/components/gisPolylines/PolylineContextMenu.js b/components/gisPolylines/PolylineContextMenu.js new file mode 100644 index 000000000..a07de670b --- /dev/null +++ b/components/gisPolylines/PolylineContextMenu.js @@ -0,0 +1,26 @@ +// /components/gisPolylines/PolylineContextMenu.js +import React from "react"; + +const PolylineContextMenu = ({ position, onAddPoint, onRemovePoint, onClose }) => { + return ( +
+
    +
  • Stützpunkt hinzufügen
  • +
  • Stützpunkt entfernen
  • +
  • Schließen
  • +
+
+ ); +}; + +export default PolylineContextMenu; diff --git a/components/gisPolylines/icons/CircleIcon.js b/components/gisPolylines/icons/CircleIcon.js new file mode 100644 index 000000000..c4a17e6ea --- /dev/null +++ b/components/gisPolylines/icons/CircleIcon.js @@ -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: '
', + iconSize: [25, 25], + iconAnchor: [5, 5], +}); + +export default CircleIcon; diff --git a/components/gisPolylines/icons/EndIcon.js b/components/gisPolylines/icons/EndIcon.js new file mode 100644 index 000000000..151fe745c --- /dev/null +++ b/components/gisPolylines/icons/EndIcon.js @@ -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: "
", // Graues Viereck + iconSize: [14, 14], + iconAnchor: [7, 7], // Mittelpunkt des Vierecks als Anker +}); + +export default EndIcon; diff --git a/components/gisPolylines/icons/StartIcon.js b/components/gisPolylines/icons/StartIcon.js new file mode 100644 index 000000000..cd2677d72 --- /dev/null +++ b/components/gisPolylines/icons/StartIcon.js @@ -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: ` + + + + + `, // Schwarzes Dreieck innerhalb eines grauen Dreiecks + iconSize: [18, 18], + iconAnchor: [9, 10], +}); + +export default StartIcon; diff --git a/components/gisPolylines/icons/SupportPointIcons.js b/components/gisPolylines/icons/SupportPointIcons.js new file mode 100644 index 000000000..d312e4a9a --- /dev/null +++ b/components/gisPolylines/icons/SupportPointIcons.js @@ -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: ` +
+
+
+
+ `, + iconSize: [24, 24], + iconAnchor: [12, 12], +}); + +// Icon für Stützpunkt entfernen +export const RemoveSupportPointIcon = L.divIcon({ + className: "custom-remove-support-point-icon", + html: ` +
+
-
+
+ `, + iconSize: [24, 24], + iconAnchor: [12, 12], +}); diff --git a/components/imports.js b/components/imports.js new file mode 100644 index 000000000..a81e36edb --- /dev/null +++ b/components/imports.js @@ -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, +}; diff --git a/components/pois/AddPoiModalWindow.js b/components/pois/AddPoiModalWindow.js new file mode 100644 index 000000000..e877c200f --- /dev/null +++ b/components/pois/AddPoiModalWindow.js @@ -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 ( +
+
+ + setName(e.target.value)} className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm" /> +
+ + {/* React Select for Devices */} +
+ + +
+ +
+
+ +
+
+ +
+
+ + +
+ ); +}; + +export default AddPoiModalWindow; diff --git a/components/pois/AddPoiModalWindowPopup.js b/components/pois/AddPoiModalWindowPopup.js new file mode 100644 index 000000000..f535a5c33 --- /dev/null +++ b/components/pois/AddPoiModalWindowPopup.js @@ -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 && ( +
+
e.stopPropagation()}> + + +
+
+ )} + + ); +}; + +export default AddPoiModalWindowPopup; diff --git a/components/pois/AddPoiModalWindowWrapper.js b/components/pois/AddPoiModalWindowWrapper.js new file mode 100644 index 000000000..1ac3402bd --- /dev/null +++ b/components/pois/AddPoiModalWindowWrapper.js @@ -0,0 +1,30 @@ +// components/pois/AddPoiModalWindowWrapper.js +import React from "react"; +import AddPoiModalWindow from "./AddPoiModalWindow"; + +const AddPoiModalWindowWrapper = ({ show, onClose, latlng, handleAddStation }) => { + return ( + show && ( +
+
e.stopPropagation()} + role="dialog" // Hinzugefügt, um das Dialog-Element zu identifizieren + > + + +
+
+ ) + ); +}; + +export default AddPoiModalWindowWrapper; diff --git a/components/pois/PoiUpdateModal.js b/components/pois/PoiUpdateModal.js new file mode 100644 index 000000000..932a21dfc --- /dev/null +++ b/components/pois/PoiUpdateModal.js @@ -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 ( +
+
e.stopPropagation()}> + +
+
+ + setDescription(e.target.value)} placeholder="Beschreibung der Station" className="block p-2 w-full border-2 border-gray-200 rounded-md text-sm" /> +
+ + {/* React Select for Devices */} +
+ + +
+ + + +
+
+
+ ); +}; + +export default PoiUpdateModal; diff --git a/components/pois/PoiUpdateModalWindow.js b/components/pois/PoiUpdateModalWindow.js new file mode 100644 index 000000000..9badee70a --- /dev/null +++ b/components/pois/PoiUpdateModalWindow.js @@ -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 && {}} latlng={popupCoordinates} />}; +}; + +export default PoiUpdateModalWindow; diff --git a/components/pois/PoiUpdateModalWrapper.js b/components/pois/PoiUpdateModalWrapper.js new file mode 100644 index 000000000..92debdc41 --- /dev/null +++ b/components/pois/PoiUpdateModalWrapper.js @@ -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 && ( + {}} // Add your submit logic here + latlng={latlng} + /> + ) + ); +}; + +export default PoiUpdateModalWrapper; diff --git a/components/pois/PoiUtils.js b/components/pois/PoiUtils.js new file mode 100644 index 000000000..9275f95f1 --- /dev/null +++ b/components/pois/PoiUtils.js @@ -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 diff --git a/components/useMapContextMenu.js b/components/useMapContextMenu.js index dc33eab7e..6a59bbf8e 100644 --- a/components/useMapContextMenu.js +++ b/components/useMapContextMenu.js @@ -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; diff --git a/config/config.js b/config/config.js index a2d95d8e7..f6ea0a555 100644 --- a/config/config.js +++ b/config/config.js @@ -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 diff --git a/config/settings.js b/config/settings.js index 36391cc2b..69ce604e7 100644 --- a/config/settings.js +++ b/config/settings.js @@ -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; diff --git a/config/urls.js b/config/urls.js index b9df41732..207d02eff 100644 --- a/config/urls.js +++ b/config/urls.js @@ -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 diff --git a/cypress.config.js b/cypress.config.js new file mode 100644 index 000000000..3b671304d --- /dev/null +++ b/cypress.config.js @@ -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", + }, + }, +}); diff --git a/cypress/e2e/spec.cy.js b/cypress/e2e/spec.cy.js new file mode 100644 index 000000000..f037e07c2 --- /dev/null +++ b/cypress/e2e/spec.cy.js @@ -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 + }); +}); diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json new file mode 100644 index 000000000..02e425437 --- /dev/null +++ b/cypress/fixtures/example.json @@ -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" +} diff --git a/cypress/integration/map_test_spec.js b/cypress/integration/map_test_spec.js new file mode 100644 index 000000000..a1f4322b2 --- /dev/null +++ b/cypress/integration/map_test_spec.js @@ -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); + }); + }); +}); diff --git a/cypress/support/commands.js b/cypress/support/commands.js new file mode 100644 index 000000000..66ea16ef0 --- /dev/null +++ b/cypress/support/commands.js @@ -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) => { ... }) \ No newline at end of file diff --git a/cypress/support/component-index.html b/cypress/support/component-index.html new file mode 100644 index 000000000..3e16e9b07 --- /dev/null +++ b/cypress/support/component-index.html @@ -0,0 +1,14 @@ + + + + + + + Components App + +
+ + +
+ + \ No newline at end of file diff --git a/cypress/support/component.js b/cypress/support/component.js new file mode 100644 index 000000000..8f9154b5e --- /dev/null +++ b/cypress/support/component.js @@ -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() \ No newline at end of file diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js new file mode 100644 index 000000000..0e7290a13 --- /dev/null +++ b/cypress/support/e2e.js @@ -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') \ No newline at end of file diff --git a/hooks/layers/useCiscoRouterMarkersLayer.js b/hooks/layers/useCiscoRouterMarkersLayer.js new file mode 100644 index 000000000..4e7abed3e --- /dev/null +++ b/hooks/layers/useCiscoRouterMarkersLayer.js @@ -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; diff --git a/hooks/layers/useDauzMarkersLayer.js b/hooks/layers/useDauzMarkersLayer.js new file mode 100644 index 000000000..bca14ccf3 --- /dev/null +++ b/hooks/layers/useDauzMarkersLayer.js @@ -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; diff --git a/hooks/layers/useEciMarkersLayer.js b/hooks/layers/useEciMarkersLayer.js new file mode 100644 index 000000000..0f24c43ab --- /dev/null +++ b/hooks/layers/useEciMarkersLayer.js @@ -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; diff --git a/hooks/layers/useGmaMarkersLayer.js b/hooks/layers/useGmaMarkersLayer.js new file mode 100644 index 000000000..d440640c9 --- /dev/null +++ b/hooks/layers/useGmaMarkersLayer.js @@ -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( + ` +
+
+ ${area_name} +
+
+ LT : ${lt} °C +
+
+ FBT : ${fbt} °C +
+
+ GT : ${gt} +
+
+ RLF : ${rlf} % +
+
+ `, + { + 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; diff --git a/hooks/layers/useGsmModemMarkersLayer.js b/hooks/layers/useGsmModemMarkersLayer.js new file mode 100644 index 000000000..8fd0260dc --- /dev/null +++ b/hooks/layers/useGsmModemMarkersLayer.js @@ -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; diff --git a/hooks/layers/useLteModemMarkersLayer.js b/hooks/layers/useLteModemMarkersLayer.js new file mode 100644 index 000000000..d32507dee --- /dev/null +++ b/hooks/layers/useLteModemMarkersLayer.js @@ -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; diff --git a/hooks/layers/useMessstellenMarkersLayer.js b/hooks/layers/useMessstellenMarkersLayer.js new file mode 100644 index 000000000..8757cb888 --- /dev/null +++ b/hooks/layers/useMessstellenMarkersLayer.js @@ -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; diff --git a/hooks/layers/useOtdrMarkersLayer.js b/hooks/layers/useOtdrMarkersLayer.js new file mode 100644 index 000000000..ff8061655 --- /dev/null +++ b/hooks/layers/useOtdrMarkersLayer.js @@ -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; diff --git a/hooks/layers/useSiemensMarkersLayer.js b/hooks/layers/useSiemensMarkersLayer.js new file mode 100644 index 000000000..6d56ac03e --- /dev/null +++ b/hooks/layers/useSiemensMarkersLayer.js @@ -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; diff --git a/hooks/layers/useSmsfunkmodemMarkersLayer.js b/hooks/layers/useSmsfunkmodemMarkersLayer.js new file mode 100644 index 000000000..4c5d182cc --- /dev/null +++ b/hooks/layers/useSmsfunkmodemMarkersLayer.js @@ -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(` +
+ ${station.Area_Name || "Unbekannt"}
+ ${station.Description || "No Description"}
+
+ `); + + 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; diff --git a/hooks/layers/useSonstigeMarkersLayer.js b/hooks/layers/useSonstigeMarkersLayer.js new file mode 100644 index 000000000..58b871391 --- /dev/null +++ b/hooks/layers/useSonstigeMarkersLayer.js @@ -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; diff --git a/hooks/layers/useTalasMarkers.js b/hooks/layers/useTalasMarkers.js new file mode 100644 index 000000000..b16f94f84 --- /dev/null +++ b/hooks/layers/useTalasMarkers.js @@ -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(`${station.Name}
${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; diff --git a/hooks/layers/useTalasMarkersLayer.js b/hooks/layers/useTalasMarkersLayer.js new file mode 100644 index 000000000..c90bd6124 --- /dev/null +++ b/hooks/layers/useTalasMarkersLayer.js @@ -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; diff --git a/hooks/layers/useTalasiclMarkersLayer.js b/hooks/layers/useTalasiclMarkersLayer.js new file mode 100644 index 000000000..78ef58e40 --- /dev/null +++ b/hooks/layers/useTalasiclMarkersLayer.js @@ -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; diff --git a/hooks/layers/useUlafMarkersLayer.js b/hooks/layers/useUlafMarkersLayer.js new file mode 100644 index 000000000..d4c5fd897 --- /dev/null +++ b/hooks/layers/useUlafMarkersLayer.js @@ -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(` +
+ ${station.name || "Unbekannt"}
+ ${station.description || "Keine Beschreibung"} +
+ `); + + marker.on("mouseover", function () { + this.openPopup(); + }); + + marker.on("mouseout", function () { + this.closePopup(); + }); + + marker.on("click", async () => { + //const deviceName = await fetchDeviceNameById(station.idLD); + marker + .bindPopup( + ` +
+ ${station.name || "Unbekannt"}
+ ${deviceName}
+ ${station.description || "Keine Beschreibung"} +
+ ` + ) + .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; diff --git a/hooks/layers/useWagoMarkersLayer.js b/hooks/layers/useWagoMarkersLayer.js new file mode 100644 index 000000000..49e033ffe --- /dev/null +++ b/hooks/layers/useWagoMarkersLayer.js @@ -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; diff --git a/hooks/layers/useWdmMarkersLayer.js b/hooks/layers/useWdmMarkersLayer.js new file mode 100644 index 000000000..3393c2d0c --- /dev/null +++ b/hooks/layers/useWdmMarkersLayer.js @@ -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; diff --git a/hooks/useCreateAndSetDevices.js b/hooks/useCreateAndSetDevices.js new file mode 100644 index 000000000..c1fcb9cdf --- /dev/null +++ b/hooks/useCreateAndSetDevices.js @@ -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; diff --git a/hooks/useFetchPoiData.js b/hooks/useFetchPoiData.js new file mode 100644 index 000000000..8683c4d7c --- /dev/null +++ b/hooks/useFetchPoiData.js @@ -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; diff --git a/hooks/useLayerVisibility.js b/hooks/useLayerVisibility.js new file mode 100644 index 000000000..0f1f2236c --- /dev/null +++ b/hooks/useLayerVisibility.js @@ -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; diff --git a/hooks/useLineData-back.js b/hooks/useLineData-back.js new file mode 100644 index 000000000..d1934e36e --- /dev/null +++ b/hooks/useLineData-back.js @@ -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) => `${msg.message}
`).join(""); + + const prioNameDisplay = statis.PrioName && statis.PrioName !== "?" ? `(${statis.PrioName})` : ""; + + colorsByModule[key] = values.messages.length > 0 ? values.messages[0].prioColor : "green"; + + newTooltipContents[key] = ` +
+ ${statis.ModulName || "Unknown"} +
+ ${statis.ModulTyp || "N/A"} +
+ Slot: ${statis.Modul || "N/A"} +
+ Station: ${namesData[matchingLine.idLD] || "N/A"} +
+
+ ${messageDisplay} +
+
+ ${values.messwert ? `Messwert: ${values.messwert}
` : ""} + ${values.schleifenwert ? `Schleifenwert: ${values.schleifenwert}` : ""} +
+ `; + } + }); + + 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; diff --git a/hooks/useLineData.js b/hooks/useLineData.js new file mode 100644 index 000000000..7bf0c8480 --- /dev/null +++ b/hooks/useLineData.js @@ -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) => `${msg.message}
`).join(""); + + const prioNameDisplay = statis.PrioName && statis.PrioName !== "?" ? `(${statis.PrioName})` : ""; + + colorsByModule[key] = values.messages.length > 0 ? values.messages[0].prioColor : "green"; + + newTooltipContents[key] = ` +
+ ${statis.ModulName || "Unknown"} +
+ ${statis.ModulTyp || "N/A"} +
+ Slot: ${statis.Modul || "N/A"} +
+ Station: ${namesData[matchingLine.idLD] || "N/A"} +
+
+ ${messageDisplay} +
+
+ ${values.messwert ? `Messwert: ${values.messwert}
` : ""} + ${values.schleifenwert ? `Schleifenwert: ${values.schleifenwert}` : ""} +
+ `; + } + }); + + 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; diff --git a/hooks/useMapComponentState.js b/hooks/useMapComponentState.js new file mode 100644 index 000000000..7d248a4b7 --- /dev/null +++ b/hooks/useMapComponentState.js @@ -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, + }; +}; diff --git a/hooks/useMarkerLayers.js b/hooks/useMarkerLayers.js new file mode 100644 index 000000000..05422f218 --- /dev/null +++ b/hooks/useMarkerLayers.js @@ -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; diff --git a/hooks/usePoiTypData.js b/hooks/usePoiTypData.js new file mode 100644 index 000000000..7e1ce2d2e --- /dev/null +++ b/hooks/usePoiTypData.js @@ -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; diff --git a/jest.config.js b/jest.config.js index 1c79cab48..d0761486d 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,12 +1,10 @@ module.exports = { - setupFilesAfterEnv: ["/setupTests.js"], + setupFilesAfterEnv: ["/jest.setup.js"], + testEnvironment: "jest-environment-jsdom", + testPathIgnorePatterns: ["/.next/", "/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", }, diff --git a/jest.setup.js b/jest.setup.js index d0de870dc..b44ebd58e 100644 --- a/jest.setup.js +++ b/jest.setup.js @@ -1 +1,3 @@ -import "@testing-library/jest-dom"; +// jest.setup.js +global.fetch = require("jest-fetch-mock"); +jest.setMock("node-fetch", fetch); diff --git a/package-lock.json b/package-lock.json index a9b9a5ddd..0dbe61850 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,43 +5,49 @@ "packages": { "": { "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" }, "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" } }, "node_modules/@adobe/css-tools": { @@ -54,7 +60,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, "engines": { "node": ">=10" }, @@ -79,7 +84,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, "dependencies": { "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" @@ -89,30 +93,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", - "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.2.tgz", + "integrity": "sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -128,12 +132,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", - "dev": true, + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.0.tgz", + "integrity": "sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==", "dependencies": { - "@babel/types": "^7.24.7", + "@babel/types": "^7.25.0", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -168,14 +171,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", - "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "browserslist": "^4.22.2", + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -184,19 +187,17 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.7.tgz", - "integrity": "sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.0.tgz", + "integrity": "sha512-GYM6BxeQsETc9mnct+nIIpf63SAyzvyYN7UB/IlTyd+MBg06afFGp0mIeUqGyWgS2mxad6vqbMrHVlaL3m70sQ==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/traverse": "^7.25.0", "semver": "^6.3.1" }, "engines": { @@ -207,9 +208,9 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.24.7.tgz", - "integrity": "sha512-03TCmXy2FtXJEZfbXDTSqq1fRJArk7lX9DOFC/47VthYcxyIOx+eXQmdo6DOQvrbpIix+KfXwvuXdFDZHxt+rA==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", + "integrity": "sha512-+wqVGP+DFmqwFD3EH6TMTfUNeqDehV3E/dl+Sd54eaXqm17tEUNbEIn4sVivVowbvUpOtIGxdo3GoXyDH9N/9g==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", @@ -239,51 +240,14 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.7.tgz", - "integrity": "sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", "dev": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -293,7 +257,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dev": true, "dependencies": { "@babel/traverse": "^7.24.7", "@babel/types": "^7.24.7" @@ -303,16 +266,15 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", - "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" }, "engines": { "node": ">=6.9.0" @@ -334,23 +296,23 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz", - "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.24.7.tgz", - "integrity": "sha512-9pKLcTlZ92hNZMQfGCHImUpDOlAgkkpqalWEeftW5FBya75k8Li2ilerxkM/uBEj01iBZXcCIB/bwvDYgWyibA==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.0.tgz", + "integrity": "sha512-NhavI2eWEIz/H9dbrG0TuOicDhNexze43i5z7lEqwYm0WEZVTwnPpA0EafUTP7+6/W79HWIP2cTe3Z5NiSTVpw==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-wrap-function": "^7.24.7" + "@babel/helper-wrap-function": "^7.25.0", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -360,14 +322,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", - "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-member-expression-to-functions": "^7.24.7", - "@babel/helper-optimise-call-expression": "^7.24.7" + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -402,23 +364,10 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.24.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true, + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", "engines": { "node": ">=6.9.0" } @@ -427,43 +376,41 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", - "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.24.7.tgz", - "integrity": "sha512-N9JIYk3TD+1vq/wn77YnJOqMtfWhNewNE+DJV4puD2X7Ew9J4JvrzrFDfTfyv5EgEXVy9/Wt8QiOErzEmv5Ifw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.0.tgz", + "integrity": "sha512-s6Q1ebqutSiZnEjaofc/UKDyC4SbzV5n5SrA2Gq8UawLycr3i04f1dX4OzoQVnexm6aOCh37SQNYlJ/8Ku+PMQ==", "dev": true, "dependencies": { - "@babel/helper-function-name": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", - "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", "dev": true, "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -473,7 +420,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", @@ -485,10 +431,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", - "dev": true, + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.3.tgz", + "integrity": "sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==", + "dependencies": { + "@babel/types": "^7.25.2" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -497,13 +445,28 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.7.tgz", - "integrity": "sha512-TiT1ss81W80eQsN+722OaeQMY/G4yTb4G9JrqeiDADs3N8lbPMGldWi9x8tyqCW5NLx1Jh2AvkE6r6QvEltMMQ==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.3.tgz", + "integrity": "sha512-wUrcsxZg6rqBXG05HG1FPYgsP6EvwF4WpBbxIpWIIYnH8wG0gzx3yZY3dtEHas4sTAOGkbTsc9EGPxwff8lRoA==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.0.tgz", + "integrity": "sha512-Bm4bH2qsX880b/3ziJ8KD711LT7z4u8CFudmjqle65AZj/HNUFhEf90dqYv6O86buWvSBmeQDjv0Tn2aF/bIBA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -513,12 +476,12 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.7.tgz", - "integrity": "sha512-unaQgZ/iRu/By6tsjMZzpeBZjChYfLYry6HrEXPoz3KmfF0sVBQ1l8zKMQ4xRGLWVsjuvB8nQfjNP/DcfEOCsg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.0.tgz", + "integrity": "sha512-lXwdNZtTmeVOOFtwM/WDe7yg1PL8sYhRk/XH0FzbR2HDQ0xC+EnQ/JHeoMYSavtU115tnUk0q9CDyq8si+LMAA==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -545,13 +508,13 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.7.tgz", - "integrity": "sha512-utA4HuR6F4Vvcr+o4DnjL8fCOlgRFGbeeBEGNg3ZTrLFw6VWG5XmUrvcQ0FjIYMU2ST4XcR2Wsp7t9qOAPnxMg==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.0.tgz", + "integrity": "sha512-tggFrk1AIShG/RUQbEwt2Tr/E+ObkfwrPjR6BjbRvsx24+PSjK8zrq0GWPNCjo8qpRx4DuJzlcvWJqlm+0h3kw==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -865,15 +828,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.7.tgz", - "integrity": "sha512-o+iF77e3u7ZS4AoAuJvapz9Fm001PuD2V3Lp6OSE4FYQke+cSewYtnek+THqGRWyQloRCyvWL1OkyfNEl9vr/g==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.0.tgz", + "integrity": "sha512-uaIi2FdqzjpAMvVqvB51S42oC2JEVgh0LDsGfZVDysWE8LrJtQC2jvKmOqEYThKyB7bDEb7BP1GYWDm7tABA0Q==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-remap-async-to-generator": "^7.24.7", - "@babel/plugin-syntax-async-generators": "^7.8.4" + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-remap-async-to-generator": "^7.25.0", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -915,12 +878,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", - "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.0.tgz", + "integrity": "sha512-yBQjYoOjXlFv9nlXb3f1casSHOZkWr29NX+zChVanLg5Nc157CrbEX9D7hxxtTpuFy7Q0YzmmWfJxzvps4kXrQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -963,18 +926,16 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.7.tgz", - "integrity": "sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.0.tgz", + "integrity": "sha512-xyi6qjr/fYU304fiRwFbekzkqVJZ6A7hOjWZd+89FVcBqPV3S9Wuozz82xdpLspckeaafntbzglaW4pqpzvtSw==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-replace-supers": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/traverse": "^7.25.0", "globals": "^11.1.0" }, "engines": { @@ -1001,12 +962,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.7.tgz", - "integrity": "sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.8.tgz", + "integrity": "sha512-36e87mfY8TnRxc7yc6M9g9gOB7rKgSahqkIKwLpz4Ppk2+zC2Cy1is0uwtuSG6AE4zlTOUa+7JGz9jCJGLqQFQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1046,6 +1007,22 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.0.tgz", + "integrity": "sha512-YLpb4LlYSc3sCUa35un84poXoraOiQucUTTu8X1j18JV+gNa8E0nyUf/CjZ171IRGr4jEguF+vzJU66QZhn29g==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/plugin-transform-dynamic-import": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.7.tgz", @@ -1111,14 +1088,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", - "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", + "version": "7.25.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.1.tgz", + "integrity": "sha512-TVVJVdW9RKMNgJJlLtHsKDTydjZAbwIsn6ySBPQaEAUU5+gVvlJt/9nRmqVbsV/IBanRjzWoaAQKLoamWVOUuA==", "dev": true, "dependencies": { - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-compilation-targets": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/traverse": "^7.25.1" }, "engines": { "node": ">=6.9.0" @@ -1144,12 +1121,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", - "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.2.tgz", + "integrity": "sha512-HQI+HcTbm9ur3Z2DkO+jgESMAMcYLuN/A7NRw9juzxAezN9AvqvUTnpKP/9kkYANz6u7dFlAyOu44ejuGySlfw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1206,13 +1183,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.7.tgz", - "integrity": "sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.8.tgz", + "integrity": "sha512-WHsk9H8XxRs3JXKWFiqtQebdh9b/pTk4EgueygFzYlTKAg0Ud985mSevdNjdXdFBATSKVJGQXP1tv6aGbssLKA==", "dev": true, "dependencies": { - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.8", + "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-simple-access": "^7.24.7" }, "engines": { @@ -1223,15 +1200,15 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.7.tgz", - "integrity": "sha512-GYQE0tW7YoaN13qFh3O1NCY4MPkUiAH3fiF7UcV/I3ajmDKEdG3l+UOcbAm4zUE3gnvUU+Eni7XrVKo9eO9auw==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.0.tgz", + "integrity": "sha512-YPJfjQPDXxyQWg/0+jHKj1llnY5f/R6a0p/vP4lPymxLu7Lvl4k2WMitqi08yxwQcCVUUdG9LCUj4TNEgAp3Jw==", "dev": true, "dependencies": { - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "@babel/helper-module-transforms": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.0" }, "engines": { "node": ">=6.9.0" @@ -1370,12 +1347,12 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.7.tgz", - "integrity": "sha512-tK+0N9yd4j+x/4hxF3F0e0fu/VdcxU18y5SevtyM/PCFlQvXbR0Zmlo2eBrKtVipGNFzpq56o8WsIIKcJFUCRQ==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.8.tgz", + "integrity": "sha512-5cTOLSMs9eypEy8JUVvIKOu6NgvbJMnpG62VpIHrTmROdQ+L5mDAaI40g25k5vXti55JWNX5jCkq3HZxXBQANw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, @@ -1466,16 +1443,16 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.24.7.tgz", - "integrity": "sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.2.tgz", + "integrity": "sha512-KQsqEAVBpU82NM/B/N9j9WOdphom1SZH3R+2V7INrQUH+V9EBFwZsEJl8eBIVeQE62FxJCc70jzEZwqU7RcVqA==", "dev": true, "dependencies": { "@babel/helper-annotate-as-pure": "^7.24.7", "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.8", "@babel/plugin-syntax-jsx": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.2" }, "engines": { "node": ">=6.9.0" @@ -1608,12 +1585,12 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.7.tgz", - "integrity": "sha512-VtR8hDy7YLB7+Pet9IarXjg/zgCMSF+1mNS/EQEiEaUPoFXCVsHG64SIxcaaI2zJgRiv+YmgaQESUfWAdbjzgg==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.8.tgz", + "integrity": "sha512-adNTUpDCVnmAE58VEqKlAA6ZBlNkMnWD0ZcW76lyNFN3MJniyGFZfNwERVk8Ap56MCnXztmDr19T4mPTztcuaw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.24.7" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -1686,19 +1663,20 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.7.tgz", - "integrity": "sha512-1YZNsc+y6cTvWlDHidMBsQZrZfEFjRIo/BZCT906PMdzOyXtSLTgqGdrpcuTDCXyd11Am5uQULtDIcCfnTc8fQ==", + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.3.tgz", + "integrity": "sha512-QsYW7UeAaXvLPX9tdVliMJE7MD7M6MLYVTovRTIwhoYQVFHR1rM4wO8wqAezYi3/BpSD+NzVCZ69R6smWiIi8g==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-plugin-utils": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.24.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.24.7", + "@babel/compat-data": "^7.25.2", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-validator-option": "^7.24.8", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.3", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.0", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.0", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.24.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.24.7", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.0", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-class-properties": "^7.12.13", @@ -1719,29 +1697,30 @@ "@babel/plugin-syntax-top-level-await": "^7.14.5", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", "@babel/plugin-transform-arrow-functions": "^7.24.7", - "@babel/plugin-transform-async-generator-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.0", "@babel/plugin-transform-async-to-generator": "^7.24.7", "@babel/plugin-transform-block-scoped-functions": "^7.24.7", - "@babel/plugin-transform-block-scoping": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", "@babel/plugin-transform-class-properties": "^7.24.7", "@babel/plugin-transform-class-static-block": "^7.24.7", - "@babel/plugin-transform-classes": "^7.24.7", + "@babel/plugin-transform-classes": "^7.25.0", "@babel/plugin-transform-computed-properties": "^7.24.7", - "@babel/plugin-transform-destructuring": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", "@babel/plugin-transform-dotall-regex": "^7.24.7", "@babel/plugin-transform-duplicate-keys": "^7.24.7", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.0", "@babel/plugin-transform-dynamic-import": "^7.24.7", "@babel/plugin-transform-exponentiation-operator": "^7.24.7", "@babel/plugin-transform-export-namespace-from": "^7.24.7", "@babel/plugin-transform-for-of": "^7.24.7", - "@babel/plugin-transform-function-name": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", "@babel/plugin-transform-json-strings": "^7.24.7", - "@babel/plugin-transform-literals": "^7.24.7", + "@babel/plugin-transform-literals": "^7.25.2", "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", "@babel/plugin-transform-member-expression-literals": "^7.24.7", "@babel/plugin-transform-modules-amd": "^7.24.7", - "@babel/plugin-transform-modules-commonjs": "^7.24.7", - "@babel/plugin-transform-modules-systemjs": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-modules-systemjs": "^7.25.0", "@babel/plugin-transform-modules-umd": "^7.24.7", "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", "@babel/plugin-transform-new-target": "^7.24.7", @@ -1750,7 +1729,7 @@ "@babel/plugin-transform-object-rest-spread": "^7.24.7", "@babel/plugin-transform-object-super": "^7.24.7", "@babel/plugin-transform-optional-catch-binding": "^7.24.7", - "@babel/plugin-transform-optional-chaining": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", "@babel/plugin-transform-parameters": "^7.24.7", "@babel/plugin-transform-private-methods": "^7.24.7", "@babel/plugin-transform-private-property-in-object": "^7.24.7", @@ -1761,7 +1740,7 @@ "@babel/plugin-transform-spread": "^7.24.7", "@babel/plugin-transform-sticky-regex": "^7.24.7", "@babel/plugin-transform-template-literals": "^7.24.7", - "@babel/plugin-transform-typeof-symbol": "^7.24.7", + "@babel/plugin-transform-typeof-symbol": "^7.24.8", "@babel/plugin-transform-unicode-escapes": "^7.24.7", "@babel/plugin-transform-unicode-property-regex": "^7.24.7", "@babel/plugin-transform-unicode-regex": "^7.24.7", @@ -1770,7 +1749,7 @@ "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.10.4", "babel-plugin-polyfill-regenerator": "^0.6.1", - "core-js-compat": "^3.31.0", + "core-js-compat": "^3.37.1", "semver": "^6.3.1" }, "engines": { @@ -1821,10 +1800,9 @@ "dev": true }, "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", - "dev": true, + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.0.tgz", + "integrity": "sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1833,33 +1811,28 @@ } }, "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", - "dev": true, + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", - "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", - "dev": true, + "version": "7.25.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.3.tgz", + "integrity": "sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==", "dependencies": { "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.2", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1868,12 +1841,11 @@ } }, "node_modules/@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.2.tgz", + "integrity": "sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==", "dependencies": { - "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-string-parser": "^7.24.8", "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, @@ -1887,6 +1859,257 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cypress/request": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", + "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "http-signature": "~1.3.6", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "performance-now": "^2.1.0", + "qs": "6.10.4", + "safe-buffer": "^5.1.2", + "tough-cookie": "^4.1.3", + "tunnel-agent": "^0.6.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@cypress/request/node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/@cypress/xvfb": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", + "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", + "dev": true, + "dependencies": { + "debug": "^3.1.0", + "lodash.once": "^4.1.1" + } + }, + "node_modules/@cypress/xvfb/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@emotion/babel-plugin": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz", + "integrity": "sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.2.0", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.13.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.13.1.tgz", + "integrity": "sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz", + "integrity": "sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==" + }, + "node_modules/@emotion/react": { + "version": "11.13.3", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.13.3.tgz", + "integrity": "sha512-lIsdU6JNrmYfJ5EbUCf4xW1ovy5wKQ2CkPRM4xogziOxH1nXxBSjpC9YqbFAP7circxMfYp+6x676BqWcEiixg==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/cache": "^11.13.0", + "@emotion/serialize": "^1.3.1", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.1.tgz", + "integrity": "sha512-dEPNKzBPU+vFPGa+z3axPRn8XVDetYORmDC0wAiej+TNcOZE70ZMJa0X7JdeoM6q/nWTMZeLpN/fTnD9o8MQBA==", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==" + }, + "node_modules/@emotion/styled": { + "version": "11.13.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.13.0.tgz", + "integrity": "sha512-tkzkY7nQhW/zC4hztlwucpT8QEZ6eUzpXDRhww/Eej4tFfO0FxQYWRyg/c5CCXa4d/f174kqeXYjuQRnhzf6dA==", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.12.0", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.0", + "@emotion/use-insertion-effect-with-fallbacks": "^1.1.0", + "@emotion/utils": "^1.4.0" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz", + "integrity": "sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.0.tgz", + "integrity": "sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==" + }, + "node_modules/@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "dependencies": { + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.11.tgz", + "integrity": "sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" + }, "node_modules/@heroicons/react": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@heroicons/react/-/react-2.1.5.tgz", @@ -1899,7 +2122,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -1916,7 +2138,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -1928,7 +2149,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "engines": { "node": ">=12" }, @@ -1939,14 +2159,12 @@ "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -1963,7 +2181,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -1978,7 +2195,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -2442,9 +2658,9 @@ } }, "node_modules/@jest/reporters/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -2708,7 +2924,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -2722,7 +2937,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -2731,27 +2945,274 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mui/core-downloads-tracker": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-6.0.2.tgz", + "integrity": "sha512-Cg68oOlAfbJgMgvbCwcX3Y3HdygCl6X1nREYTdEWcEKUQhNarrC45Cc35mP+zA7p3ZXE/7FLiaTCCgwuSoef/Q==", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + } + }, + "node_modules/@mui/icons-material": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-6.0.2.tgz", + "integrity": "sha512-WaTPSvKcx8X7NdWAHzJWDZv+YXvK0MUY8+JI/r4/q2GgIa5RW+n4+08CGX6jB7sWhU1R3zy28NfsDUwwQjOThw==", + "dependencies": { + "@babel/runtime": "^7.25.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@mui/material": "^6.0.2", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@mui/material/-/material-6.0.2.tgz", + "integrity": "sha512-KrnkJFSyhsAh8V30DNUbWyRyxMi4ZHjFg1ikQGx+mUAIffFTYIEx9Q+Kxd3vCT0FUFGOmbsuh6F6yRhpybsjkg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.25.0", + "@mui/core-downloads-tracker": "^6.0.2", + "@mui/system": "^6.0.2", + "@mui/types": "^7.2.16", + "@mui/utils": "^6.0.2", + "@popperjs/core": "^2.11.8", + "@types/react-transition-group": "^4.4.11", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1", + "react-is": "^18.3.1", + "react-transition-group": "^4.4.5" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@mui/material-pigment-css": "^6.0.2", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@mui/material-pigment-css": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/material/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "peer": true + }, + "node_modules/@mui/private-theming": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.0.2.tgz", + "integrity": "sha512-emddFcRhA0hPGVIwIbW5g0V8vtCgw2g/H/A7jTdGe7dpCWEPpp6jPIXRRKcEUWgmg91R6rBNfV+LFHxBxmZXOQ==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.25.0", + "@mui/utils": "^6.0.2", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/styled-engine": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-6.0.2.tgz", + "integrity": "sha512-qd3Vlhted0SYVGotnCfVNcxff7vW2WN0fclbAexff60NeNS1qs/H/CImHEHUBiUGeNWMPRochbN6VF1arQ7/jA==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.25.0", + "@emotion/cache": "^11.13.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.4.1", + "@emotion/styled": "^11.3.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + } + } + }, + "node_modules/@mui/system": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@mui/system/-/system-6.0.2.tgz", + "integrity": "sha512-AZv1/C4PuHgWFTA8YraIzl3FTVLdRz0RIMRwEADWZBdIhnuTHS/4+r8qE9+3CcpTHg1WsEu8btaO3AhQahSM9A==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.25.0", + "@mui/private-theming": "^6.0.2", + "@mui/styled-engine": "^6.0.2", + "@mui/types": "^7.2.16", + "@mui/utils": "^6.0.2", + "clsx": "^2.1.1", + "csstype": "^3.1.3", + "prop-types": "^15.8.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@emotion/react": "^11.5.0", + "@emotion/styled": "^11.3.0", + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@emotion/react": { + "optional": true + }, + "@emotion/styled": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/types": { + "version": "7.2.16", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.16.tgz", + "integrity": "sha512-qI8TV3M7ShITEEc8Ih15A2vLzZGLhD+/UPNwck/hcls2gwg7dyRjNGXcQYHKLB5Q7PuTRfrTkAoPa2VV1s67Ag==", + "peer": true, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.0.2.tgz", + "integrity": "sha512-TeFrYsxcmeoDSlkoPhX+LjIuuqC5Pyj+xz2kRceKCkUpwMNTEeVOfowXDPe+mboZwmpJ5ZxP4eiAgQMdeEasjg==", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.25.0", + "@mui/types": "^7.2.16", + "@types/prop-types": "^15.7.12", + "clsx": "^2.1.1", + "prop-types": "^15.8.1", + "react-is": "^18.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mui-org" + }, + "peerDependencies": { + "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0", + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@mui/utils/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "peer": true + }, "node_modules/@next/env": { "version": "14.2.5", "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.5.tgz", @@ -2896,7 +3357,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -2909,7 +3369,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -2918,7 +3377,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -2931,20 +3389,66 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "optional": true, "engines": { "node": ">=14" } }, - "node_modules/@react-leaflet/core": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@react-leaflet/core/-/core-2.1.0.tgz", - "integrity": "sha512-Qk7Pfu8BSarKGqILj4x7bCSZ1pjuAPZ+qmRwH5S7mDS91VSbVVsJSrW4qA+GPrro8t69gFYVMWb1Zc4yFmPiVg==", + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@reduxjs/toolkit": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-2.2.7.tgz", + "integrity": "sha512-faI3cZbSdFb8yv9dhDTmGwclW0vk0z5o1cia+kf7gCbaCwHI5e+7tP57mJUv22pNcNbeA62GSrPpfrUfdXcQ6g==", + "dependencies": { + "immer": "^10.0.3", + "redux": "^5.0.1", + "redux-thunk": "^3.1.0", + "reselect": "^5.1.0" + }, "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" + "react": "^16.9.0 || ^17.0.0 || ^18", + "react-redux": "^7.2.1 || ^8.1.3 || ^9.0.0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-redux": { + "optional": true + } + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" } }, "node_modules/@sinclair/typebox": { @@ -2986,9 +3490,9 @@ } }, "node_modules/@testing-library/dom": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.3.1.tgz", - "integrity": "sha512-q/WL+vlXMpC0uXDyfsMtc1rmotzLV8Y0gq6q1gfrrDjQeHoeLrqHbxdPvPNAh1i+xuJl7+BezywcXArz7vLqKQ==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", "dev": true, "peer": true, "dependencies": { @@ -3082,9 +3586,9 @@ } }, "node_modules/@testing-library/jest-dom": { - "version": "6.4.6", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.6.tgz", - "integrity": "sha512-8qpnGVincVDLEcQXWaHOf6zmlbwTKc6Us6PPu4CRnPXCzo2OGBS5cwgMMOWdxDpEz1mkbvXHpEy99M5Yvt682w==", + "version": "6.4.8", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.8.tgz", + "integrity": "sha512-JD0G+Zc38f5MBHA4NgxQMR5XtO5Jx9g86jqturNTt2WUfRmLDIY7iKkWHDCCTiDuFMre6nxAD5wHw9W5kI4rGw==", "dev": true, "dependencies": { "@adobe/css-tools": "^4.4.0", @@ -3100,30 +3604,6 @@ "node": ">=14", "npm": ">=6", "yarn": ">=1" - }, - "peerDependencies": { - "@jest/globals": ">= 28", - "@types/bun": "latest", - "@types/jest": ">= 28", - "jest": ">= 28", - "vitest": ">= 0.32" - }, - "peerDependenciesMeta": { - "@jest/globals": { - "optional": true - }, - "@types/bun": { - "optional": true - }, - "@types/jest": { - "optional": true - }, - "jest": { - "optional": true - }, - "vitest": { - "optional": true - } } }, "node_modules/@testing-library/jest-dom/node_modules/ansi-styles": { @@ -3226,6 +3706,19 @@ } } }, + "node_modules/@testing-library/user-event": { + "version": "14.5.2", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.2.tgz", + "integrity": "sha512-YAh82Wh4TIrxYLmfGcixwD18oIjyC1pFQC2Y01F2lzV2HTMiYrI0nze0FD0ocB//CKS/7jIUgae+adPqxK5yCQ==", + "dev": true, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, "node_modules/@tootallnate/once": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", @@ -3283,11 +3776,12 @@ "@babel/types": "^7.20.7" } }, - "node_modules/@types/geojson": { - "version": "7946.0.14", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", - "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==", - "dev": true + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true, + "peer": true }, "node_modules/@types/graceful-fs": { "version": "4.1.9", @@ -3341,57 +3835,59 @@ "parse5": "^7.0.0" } }, - "node_modules/@types/leaflet": { - "version": "1.9.12", - "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.9.12.tgz", - "integrity": "sha512-BK7XS+NyRI291HIo0HCfE18Lp8oA30H1gpi1tf0mF3TgiCEzanQjOqNZ4x126SXzzi2oNSZhZ5axJp1k0iM6jg==", - "dev": true, - "dependencies": { - "@types/geojson": "*" - } - }, - "node_modules/@types/leaflet-contextmenu": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@types/leaflet-contextmenu/-/leaflet-contextmenu-1.4.3.tgz", - "integrity": "sha512-S2FCwMDtgyuykW9tZ0Wg99FDDdtpoMhmoqGgbrqXvMlQ2Yfl7ZuHJqcmvLZznr48pZjfPuvdkeGzcGkIM3ihYg==", - "dev": true, - "dependencies": { - "@types/leaflet": "*" - } + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true }, "node_modules/@types/node": { - "version": "20.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", - "integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.0.2.tgz", + "integrity": "sha512-yPL6DyFwY5PiMVEwymNeqUTKsDczQBJ/5T7W/46RwLU/VH+AA8aT5TZkvBviLKLbbm0hlfftEkGrNzfRk/fofQ==", "dependencies": { - "undici-types": "~5.26.4" + "undici-types": "~6.11.1" } }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" + }, "node_modules/@types/prop-types": { "version": "15.7.12", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz", - "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==", - "dev": true + "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==" }, "node_modules/@types/react": { - "version": "18.3.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.3.tgz", - "integrity": "sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==", - "dev": true, + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.5.tgz", + "integrity": "sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, - "node_modules/@types/react-dom": { - "version": "18.3.0", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.0.tgz", - "integrity": "sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==", - "dev": true, + "node_modules/@types/react-transition-group": { + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.11.tgz", + "integrity": "sha512-RM05tAniPZ5DZPzzNFP+DmrcOdD0efDUxMy3145oljWSl3x9ZV5vhme98gTxFrj2lhXvmGNnUiuDyJgY9IKkNA==", "dependencies": { "@types/react": "*" } }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", + "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", + "dev": true + }, + "node_modules/@types/sizzle": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.8.tgz", + "integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==", + "dev": true + }, "node_modules/@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", @@ -3404,6 +3900,11 @@ "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", "dev": true }, + "node_modules/@types/use-sync-external-store": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz", + "integrity": "sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==" + }, "node_modules/@types/yargs": { "version": "17.0.32", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", @@ -3419,6 +3920,191 @@ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", + "integrity": "sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz", + "integrity": "sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz", + "integrity": "sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.12.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dev": true, + "peer": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dev": true, + "peer": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==", + "dev": true, + "peer": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz", + "integrity": "sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-opt": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1", + "@webassemblyjs/wast-printer": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz", + "integrity": "sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz", + "integrity": "sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-buffer": "1.12.1", + "@webassemblyjs/wasm-gen": "1.12.1", + "@webassemblyjs/wasm-parser": "1.12.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz", + "integrity": "sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz", + "integrity": "sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==", + "dev": true, + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.12.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "peer": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "peer": true + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -3426,18 +4112,6 @@ "deprecated": "Use your platform's native atob() and btoa() methods instead", "dev": true }, - "node_modules/accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/acorn": { "version": "8.12.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", @@ -3460,6 +4134,16 @@ "acorn-walk": "^8.0.2" } }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "peer": true, + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-walk": { "version": "8.3.3", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", @@ -3484,6 +4168,53 @@ "node": ">= 6.0.0" } }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -3503,7 +4234,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -3512,7 +4242,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -3523,14 +4252,12 @@ "node_modules/any-promise": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -3539,11 +4266,30 @@ "node": ">= 8" } }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" }, "node_modules/argparse": { "version": "1.0.10", @@ -3563,10 +4309,53 @@ "dequal": "^2.0.3" } }, - "node_modules/array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } }, "node_modules/asynckit": { "version": "0.4.0", @@ -3578,7 +4367,6 @@ "version": "10.4.19", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.19.tgz", "integrity": "sha512-BaENR2+zBZ8xXhM4pUaKUxlVdxZ0EZhjvbopwnXmxRUfqDmwSpC2lAi/QXvx7NRdPCo1WKEcEF6mV64si1z4Ew==", - "dev": true, "funding": [ { "type": "opencollective", @@ -3611,6 +4399,29 @@ "postcss": "^8.1.0" } }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.1.tgz", + "integrity": "sha512-+H+kuK34PfMaI9PNU/NSjBKL5hh/KDM9J72kwYeYEm0A8B1AC4fuCy3qsjnA7lxklgyXsB68yn8Z2xoZEjgwCQ==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/aws4": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", + "dev": true + }, "node_modules/babel-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", @@ -3733,6 +4544,20 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.4.11", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz", @@ -3814,8 +4639,45 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } }, "node_modules/bignumber.js": { "version": "9.0.0", @@ -3829,7 +4691,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, "engines": { "node": ">=8" }, @@ -3837,41 +4698,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.2", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } + "node_modules/blob-util": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", + "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", + "dev": true }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -3898,7 +4735,6 @@ "version": "4.23.2", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz", "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==", - "dev": true, "funding": [ { "type": "opencollective", @@ -3935,6 +4771,39 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -3952,18 +4821,20 @@ "node": ">=10.16.0" } }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "node_modules/cachedir": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", + "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==", + "dev": true, "engines": { - "node": ">= 0.8" + "node": ">=6" } }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -3982,7 +4853,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -4000,15 +4870,14 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, "engines": { "node": ">= 6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001641", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001641.tgz", - "integrity": "sha512-Phv5thgl67bHYo1TtMY/MurjkHhV4EDaCosezRXgZ8jzA/Ub+wjxAvbGvjoFENStinwi5kCyOYV3mi5tOGykwA==", + "version": "1.0.30001646", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001646.tgz", + "integrity": "sha512-dRg00gudiBDDTmUhClSdv3hqRfpbOnU28IpI1T6PBTLWa+kOj0681C8uML3PifYfREuBrVjDGhL3adYpBT6spw==", "funding": [ { "type": "opencollective", @@ -4024,11 +4893,16 @@ } ] }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -4047,11 +4921,19 @@ "node": ">=10" } }, + "node_modules/check-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -4075,7 +4957,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -4083,6 +4964,16 @@ "node": ">= 6" } }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.0" + } + }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -4104,6 +4995,58 @@ "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", "dev": true }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/client-only": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", @@ -4151,7 +5094,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -4159,7 +5101,12 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, "node_modules/combined-stream": { @@ -4178,55 +5125,31 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, "engines": { "node": ">= 6" } }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, - "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" - }, "node_modules/core-js-compat": { "version": "3.37.1", "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.1.tgz", @@ -4257,6 +5180,29 @@ "node": ">= 0.10" } }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + }, "node_modules/create-jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", @@ -4315,10 +5261,7 @@ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "color-name": "1.1.3" } }, "node_modules/create-jest/node_modules/color-name": { @@ -4348,11 +5291,61 @@ "node": ">=8" } }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/cross-fetch/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/cross-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "dev": true + }, + "node_modules/cross-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "dev": true + }, + "node_modules/cross-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dev": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -4372,7 +5365,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, "bin": { "cssesc": "bin/cssesc" }, @@ -4407,7 +5399,257 @@ "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" + }, + "node_modules/cypress": { + "version": "13.14.2", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.14.2.tgz", + "integrity": "sha512-lsiQrN17vHMB2fnvxIrKLAjOr9bPwsNbPZNrWf99s4u+DVmCY6U+w7O3GGG9FvP4EUVYaDu+guWeNLiUzBrqvA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@cypress/request": "^3.0.1", + "@cypress/xvfb": "^1.2.4", + "@types/sinonjs__fake-timers": "8.1.1", + "@types/sizzle": "^2.3.2", + "arch": "^2.2.0", + "blob-util": "^2.0.2", + "bluebird": "^3.7.2", + "buffer": "^5.7.1", + "cachedir": "^2.3.0", + "chalk": "^4.1.0", + "check-more-types": "^2.24.0", + "cli-cursor": "^3.1.0", + "cli-table3": "~0.6.1", + "commander": "^6.2.1", + "common-tags": "^1.8.0", + "dayjs": "^1.10.4", + "debug": "^4.3.4", + "enquirer": "^2.3.6", + "eventemitter2": "6.4.7", + "execa": "4.1.0", + "executable": "^4.1.1", + "extract-zip": "2.0.1", + "figures": "^3.2.0", + "fs-extra": "^9.1.0", + "getos": "^3.2.1", + "is-ci": "^3.0.1", + "is-installed-globally": "~0.4.0", + "lazy-ass": "^1.6.0", + "listr2": "^3.8.3", + "lodash": "^4.17.21", + "log-symbols": "^4.0.0", + "minimist": "^1.2.8", + "ospath": "^1.2.2", + "pretty-bytes": "^5.6.0", + "process": "^0.11.10", + "proxy-from-env": "1.0.0", + "request-progress": "^3.0.0", + "semver": "^7.5.3", + "supports-color": "^8.1.1", + "tmp": "~0.2.3", + "untildify": "^4.0.0", + "yauzl": "^2.10.0" + }, + "bin": { + "cypress": "bin/cypress" + }, + "engines": { + "node": "^16.0.0 || ^18.0.0 || >=20.0.0" + } + }, + "node_modules/cypress/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cypress/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cypress/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cypress/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cypress/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/cypress/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cypress/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/cypress/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cypress/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cypress/node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/cypress/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cypress/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/data-urls": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", + "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^11.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dayjs": { + "version": "1.11.13", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz", + "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==", "dev": true }, "node_modules/data-urls": { @@ -4425,9 +5667,9 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", "dependencies": { "ms": "2.1.2" }, @@ -4473,6 +5715,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -4502,14 +5745,6 @@ "node": ">=0.10" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -4519,13 +5754,13 @@ "node": ">=6" } }, - "node_modules/destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" + "node": ">=8" } }, "node_modules/detect-newline": { @@ -4540,8 +5775,16 @@ "node_modules/didyoumean": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } }, "node_modules/diff-sequences": { "version": "29.6.3", @@ -4555,8 +5798,47 @@ "node_modules/dlv": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "peer": true + }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } }, "node_modules/dom-accessibility-api": { "version": "0.5.16", @@ -4581,19 +5863,34 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } }, "node_modules/electron-to-chromium": { - "version": "1.4.824", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.824.tgz", - "integrity": "sha512-GTQnZOP1v0wCuoWzKOxL8rurg9T13QRYISkoICGaZzskBf9laC3V8g9BHTpJv+j9vBRcKOulbGXwMzuzNdVrAA==", - "dev": true + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.4.tgz", + "integrity": "sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } }, "node_modules/emittery": { "version": "0.13.1", @@ -4610,15 +5907,71 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, - "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, "engines": { - "node": ">= 0.8" + "node": ">= 4" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", + "dev": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" } }, "node_modules/entities": { @@ -4646,6 +5999,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -4657,29 +6011,30 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, "engines": { "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.4.tgz", + "integrity": "sha512-MVNK56NiMrOwitFB7cqDwq0CQutbw+0BvLshJSse0MUNU+y1FC3bUS/AQg7oUng+/wKrrki7JfmwtVHkVfPLlw==", + "dev": true, + "peer": true + }, "node_modules/escalade": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", - "dev": true, "engines": { "node": ">=6" } }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -4705,6 +6060,30 @@ "source-map": "~0.6.1" } }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "peer": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "peer": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -4718,6 +6097,19 @@ "node": ">=4" } }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "peer": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", @@ -4736,19 +6128,27 @@ "node": ">=0.10.0" } }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "engines": { - "node": ">= 0.6" - } + "node_modules/eventemitter2": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", + "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", + "dev": true }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "peer": true, + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -4772,6 +6172,18 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "dev": true, + "dependencies": { + "pify": "^2.2.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", @@ -4797,65 +6209,66 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, "dependencies": { - "accepts": "~1.3.8", - "array-flatten": "1.1.1", - "body-parser": "1.20.2", - "content-disposition": "0.5.4", - "content-type": "~1.0.4", - "cookie": "0.6.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "2.0.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "finalhandler": "1.2.0", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", - "methods": "~1.1.2", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", - "proxy-addr": "~2.0.7", - "qs": "6.11.0", - "range-parser": "~1.2.1", - "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "type-is": "~1.6.18", - "utils-merge": "1.0.1", - "vary": "~1.1.2" + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" } }, - "node_modules/express/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, "dependencies": { - "ms": "2.0.0" + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/express/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -4871,7 +6284,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -4889,7 +6301,6 @@ "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -4903,6 +6314,53 @@ "bser": "2.1.1" } }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -4914,35 +6372,10 @@ "node": ">=8" } }, - "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" }, "node_modules/find-up": { "version": "4.1.0", @@ -4980,7 +6413,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", - "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -4996,7 +6428,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "engines": { "node": ">=14" }, @@ -5004,6 +6435,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/form-data": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", @@ -5018,19 +6458,22 @@ "node": ">= 6" } }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "dependencies": { + "fetch-blob": "^3.1.2" + }, "engines": { - "node": ">= 0.6" + "node": ">=12.20.0" } }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", - "dev": true, "engines": { "node": "*" }, @@ -5039,12 +6482,28 @@ "url": "https://github.com/sponsors/rawify" } }, - "node_modules/fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, "engines": { - "node": ">= 0.6" + "node": ">=10" + } + }, + "node_modules/fs-extra/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" } }, "node_modules/fs.realpath": { @@ -5057,7 +6516,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ @@ -5105,6 +6563,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -5140,6 +6599,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/getos": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", + "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", + "dev": true, + "dependencies": { + "async": "^3.2.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -5165,7 +6642,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -5173,11 +6649,32 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true, + "peer": true + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "engines": { "node": ">=4" } @@ -5186,6 +6683,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -5213,7 +6711,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, "engines": { "node": ">=4" } @@ -5222,6 +6719,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, "dependencies": { "es-define-property": "^1.0.0" }, @@ -5233,6 +6731,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -5244,6 +6743,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -5262,6 +6762,19 @@ "node": ">= 0.4" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/html-encoding-sniffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", @@ -5280,21 +6793,6 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/http-proxy": { "version": "1.18.1", "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", @@ -5338,6 +6836,20 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -5361,11 +6873,11 @@ } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" @@ -5383,10 +6895,62 @@ "node": ">=4" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/immer": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/immer/-/immer-10.1.1.tgz", + "integrity": "sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "dependencies": { "pkg-dir": "^4.2.0", @@ -5436,25 +7000,24 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, "engines": { - "node": ">= 0.10" + "node": ">=10" } }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -5462,11 +7025,22 @@ "node": ">=8" } }, - "node_modules/is-core-module": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", - "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.0.tgz", + "integrity": "sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==", "dependencies": { "hasown": "^2.0.2" }, @@ -5489,7 +7063,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -5514,6 +7087,22 @@ "node": ">=0.10.0" } }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5522,6 +7111,15 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", @@ -5556,6 +7154,24 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -5564,7 +7180,12 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, "node_modules/istanbul-lib-coverage": { @@ -5658,7 +7279,6 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -6092,32 +7712,6 @@ "node": ">=8" } }, - "node_modules/jest-css-modules-transform": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/jest-css-modules-transform/-/jest-css-modules-transform-4.4.2.tgz", - "integrity": "sha512-qsUVOcY26chaFMJNMVrFYJBtYvPt1TImi9FWGaVycfsP6xnFW2HlnKRdZdKdg2LVVBv2Q9M4aLv7IbxPSXqPmg==", - "dev": true, - "dependencies": { - "camelcase": "6.3.0", - "postcss": "^7.0.30 || ^8.0.0", - "postcss-nested": "^4.2.1 || ^5.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/jest-css-modules-transform/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/jest-diff": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", @@ -6409,6 +8003,16 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-fetch-mock": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/jest-fetch-mock/-/jest-fetch-mock-3.0.3.tgz", + "integrity": "sha512-Ux1nWprtLrdrH4XwE7O7InRY6psIi3GOsqNESJgMJ+M5cv4A8Lh7SN9d2V2kKRZ8ebAfcd1LNyZguAOb6JiDqw==", + "dev": true, + "dependencies": { + "cross-fetch": "^3.0.4", + "promise-polyfill": "^8.1.3" + } + }, "node_modules/jest-get-type": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", @@ -7197,9 +8801,9 @@ "dev": true }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -7570,7 +9174,6 @@ "version": "1.21.6", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", - "dev": true, "bin": { "jiti": "bin/jiti.js" } @@ -7593,6 +9196,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, "node_modules/jsdom": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", @@ -7642,7 +9251,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -7653,7 +9261,24 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true }, "node_modules/json5": { @@ -7668,6 +9293,42 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonfile/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -7677,6 +9338,15 @@ "node": ">=6" } }, + "node_modules/lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", + "dev": true, + "engines": { + "node": "> 0.8" + } + }, "node_modules/leaflet": { "version": "1.9.4", "resolved": "https://registry.npmjs.org/leaflet/-/leaflet-1.9.4.tgz", @@ -7688,9 +9358,18 @@ "integrity": "sha512-BXASCmJ5bLkuJGDCpWmvGqhZi5AzeOY0IbQalfkgBcMAMfAOFSvD4y0gIQxF/XzEyLkjXaRiUpibVj4+Cf3tUA==" }, "node_modules/leaflet.smooth_marker_bouncing": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/leaflet.smooth_marker_bouncing/-/leaflet.smooth_marker_bouncing-3.0.3.tgz", - "integrity": "sha512-Y+1MJ1nX0vy/NjvzW4Kq2gE3Pnpz3fgP3dZJQNMQW90bFQ8d2TjXrqazP5oWKNUWjvrVVzfMv/FrB7vUFmsLDA==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leaflet.smooth_marker_bouncing/-/leaflet.smooth_marker_bouncing-3.1.0.tgz", + "integrity": "sha512-Gz5DmYwV5UZJCL8xfYLLTn716YF6ljinflf3v/MQSjNdf4G8K8CjGicMXY6ceL3jRJzZ23VihaxeuBaQ6zYDPQ==" + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } }, "node_modules/leven": { "version": "3.1.0", @@ -7705,7 +9384,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, "engines": { "node": ">=10" } @@ -7713,8 +9391,70 @@ "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/listr2": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", + "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "dev": true, + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.1", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "peer": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/locate-path": { "version": "5.0.0", @@ -7731,7 +9471,188 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-update/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/lodash.debounce": { "version": "4.0.8", @@ -7790,9 +9711,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -7810,18 +9731,16 @@ "tmpl": "1.0.5" } }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "engines": { - "node": ">= 0.6" - } + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==" }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true }, "node_modules/merge-stream": { "version": "2.0.0", @@ -7833,19 +9752,10 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "engines": { "node": ">= 8" } }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "engines": { - "node": ">= 0.6" - } - }, "node_modules/micromatch": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", @@ -7858,21 +9768,11 @@ "node": ">=8.6" } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, "engines": { "node": ">= 0.6" } @@ -7881,6 +9781,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -7918,11 +9819,19 @@ "node": "*" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } @@ -7952,10 +9861,11 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/mysql2": { - "version": "3.10.2", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.10.2.tgz", - "integrity": "sha512-KCXPEvAkO0RcHPr362O5N8tFY2fXvbjfkPvRY/wGumh4EOemo9Hm5FjQZqv/pCmrnuxGu5OxnSENG0gTXqKMgQ==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.11.0.tgz", + "integrity": "sha512-J9phbsXGvTOcRVPR95YedzVSxJecpW5A5+cQ57rhHIFXteTP10HCs+VBjS7DHIKfEaI1zQ5tlVrquCd64A6YvA==", "dependencies": { + "aws-ssl-profiles": "^1.1.1", "denque": "^2.1.0", "generate-function": "^2.3.1", "iconv-lite": "^0.6.3", @@ -7969,17 +9879,6 @@ "node": ">= 8.0" } }, - "node_modules/mysql2/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/mysql2/node_modules/lru-cache": { "version": "8.0.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", @@ -8000,7 +9899,6 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, "dependencies": { "any-promise": "^1.0.0", "object-assign": "^4.0.1", @@ -8049,13 +9947,12 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "engines": { - "node": ">= 0.6" - } + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "peer": true }, "node_modules/next": { "version": "14.2.5", @@ -8144,6 +10041,43 @@ "next": "^8.1.1-canary.54 || ^9.0.0 || ^10.0.0-0 || ^11.0.0 || ^12.0.0 || ^13.0.0 || ^14.0.0" } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -8151,16 +10085,14 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -8169,7 +10101,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -8204,7 +10135,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, "engines": { "node": ">= 6" } @@ -8213,6 +10143,7 @@ "version": "1.13.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "dev": true, "engines": { "node": ">= 0.4" }, @@ -8220,17 +10151,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -8255,6 +10175,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ospath": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", + "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", + "dev": true + }, "node_modules/overlapping-marker-spiderfier-leaflet": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/overlapping-marker-spiderfier-leaflet/-/overlapping-marker-spiderfier-leaflet-0.2.7.tgz", @@ -8302,6 +10228,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -8314,14 +10255,23 @@ "node_modules/package-json-from-dist": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -8347,12 +10297,22 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, "engines": { - "node": ">= 0.8" + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/path-exists": { @@ -8377,7 +10337,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -8385,14 +10344,12 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -8407,13 +10364,27 @@ "node_modules/path-scurry/node_modules/lru-cache": { "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", "dev": true }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true }, "node_modules/picocolors": { "version": "1.0.1", @@ -8435,7 +10406,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -8444,7 +10414,6 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, "engines": { "node": ">= 6" } @@ -8462,10 +10431,9 @@ } }, "node_modules/postcss": { - "version": "8.4.39", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.39.tgz", - "integrity": "sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==", - "dev": true, + "version": "8.4.40", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.40.tgz", + "integrity": "sha512-YF2kKIUzAofPMpfH6hOi2cGnv/HrUlfucspc7pDyvv7kGdqXrfj8SCl/t8owkEgKEuu8ZcRjSOxFxVLqwChZ2Q==", "funding": [ { "type": "opencollective", @@ -8493,7 +10461,6 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", @@ -8510,7 +10477,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dev": true, "dependencies": { "camelcase-css": "^2.0.1" }, @@ -8529,7 +10495,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -8564,7 +10529,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "dev": true, "engines": { "node": ">=14" }, @@ -8573,29 +10537,33 @@ } }, "node_modules/postcss-nested": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", - "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", - "dev": true, + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "postcss-selector-parser": "^6.0.6" + "postcss-selector-parser": "^6.1.1" }, "engines": { "node": ">=12.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": "^8.2.14" } }, "node_modules/postcss-selector-parser": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", - "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", - "dev": true, + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.1.tgz", + "integrity": "sha512-b4dlw/9V8A71rLIDsSwVmak9z2DuBUB7CA1/wSdelNEzqsjoSPeADTWNO09lpH49Diy3/JIZ2bSPB1dI3LJCHg==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -8607,22 +10575,55 @@ "node_modules/postcss-value-parser": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, - "node_modules/prettier": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", - "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, "engines": { - "node": ">=14" + "node": ">=6" }, "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" } }, "node_modules/pretty-format": { @@ -8658,6 +10659,12 @@ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, + "node_modules/promise-polyfill": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.3.0.tgz", + "integrity": "sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==", + "dev": true + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -8671,24 +10678,43 @@ "node": ">= 6" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" } }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", + "dev": true + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -8715,9 +10741,10 @@ ] }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "dev": true, "dependencies": { "side-channel": "^1.0.4" }, @@ -8738,7 +10765,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -8754,26 +10780,34 @@ } ] }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "peer": true, + "dependencies": { + "safe-buffer": "^5.1.0" } }, - "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "node_modules/raw-loader": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz", + "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==", + "dev": true, "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" } }, "node_modules/react": { @@ -8806,17 +10840,46 @@ "dev": true, "peer": true }, - "node_modules/react-leaflet": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/react-leaflet/-/react-leaflet-4.2.1.tgz", - "integrity": "sha512-p9chkvhcKrWn/H/1FFeVSqLdReGwn2qmiobOQGO3BifX+/vV/39qhY8dGqbdcPh1e6jxh/QHriLXr7a4eLFK4Q==", + "node_modules/react-redux": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.1.2.tgz", + "integrity": "sha512-0OA4dhM1W48l3uzmv6B7TXPCGmokUU4p1M44DGN2/D9a1FjVPukVjER1PcPX97jIg6aUeLq1XJo1IpfbgULn0w==", "dependencies": { - "@react-leaflet/core": "^2.1.0" + "@types/use-sync-external-store": "^0.0.3", + "use-sync-external-store": "^1.0.0" }, "peerDependencies": { - "leaflet": "^1.9.0", - "react": "^18.0.0", - "react-dom": "^18.0.0" + "@types/react": "^18.2.25", + "react": "^18.0", + "redux": "^5.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "redux": { + "optional": true + } + } + }, + "node_modules/react-select": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.8.0.tgz", + "integrity": "sha512-TfjLDo58XrhP6VG5M/Mi56Us0Yt8X7xD6cDybC7yoRMUNm7BGO7qk8J0TLQOua/prb8vUOtsfnXZwfm30HGsAA==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.8.1", + "@floating-ui/dom": "^1.0.1", + "@types/react-transition-group": "^4.4.0", + "memoize-one": "^6.0.0", + "prop-types": "^15.6.0", + "react-transition-group": "^4.3.0", + "use-isomorphic-layout-effect": "^1.1.2" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "node_modules/react-toastify": { @@ -8831,11 +10894,25 @@ "react-dom": ">=18" } }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, "dependencies": { "pify": "^2.3.0" } @@ -8863,7 +10940,6 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -8903,6 +10979,19 @@ "node": ">=8" } }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, + "node_modules/redux-thunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz", + "integrity": "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw==", + "peerDependencies": { + "redux": "^5.0.0" + } + }, "node_modules/regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -8924,8 +11013,7 @@ "node_modules/regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "node_modules/regenerator-transform": { "version": "0.15.2", @@ -8974,6 +11062,15 @@ "jsesc": "bin/jsesc" } }, + "node_modules/request-progress": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", + "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", + "dev": true, + "dependencies": { + "throttleit": "^1.0.0" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -8988,11 +11085,15 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" }, + "node_modules/reselect": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/reselect/-/reselect-5.1.1.tgz", + "integrity": "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==" + }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -9035,21 +11136,38 @@ "node": ">=10" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -9068,6 +11186,15 @@ "queue-microtask": "^1.2.2" } }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -9112,6 +11239,24 @@ "loose-envify": "^1.1.0" } }, + "node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -9121,70 +11266,26 @@ "semver": "bin/semver.js" } }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, "node_modules/seq-queue": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "peer": true, "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" + "randombytes": "^2.1.0" } }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -9197,16 +11298,10 @@ "node": ">= 0.4" } }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -9218,7 +11313,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -9227,6 +11321,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -9261,6 +11356,53 @@ "node": ">=8" } }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9302,6 +11444,31 @@ "node": ">= 0.6" } }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", @@ -9323,14 +11490,6 @@ "node": ">=8" } }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -9347,11 +11506,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -9369,7 +11523,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9384,7 +11537,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9398,7 +11550,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -9411,7 +11562,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -9483,11 +11633,15 @@ } } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" + }, "node_modules/sucrase": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", "commander": "^4.0.0", @@ -9509,7 +11663,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -9518,7 +11671,6 @@ "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", @@ -9538,7 +11690,6 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -9553,7 +11704,6 @@ "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -9565,7 +11715,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -9580,10 +11729,9 @@ "dev": true }, "node_modules/tailwindcss": { - "version": "3.4.4", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz", - "integrity": "sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==", - "dev": true, + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.7.tgz", + "integrity": "sha512-rxWZbe87YJb4OcSopb7up2Ba4U82BoiSGUdoDr3Ydrg9ckxFS/YWsvhN323GMcddgU65QRy7JndC7ahhInhvlQ==", "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", @@ -9616,23 +11764,127 @@ "node": ">=14.0.0" } }, - "node_modules/tailwindcss/node_modules/postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.6.tgz", + "integrity": "sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==", + "dev": true, + "peer": true, "dependencies": { - "postcss-selector-parser": "^6.0.11" + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" }, "engines": { - "node": ">=12.0" + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dev": true, + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "postcss": "^8.2.14" + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "peer": true + }, + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, "node_modules/test-exclude": { @@ -9653,7 +11905,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, "dependencies": { "any-promise": "^1.0.0" } @@ -9662,7 +11913,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, "dependencies": { "thenify": ">= 3.1.0 < 4" }, @@ -9670,6 +11920,30 @@ "node": ">=0.8" } }, + "node_modules/throttleit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz", + "integrity": "sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "dev": true, + "engines": { + "node": ">=14.14" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -9680,7 +11954,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, "engines": { "node": ">=4" } @@ -9696,12 +11969,31 @@ "node": ">=8.0" } }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, "engines": { - "node": ">=0.6" + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" } }, "node_modules/tough-cookie": { @@ -9734,14 +12026,31 @@ "node_modules/ts-interface-checker": { "version": "0.1.13", "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, "node_modules/tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==" }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, "node_modules/type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -9763,22 +12072,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.11.1.tgz", + "integrity": "sha512-mIDEX2ek50x0OlRgxryxsenE5XaQD4on5U2inY7RApK3SOJpofyw7uW2AyfMKkhAxXIceo2DeWGVGwyvng1GNQ==" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", @@ -9829,19 +12126,19 @@ "node": ">= 4.0.0" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, "node_modules/update-browserslist-db": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -9867,6 +12164,15 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/url-parse": { "version": "1.5.10", "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", @@ -9877,17 +12183,53 @@ "requires-port": "^1.0.0" } }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", + "integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz", + "integrity": "sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, "engines": { - "node": ">= 0.4.0" + "node": ">=10.12.0" } }, "node_modules/v8-to-istanbul": { @@ -9912,6 +12254,26 @@ "node": ">= 0.8" } }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, "node_modules/w3c-xmlserializer": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", @@ -9933,6 +12295,29 @@ "makeerror": "1.0.12" } }, + "node_modules/watchpack": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.2.tgz", + "integrity": "sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==", + "dev": true, + "peer": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -9942,6 +12327,63 @@ "node": ">=12" } }, + "node_modules/webpack": { + "version": "5.94.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.94.0.tgz", + "integrity": "sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg==", + "dev": true, + "peer": true, + "dependencies": { + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.12.1", + "@webassemblyjs/wasm-edit": "^1.12.1", + "@webassemblyjs/wasm-parser": "^1.12.1", + "acorn": "^8.7.1", + "acorn-import-attributes": "^1.9.5", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.17.1", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.11", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "peer": true, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/whatwg-encoding": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", @@ -9954,18 +12396,6 @@ "node": ">=12" } }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/whatwg-mimetype": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", @@ -9992,7 +12422,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -10025,7 +12454,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -10042,7 +12470,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -10057,7 +12484,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -10068,8 +12494,7 @@ "node_modules/wrap-ansi-cjs/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "4.3.0", @@ -10127,7 +12552,6 @@ "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", - "dev": true, "engines": { "node": ">=10.0.0" }, @@ -10175,10 +12599,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.4.5", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", - "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", - "dev": true, + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", + "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", "bin": { "yaml": "bin.mjs" }, @@ -10213,6 +12636,16 @@ "node": ">=12" } }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index bbe4aa838..18b4262b8 100644 --- a/package.json +++ b/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" } } diff --git a/pages/_app.js b/pages/_app.js index fc74da978..1a2213940 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -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 ( - - - + + + + + ); } diff --git a/pages/api - Kopie/[...path].js b/pages/api - Kopie/[...path].js new file mode 100644 index 000000000..b270661b1 --- /dev/null +++ b/pages/api - Kopie/[...path].js @@ -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 +}); diff --git a/pages/api - Kopie/get-talasIP.js b/pages/api - Kopie/get-talasIP.js new file mode 100644 index 000000000..1216fbbb7 --- /dev/null +++ b/pages/api - Kopie/get-talasIP.js @@ -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 }); +} diff --git a/pages/api - Kopie/gis-proxy.js b/pages/api - Kopie/gis-proxy.js new file mode 100644 index 000000000..b76883298 --- /dev/null +++ b/pages/api - Kopie/gis-proxy.js @@ -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") || ""; + }); +}; diff --git a/pages/api - Kopie/linesColorApi.js b/pages/api - Kopie/linesColorApi.js new file mode 100644 index 000000000..57ee59262 --- /dev/null +++ b/pages/api - Kopie/linesColorApi.js @@ -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); +} diff --git a/pages/api - Kopie/rights.js b/pages/api - Kopie/rights.js new file mode 100644 index 000000000..507228147 --- /dev/null +++ b/pages/api - Kopie/rights.js @@ -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: [] }); + } +} diff --git a/pages/api - Kopie/talas5/area.js b/pages/api - Kopie/talas5/area.js new file mode 100644 index 000000000..9205aa5ca --- /dev/null +++ b/pages/api - Kopie/talas5/area.js @@ -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(); + }); + }); +} diff --git a/pages/api - Kopie/talas5/location_device.js b/pages/api - Kopie/talas5/location_device.js new file mode 100644 index 000000000..9292690e0 --- /dev/null +++ b/pages/api - Kopie/talas5/location_device.js @@ -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" }); + } +} diff --git a/pages/api - Kopie/talas5/webserviceMap/GisStationsMeasurements.js b/pages/api - Kopie/talas5/webserviceMap/GisStationsMeasurements.js new file mode 100644 index 000000000..5aba69fc6 --- /dev/null +++ b/pages/api - Kopie/talas5/webserviceMap/GisStationsMeasurements.js @@ -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'); + } + }; \ No newline at end of file diff --git a/pages/api - Kopie/talas5/webserviceMap/GisStationsStaticDistrict.js b/pages/api - Kopie/talas5/webserviceMap/GisStationsStaticDistrict.js new file mode 100644 index 000000000..bf302f3d7 --- /dev/null +++ b/pages/api - Kopie/talas5/webserviceMap/GisStationsStaticDistrict.js @@ -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'); + } + }; \ No newline at end of file diff --git a/pages/api - Kopie/talas5/webserviceMap/GisStationsStatusDistrict.js b/pages/api - Kopie/talas5/webserviceMap/GisStationsStatusDistrict.js new file mode 100644 index 000000000..ae7c25bde --- /dev/null +++ b/pages/api - Kopie/talas5/webserviceMap/GisStationsStatusDistrict.js @@ -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" }); + } +} diff --git a/pages/api - Kopie/talas5/webserviceMap/GisSystemStatic.js b/pages/api - Kopie/talas5/webserviceMap/GisSystemStatic.js new file mode 100644 index 000000000..b2fb56635 --- /dev/null +++ b/pages/api - Kopie/talas5/webserviceMap/GisSystemStatic.js @@ -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'); + } +}; \ No newline at end of file diff --git a/pages/api - Kopie/talas5/webserviceMap/gisStationsMeasurementsSQL.js b/pages/api - Kopie/talas5/webserviceMap/gisStationsMeasurementsSQL.js new file mode 100644 index 000000000..90c535086 --- /dev/null +++ b/pages/api - Kopie/talas5/webserviceMap/gisStationsMeasurementsSQL.js @@ -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); + }); +} diff --git a/pages/api - Kopie/talas_v5_DB/gisLines/readGisLines.js b/pages/api - Kopie/talas_v5_DB/gisLines/readGisLines.js new file mode 100644 index 000000000..d734ed011 --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/gisLines/readGisLines.js @@ -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" }); + } +} diff --git a/pages/api - Kopie/talas_v5_DB/gisLines/updateLineCoordinates.js b/pages/api - Kopie/talas_v5_DB/gisLines/updateLineCoordinates.js new file mode 100644 index 000000000..4271160a0 --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/gisLines/updateLineCoordinates.js @@ -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(); + } +} diff --git a/pages/api - Kopie/talas_v5_DB/locationDevice/getDeviceId.js b/pages/api - Kopie/talas_v5_DB/locationDevice/getDeviceId.js new file mode 100644 index 000000000..8b2326316 --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/locationDevice/getDeviceId.js @@ -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" }); + } +} diff --git a/pages/api - Kopie/talas_v5_DB/locationDevice/locationDeviceNameById.js b/pages/api - Kopie/talas_v5_DB/locationDevice/locationDeviceNameById.js new file mode 100644 index 000000000..575541547 --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/locationDevice/locationDeviceNameById.js @@ -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" }); + } +} diff --git a/pages/api - Kopie/talas_v5_DB/locationDevice/locationDevices.js b/pages/api - Kopie/talas_v5_DB/locationDevice/locationDevices.js new file mode 100644 index 000000000..082dc2929 --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/locationDevice/locationDevices.js @@ -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" }); + } +} diff --git a/pages/api - Kopie/talas_v5_DB/poiTyp/readPoiTyp.js b/pages/api - Kopie/talas_v5_DB/poiTyp/readPoiTyp.js new file mode 100644 index 000000000..baff8f83d --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/poiTyp/readPoiTyp.js @@ -0,0 +1,37 @@ +// pages/api/talas_v5_DB/poiTyp/readPoiTyp.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") { + res.setHeader("Allow", ["GET"]); + return res.status(405).end(`Method ${req.method} Not Allowed`); + } + + const query = "SELECT * FROM poityp"; + + try { + // Ausführen der Abfrage mit dem Verbindungspool + const [results] = await pool.query(query); + + if (results.length === 0) { + return res.status(404).json({ message: "Keine Einträge gefunden" }); + } + + res.status(200).json(results); + } catch (error) { + console.error("Fehler beim Abfragen der Datenbank:", error); + res.status(500).json({ error: "Ein Fehler ist aufgetreten" }); + } +} diff --git a/pages/api - Kopie/talas_v5_DB/pois/addLocation.js b/pages/api - Kopie/talas_v5_DB/pois/addLocation.js new file mode 100644 index 000000000..864835647 --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/pois/addLocation.js @@ -0,0 +1,37 @@ +// pages/api/addLocation.js +import mysql from "mysql"; + +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, + connectionLimit: 10, // Maximale Anzahl gleichzeitiger Verbindungen +}); + +export default function handler(req, res) { + if (req.method === "POST") { + const { name, poiTypeId, latitude, longitude, idLD } = req.body; + console.log("Received data:", req.body); // Überprüfen der empfangenen Daten + + const query = "INSERT INTO poi (description, idPoiTyp, position, idLD) VALUES (?, ?, ST_GeomFromText(?),?)"; + const point = `POINT(${longitude} ${latitude})`; + const values = [name, poiTypeId, point, idLD]; + + // Verwende den Pool, um eine Verbindung zu bekommen und die Query auszuführen + pool.query(query, values, (error, results) => { + if (error) { + console.error("Fehler beim Einfügen des Standorts:", error); + return res.status(500).json({ error: "Ein Fehler ist aufgetreten" }); + } + res.status(200).json({ + id: results.insertId, + message: "Standort erfolgreich hinzugefügt", + }); + }); + } else { + res.setHeader("Allow", ["POST"]); + res.status(405).end(`Method ${req.method} Not Allowed`); + } +} diff --git a/pages/api - Kopie/talas_v5_DB/pois/deletePoi.js b/pages/api - Kopie/talas_v5_DB/pois/deletePoi.js new file mode 100644 index 000000000..e9132bd6b --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/pois/deletePoi.js @@ -0,0 +1,42 @@ +// pages/api/talas_v5_DB/pois/deletePoi.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 !== "DELETE") { + return res.status(405).json({ error: "Nur DELETE Methode erlaubt" }); + } + + const { id } = req.query; // ID aus der Anfrage holen + + if (!id) { + return res.status(400).json({ error: "POI ID ist erforderlich" }); + } + + const query = "DELETE FROM poi WHERE idPoi = ?"; + + try { + // Ausführen der Abfrage mit dem Verbindungspool + const [results] = await pool.query(query, [id]); + + if (results.affectedRows > 0) { + res.status(200).json({ message: "POI erfolgreich gelöscht" }); + } else { + res.status(404).json({ error: "POI nicht gefunden" }); + } + } catch (error) { + console.error("Fehler beim Löschen des POI 3:", error); + res.status(500).json({ error: "Fehler beim Löschen des POI" }); + } +} diff --git a/pages/api - Kopie/talas_v5_DB/pois/getPoiById.js b/pages/api - Kopie/talas_v5_DB/pois/getPoiById.js new file mode 100644 index 000000000..3bd2f1023 --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/pois/getPoiById.js @@ -0,0 +1,43 @@ +// pages/api/talas_v5_DB/pois/getPoiById.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") { + res.setHeader("Allow", ["GET"]); + return res.status(405).end(`Method ${req.method} Not Allowed`); + } + + const { idPoi } = req.query; + + if (!idPoi) { + return res.status(400).json({ error: "idPoi ist erforderlich" }); + } + + const query = "SELECT description FROM poi WHERE idPoi = ?"; + + try { + // Ausführen der Abfrage mit dem Verbindungspool + const [results] = await pool.query(query, [idPoi]); + + if (results.length === 0) { + return res.status(404).json({ error: "POI nicht gefunden" }); + } + + res.status(200).json(results[0]); + } catch (error) { + console.error("Fehler bei der Abfrage:", error); + res.status(500).json({ error: "Fehler bei der Abfrage" }); + } +} diff --git a/pages/api - Kopie/talas_v5_DB/pois/poi-icons.js b/pages/api - Kopie/talas_v5_DB/pois/poi-icons.js new file mode 100644 index 000000000..407704538 --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/pois/poi-icons.js @@ -0,0 +1,36 @@ +// pages/api/talas_v5_DB/pois/poi-icons.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 p.idPoi, i.path + FROM poi p + JOIN poiTyp pt ON p.idPoiTyp = pt.idPoiTyp + JOIN poiicons i ON pt.icon = i.idpoiicons; + `; + + 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 Icons:", error); + res.status(500).json({ error: "Fehler beim Abrufen der Icons" }); + } +} diff --git a/pages/api - Kopie/talas_v5_DB/pois/readLocations.js b/pages/api - Kopie/talas_v5_DB/pois/readLocations.js new file mode 100644 index 000000000..308de78af --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/pois/readLocations.js @@ -0,0 +1,32 @@ +// pages/api/talas_v5_DB/pois/readLocations.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) { + const query = ` + SELECT idPoi, description, idPoiTyp, idLD, ST_AsText(position) AS position + FROM poi + `; + + try { + // Ausführen der Abfrage mit dem Verbindungspool + const [results] = await pool.query(query); + + // Senden der Antwort zurück + res.status(200).json(results); + } catch (error) { + console.error("Fehler beim Abrufen der API:", error); + res.status(500).json({ error: "Fehler bei der Abfrage" }); + } +} diff --git a/pages/api - Kopie/talas_v5_DB/pois/updateLocation.js b/pages/api - Kopie/talas_v5_DB/pois/updateLocation.js new file mode 100644 index 000000000..ee61070f2 --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/pois/updateLocation.js @@ -0,0 +1,82 @@ +// pages/api/talas_v5_DB/pois/updateLocation.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, + charset: "utf8mb4", + waitForConnections: true, + connectionLimit: 10, + queueLimit: 0, +}); + +export default async function handler(req, res) { + if (req.method !== "POST") { + res.setHeader("Allow", ["POST"]); + return res.status(405).end(`Method ${req.method} Not Allowed`); + } + + const { id, latitude, longitude } = req.body; + + if (!id || latitude === undefined || longitude === undefined) { + return res.status(400).json({ error: "id, latitude, und longitude sind erforderlich" }); + } + + const query = "UPDATE poi SET position = POINT(?, ?) WHERE idPoi = ?"; + + try { + const [result] = await pool.query(query, [longitude, latitude, id]); + + if (result.affectedRows > 0) { + res.status(200).json({ success: true }); + } else { + res.status(404).json({ error: "POI nicht gefunden" }); + } + } catch (error) { + console.error("Fehler beim Aktualisieren der Position:", error); + res.status(500).json({ error: "Ein Fehler ist aufgetreten" }); + } +} + +/* import mysql from "mysql"; +import util from "util"; + +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, + charset: "utf8mb4", +}; + +export default async function handler(req, res) { + if (req.method !== "POST") { + res.setHeader("Allow", ["POST"]); + return res.status(405).end(`Method ${req.method} Not Allowed`); + } + + const { id, latitude, longitude } = req.body; + + const connection = mysql.createConnection(dbConfig); + // Promisify the query method + const query = util.promisify(connection.query).bind(connection); + + try { + await query("UPDATE poi SET position = POINT(?, ?) WHERE idPoi = ?", [ + longitude, + latitude, + id, + ]); + res.status(200).json({ success: true }); + } catch (error) { + console.error(error); + res.status(500).json({ error: "Ein Fehler ist aufgetreten" }); + } finally { + connection.end(); + } +} */ diff --git a/pages/api - Kopie/talas_v5_DB/pois/updatePoi.js b/pages/api - Kopie/talas_v5_DB/pois/updatePoi.js new file mode 100644 index 000000000..bc3356a2f --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/pois/updatePoi.js @@ -0,0 +1,45 @@ +// pages/api/talas_v5_DB/pois/updatePoi.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 !== "POST") { + return res.status(405).json({ error: "Nur POST Methode erlaubt" }); + } + + const { idPoi, description, idPoiTyp, idLD } = req.body; + + if (!idPoi) { + return res.status(400).json({ error: "POI ID ist erforderlich" }); + } + + const query = ` + UPDATE talas_v5.poi + SET description = ?, idPoiTyp = ?, idLD = ? + WHERE idPoi = ? + `; + + try { + const [results] = await pool.query(query, [description, idPoiTyp, idLD, idPoi]); + + if (results.affectedRows > 0) { + res.status(200).json({ message: "POI erfolgreich aktualisiert" }); + } else { + res.status(404).json({ error: "POI nicht gefunden" }); + } + } catch (error) { + console.error("Fehler beim Aktualisieren des POI:", error); + res.status(500).json({ error: "Fehler beim Aktualisieren des POI" }); + } +} diff --git a/pages/api - Kopie/talas_v5_DB/priorityConfig.js b/pages/api - Kopie/talas_v5_DB/priorityConfig.js new file mode 100644 index 000000000..719007020 --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/priorityConfig.js @@ -0,0 +1,31 @@ +// pages/api/talas_v5_DB/priorityConfig.js +// in tals5 http://10.10.0.13/talas5/Management/PriorityConfig.aspx beinhaltet die Tabelle prio die Prioritäten der Meldungen (Level 1-4) oder (0-4) je nachdem DB-Design +// das ist die API, die die Prioritäten zurückgibt + +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) { + try { + // Ausführen der Datenbankabfrage + const query = "SELECT idprio, level, name, color FROM prio"; + const results = await pool.query(query); + + // Wichtig: Senden Sie die Antwort zurück + res.status(200).json(results[0]); // Da mysql2 Tuple [rows, fields] zurückgibt, wählen wir nur rows mit [0] + } catch (error) { + console.error("Fehler beim Abrufen der API", error); + res.status(500).json({ error: "Fehler bei der Abfrage" }); + } +} diff --git a/pages/api - Kopie/talas_v5_DB/station/getAllStationsNames.js b/pages/api - Kopie/talas_v5_DB/station/getAllStationsNames.js new file mode 100644 index 000000000..0d5d5ca05 --- /dev/null +++ b/pages/api - Kopie/talas_v5_DB/station/getAllStationsNames.js @@ -0,0 +1,43 @@ +// /pages/api/talas_v5_DB/station/getAllStationsNames.js +import mysql from "mysql2/promise"; + +// Verbindungspool-Konfiguration +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") { + res.setHeader("Allow", ["GET"]); + return res.status(405).end(`Method ${req.method} Not Allowed`); + } + + try { + // Abrufen aller idLD und ihrer Namen + const [results] = await pool.query("SELECT idLD, name FROM location_device"); + + if (results.length === 0) { + return res.status(404).json({ error: "No data found" }); + } + + // Struktur der Antwort anpassen + const namesMap = results.reduce((map, { idLD, name }) => { + if (!map[idLD]) { + map[idLD] = name; // Stelle sicher, dass hier keine Duplikate oder Überschreibungen entstehen + } + return map; + }, {}); + + res.status(200).json(namesMap); + } catch (err) { + console.error("Fehler beim Abrufen der Daten:", err); + res.status(500).json({ error: "Error retrieving data from the database" }); + } +} diff --git a/pages/api back30/[...path].js b/pages/api back30/[...path].js new file mode 100644 index 000000000..0578e8448 --- /dev/null +++ b/pages/api back30/[...path].js @@ -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: `${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 +}); diff --git a/pages/api back30/get-talasIP.js b/pages/api back30/get-talasIP.js new file mode 100644 index 000000000..1216fbbb7 --- /dev/null +++ b/pages/api back30/get-talasIP.js @@ -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 }); +} diff --git a/pages/api back30/gis-proxy.js b/pages/api back30/gis-proxy.js new file mode 100644 index 000000000..b76883298 --- /dev/null +++ b/pages/api back30/gis-proxy.js @@ -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") || ""; + }); +}; diff --git a/pages/api back30/linesColorApi.js b/pages/api back30/linesColorApi.js new file mode 100644 index 000000000..57ee59262 --- /dev/null +++ b/pages/api back30/linesColorApi.js @@ -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); +} diff --git a/pages/api back30/rights.js b/pages/api back30/rights.js new file mode 100644 index 000000000..507228147 --- /dev/null +++ b/pages/api back30/rights.js @@ -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: [] }); + } +} diff --git a/pages/api back30/talas5/area.js b/pages/api back30/talas5/area.js new file mode 100644 index 000000000..9205aa5ca --- /dev/null +++ b/pages/api back30/talas5/area.js @@ -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(); + }); + }); +} diff --git a/pages/api back30/talas5/location_device.js b/pages/api back30/talas5/location_device.js new file mode 100644 index 000000000..8c956f459 --- /dev/null +++ b/pages/api back30/talas5/location_device.js @@ -0,0 +1,39 @@ +// pages/api/talas_v5/location_device.js +// talas_v5 Datenbank -> location_device Tabelle enthält DAUZ Geräte + +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 idLD, iddevice, iddevice, name FROM location_device WHERE iddevice = 160", (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(); + }); + }); +} diff --git a/pages/api back30/talas5/webserviceMap/GisStationsMeasurements.js b/pages/api back30/talas5/webserviceMap/GisStationsMeasurements.js new file mode 100644 index 000000000..5aba69fc6 --- /dev/null +++ b/pages/api back30/talas5/webserviceMap/GisStationsMeasurements.js @@ -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'); + } + }; \ No newline at end of file diff --git a/pages/api back30/talas5/webserviceMap/GisStationsStaticDistrict.js b/pages/api back30/talas5/webserviceMap/GisStationsStaticDistrict.js new file mode 100644 index 000000000..bf302f3d7 --- /dev/null +++ b/pages/api back30/talas5/webserviceMap/GisStationsStaticDistrict.js @@ -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'); + } + }; \ No newline at end of file diff --git a/pages/api back30/talas5/webserviceMap/GisStationsStatusDistrict.js b/pages/api back30/talas5/webserviceMap/GisStationsStatusDistrict.js new file mode 100644 index 000000000..9d0f2024c --- /dev/null +++ b/pages/api back30/talas5/webserviceMap/GisStationsStatusDistrict.js @@ -0,0 +1,100 @@ +import mysql from "mysql2/promise"; + +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, +}; + +export default async function handler(req, res) { + const { idMap, idUser } = req.query; + + if (!idMap || !idUser) { + res.status(400).json({ error: "idMap and idUser are required" }); + return; + } + + let connection; + try { + connection = await mysql.createConnection(dbConfig); + + let onlySystem = -1; + let districtCounter = 0; + + // Get onlySystem + const [mapResult] = await connection.execute( + "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 connection.execute( + "SELECT count(*) as count FROM user_User_layer1 WHERE iduser = ?", + [idUser] + ); + districtCounter = userLayerResult[0].count; + } + + // Get GisStatusStations + 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 + `; + + if (districtCounter > 0) { + query += ` AND a.iddistrict IN (SELECT iddistrict FROM user_user_layer1 WHERE iduser = ?)`; + } + + if (onlySystem >= 0) { + query += ` AND de.idsystem_typ = ?`; + } + + query += ` ORDER BY p.level desc`; + + const queryParams = [idMap]; + if (districtCounter > 0) { + queryParams.push(idUser); + } + if (onlySystem >= 0) { + queryParams.push(onlySystem); + } + + const [results] = await connection.execute(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" }); + } finally { + if (connection) { + await connection.end(); + } + } +} diff --git a/pages/api back30/talas5/webserviceMap/GisSystemStatic.js b/pages/api back30/talas5/webserviceMap/GisSystemStatic.js new file mode 100644 index 000000000..b2fb56635 --- /dev/null +++ b/pages/api back30/talas5/webserviceMap/GisSystemStatic.js @@ -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'); + } +}; \ No newline at end of file diff --git a/pages/api back30/talas5/webserviceMap/gisStationsMeasurementsSQL.js b/pages/api back30/talas5/webserviceMap/gisStationsMeasurementsSQL.js new file mode 100644 index 000000000..de3670b6d --- /dev/null +++ b/pages/api back30/talas5/webserviceMap/gisStationsMeasurementsSQL.js @@ -0,0 +1,70 @@ +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, +}; + +const connection = mysql.createConnection(dbConfig); +connection.connect((err) => { + if (err) { + console.error("Fehler beim Verbinden:", err.stack); + return; + } + console.log("Database connected successfully."); +}); + +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" }); + } + + connection.query(` + 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 = ${idMap} + 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 + `, (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); + }); +} \ No newline at end of file diff --git a/pages/api back30/talas_v5_DB/gisLines/readGisLines.js b/pages/api back30/talas_v5_DB/gisLines/readGisLines.js new file mode 100644 index 000000000..7d8900a83 --- /dev/null +++ b/pages/api back30/talas_v5_DB/gisLines/readGisLines.js @@ -0,0 +1,37 @@ +// /pages/api/talas_v5_DB/gisLines/readGisLines.js +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, +}; + +const connection = mysql.createConnection(dbConfig); +connection.connect((err) => { + if (err) { + console.error("Fehler beim Verbinden:", err.stack); + return; + } + //console.log("Database connected successfully."); +}); + +export default 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;"; + connection.query(query, (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" }); + } + if (results.length > 0) { + res.json(results); + } else { + res.status(404).json({ error: "Gerät nicht gefunden" }); + } + }); +} diff --git a/pages/api back30/talas_v5_DB/gisLines/updateLineCoordinates.js b/pages/api back30/talas_v5_DB/gisLines/updateLineCoordinates.js new file mode 100644 index 000000000..48dfa36bc --- /dev/null +++ b/pages/api back30/talas_v5_DB/gisLines/updateLineCoordinates.js @@ -0,0 +1,61 @@ +// /pages/api/talas_v5_DB/gisLines/updateLineCoordinates.js +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, +}; + +const connection = mysql.createConnection(dbConfig); +connection.connect((err) => { + if (err) { + console.error("Fehler beim Verbinden:", err.stack); + return; + } + //console.log("Database connected successfully."); +}); + +export default 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 = ?;"; + + connection.beginTransaction((err) => { + if (err) { + throw err; + } + connection.query(query, [newLineString, idLD, idModul], (error, results, fields) => { + if (error) { + return connection.rollback(() => { + console.error("Fehler beim Aktualisieren der gis_lines:", error); + res.status(500).json({ error: "Fehler beim Aktualisieren der gis_lines" }); + }); + } + + connection.commit((err) => { + if (err) { + return connection.rollback(() => { + throw err; + }); + } + console.log("Transaction Complete."); + res.status(200).json({ + success: "Updated successfully.", + affectedRows: results.affectedRows, + }); + }); + }); + }); +} diff --git a/pages/api back30/talas_v5_DB/locationDevice/getDeviceId.js b/pages/api back30/talas_v5_DB/locationDevice/getDeviceId.js new file mode 100644 index 000000000..fa373c80c --- /dev/null +++ b/pages/api back30/talas_v5_DB/locationDevice/getDeviceId.js @@ -0,0 +1,40 @@ +// API in /api/talas_v5_DB/locationDevice/getDeviceId.js +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, +}; + +const connection = mysql.createConnection(dbConfig); +connection.connect((err) => { + if (err) { + console.error("Fehler beim Verbinden:", err.stack); + return; + } +}); + +export default function handler(req, res) { + if (req.method !== "GET") { + return res.status(405).json({ error: "Nur GET Methode erlaubt" }); + } + const { deviceName } = req.query; + + const query = "SELECT idLD FROM location_device WHERE name = ?"; + connection.query(query, [deviceName], (error, results) => { + if (error) { + console.error("Fehler beim Abrufen der Geräte-ID:", error); + return res + .status(500) + .json({ error: "Fehler beim Abrufen der Geräte-ID" }); + } + if (results.length > 0) { + res.json({ idLD: results[0].idLD }); + } else { + res.status(404).json({ error: "Gerät nicht gefunden" }); + } + }); +} diff --git a/pages/api back30/talas_v5_DB/locationDevice/locationDeviceNameById.js b/pages/api back30/talas_v5_DB/locationDevice/locationDeviceNameById.js new file mode 100644 index 000000000..efccd89d9 --- /dev/null +++ b/pages/api back30/talas_v5_DB/locationDevice/locationDeviceNameById.js @@ -0,0 +1,46 @@ +// API in /api/talas_v5_DB/locationDevice/locationDeviceNameById.js +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, +}; + +const connection = mysql.createConnection(dbConfig); +connection.connect((err) => { + if (err) { + console.error("Fehler beim Verbinden:", err.stack); + return; + } +}); + +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; + + try { + const query = "SELECT name FROM location_device WHERE idLD = ?"; + const [results] = await new Promise((resolve, reject) => { + connection.query(query, [idLD], (error, results) => { + if (error) { + return reject(error); + } + resolve(results); + }); + }); + + if (results.length > 0) { + res.json({ name: results[0].name }); + } else { + res.status(404).json({ error: "Gerät nicht gefunden", idLD, results }); + } + } catch (error) { + console.error("Fehler beim Abrufen des Gerätenamens in locationDeviceNameById.js :", error); + res.status(500).json({ error: "Fehler beim Abrufen des Gerätenamens" }); + } +} diff --git a/pages/api back30/talas_v5_DB/locationDevice/locationDevices.js b/pages/api back30/talas_v5_DB/locationDevice/locationDevices.js new file mode 100644 index 000000000..bfaf57654 --- /dev/null +++ b/pages/api back30/talas_v5_DB/locationDevice/locationDevices.js @@ -0,0 +1,35 @@ +// API in /api/talas_v5_DB/locationDevice/locationDevices.js +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, +}; + +const connection = mysql.createConnection(dbConfig); +connection.connect((err) => { + if (err) { + console.error("Fehler beim Verbinden:", err.stack); + return; + } +}); + +export default 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"; + connection.query(query, (error, results) => { + if (error) { + console.error("Fehler beim Abrufen der Geräteinformationen:", error); + return res + .status(500) + .json({ error: "Fehler beim Abrufen der Geräteinformationen" }); + } + res.json(results); + }); +} diff --git a/pages/api back30/talas_v5_DB/poiTyp/readPoiTyp.js b/pages/api back30/talas_v5_DB/poiTyp/readPoiTyp.js new file mode 100644 index 000000000..062c442cd --- /dev/null +++ b/pages/api back30/talas_v5_DB/poiTyp/readPoiTyp.js @@ -0,0 +1,33 @@ +// pages/api/talas_v5_DB/poiTyp/readPoiTyp.js +import mysql from "mysql"; + +const pool = mysql.createPool({ + //connectionLimit: 10, + 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, +}); + +export default function handler(req, res) { + if (req.method === "GET") { + const query = "SELECT * FROM poityp"; + + pool.query(query, (error, results) => { + if (error) { + console.error("Fehler beim Abfragen der Datenbank:", error); + return res.status(500).json({ error: "Ein Fehler ist aufgetreten" }); + } + + if (results.length === 0) { + return res.status(404).json({ message: "Keine Einträge gefunden" }); + } + + res.status(200).json(results); + }); + } else { + res.setHeader("Allow", ["GET"]); + res.status(405).end(`Method ${req.method} Not Allowed`); + } +} diff --git a/pages/api back30/talas_v5_DB/pois/addLocation.js b/pages/api back30/talas_v5_DB/pois/addLocation.js new file mode 100644 index 000000000..118704d7d --- /dev/null +++ b/pages/api back30/talas_v5_DB/pois/addLocation.js @@ -0,0 +1,38 @@ +// pages/api/talas_v5_DB/pois/addLocation.js +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, +}; + +export default function handler(req, res) { + if (req.method === "POST") { + const { name, poiTypeId, latitude, longitude, idLD } = req.body; + console.log("Received data:", req.body); // Überprüfen der empfangenen Daten + const connection = mysql.createConnection(dbConfig); + + const query = + "INSERT INTO poi (description, idPoiTyp, position, idLD) VALUES (?, ?, ST_GeomFromText(?),?)"; + const point = `POINT(${longitude} ${latitude})`; + const values = [name, poiTypeId, point, idLD]; // Stellen Sie sicher, dass poiTypeId korrekt ist + + connection.query(query, values, (error, results) => { + connection.end(); + if (error) { + console.error("Fehler beim Einfügen des Standorts:", error); + return res.status(500).json({ error: "Ein Fehler ist aufgetreten" }); + } + res.status(200).json({ + id: results.insertId, + message: "Standort erfolgreich hinzugefügt", + }); + }); + } else { + res.setHeader("Allow", ["POST"]); + res.status(405).end(`Method ${req.method} Not Allowed`); + } +} diff --git a/pages/api back30/talas_v5_DB/pois/deletePoi.js b/pages/api back30/talas_v5_DB/pois/deletePoi.js new file mode 100644 index 000000000..780a1b755 --- /dev/null +++ b/pages/api back30/talas_v5_DB/pois/deletePoi.js @@ -0,0 +1,45 @@ +// pages/api/talas_v5_DB/pois/deletePoi.js +import mysql from "mysql"; + +// Datenbankkonfiguration +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, +}; + +const connection = mysql.createConnection(dbConfig); +connection.connect((err) => { + if (err) { + console.error("Fehler beim Verbinden:", err.stack); + return; + } + console.log("Verbunden als ID", connection.threadId); +}); + +export default function handler(req, res) { + if (req.method !== "DELETE") { + return res.status(405).json({ error: "Nur DELETE Methode erlaubt" }); + } + + const { id } = req.query; // ID aus der Anfrage holen + + if (!id) { + return res.status(400).json({ error: "POI ID ist erforderlich" }); + } + + const query = "DELETE FROM poi WHERE idPoi = ?"; + connection.query(query, [id], (error, results) => { + if (error) { + console.error("Fehler beim Löschen des POI 4:", error); + return res.status(500).json({ error: "Fehler beim Löschen des POI" }); + } + if (results.affectedRows > 0) { + res.json({ message: "POI erfolgreich gelöscht" }); + } else { + res.status(404).json({ error: "POI nicht gefunden" }); + } + }); +} diff --git a/pages/api back30/talas_v5_DB/pois/getPoiById.js b/pages/api back30/talas_v5_DB/pois/getPoiById.js new file mode 100644 index 000000000..4ebf5b62c --- /dev/null +++ b/pages/api back30/talas_v5_DB/pois/getPoiById.js @@ -0,0 +1,42 @@ +// pages/api/talas_v5_DB/pois/getPoiById.js +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, +}; + +export default function handler(req, res) { + if (req.method === "GET") { + const { idPoi } = req.query; + const connection = mysql.createConnection(dbConfig); + + connection.connect((err) => { + if (err) { + console.error("Fehler beim Verbinden:", err.stack); + return res + .status(500) + .json({ error: "Verbindungsfehler zur Datenbank" }); + } + + const query = "SELECT description FROM poi WHERE idPoi = ?"; + connection.query(query, [idPoi], (error, results) => { + connection.end(); + if (error) { + console.error("Fehler bei der Abfrage:", error); + return res.status(500).json({ error: "Fehler bei der Abfrage" }); + } + if (results.length === 0) { + return res.status(404).json({ error: "POI nicht gefunden" }); + } + res.status(200).json(results[0]); + }); + }); + } else { + res.setHeader("Allow", ["GET"]); + res.status(405).end(`Method ${req.method} Not Allowed`); + } +} diff --git a/pages/api back30/talas_v5_DB/pois/poi-icons.js b/pages/api back30/talas_v5_DB/pois/poi-icons.js new file mode 100644 index 000000000..ee092c226 --- /dev/null +++ b/pages/api back30/talas_v5_DB/pois/poi-icons.js @@ -0,0 +1,42 @@ +// pages/api/talas_v5_DB/pois/poi-icons.js +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, +}; + +const connection = mysql.createConnection(dbConfig); + +connection.connect((err) => { + if (err) { + console.error("Fehler beim Verbinden:", err.stack); + return; + } +}); + +export default function handler(req, res) { + if (req.method !== "GET") { + return res.status(405).json({ error: "Nur GET Methode erlaubt" }); + } + + const query = `SELECT p.idPoi, i.path + FROM poi p + JOIN poiTyp pt ON p.idPoiTyp = pt.idPoiTyp + JOIN poiicons i ON pt.icon = i.idpoiicons;`; + + connection.query(query, (error, results) => { + try { + if (error) { + throw error; + } + res.json(results); + } catch (err) { + console.error("Fehler beim Abrufen der icons:", err); + res.status(500).json({ error: "Fehler beim Abrufen der icons" }); + } + }); +} diff --git a/pages/api back30/talas_v5_DB/pois/readLocations.js b/pages/api back30/talas_v5_DB/pois/readLocations.js new file mode 100644 index 000000000..98a33cc88 --- /dev/null +++ b/pages/api back30/talas_v5_DB/pois/readLocations.js @@ -0,0 +1,42 @@ +// pages/api/talas_v5_DB/pois/readLocations.js +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); + + connection.query("SELECT idPoi, description, idPoiTyp, idLD, ST_AsText(position) AS position FROM poi", (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); + /* console.log( + "--------------- location.js ---------------", + "results in location.js : ", + results, + "---------------------- location.js end ---------------------------" + ); */ + connection.end(); + }); + }); +} diff --git a/pages/api back30/talas_v5_DB/pois/updateLocation.js b/pages/api back30/talas_v5_DB/pois/updateLocation.js new file mode 100644 index 000000000..625be5a75 --- /dev/null +++ b/pages/api back30/talas_v5_DB/pois/updateLocation.js @@ -0,0 +1,39 @@ +// pages/api/talas_v5_DB/pois/updateLocation.js +import mysql from "mysql"; +import util from "util"; + +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, + charset: "utf8mb4", +}; + +export default async function handler(req, res) { + if (req.method !== "POST") { + res.setHeader("Allow", ["POST"]); + return res.status(405).end(`Method ${req.method} Not Allowed`); + } + + const { id, latitude, longitude } = req.body; + + const connection = mysql.createConnection(dbConfig); + // Promisify the query method + const query = util.promisify(connection.query).bind(connection); + + try { + await query("UPDATE poi SET position = POINT(?, ?) WHERE idPoi = ?", [ + longitude, + latitude, + id, + ]); + res.status(200).json({ success: true }); + } catch (error) { + console.error(error); + res.status(500).json({ error: "Ein Fehler ist aufgetreten" }); + } finally { + connection.end(); + } +} diff --git a/pages/api back30/talas_v5_DB/pois/updatePoi.js b/pages/api back30/talas_v5_DB/pois/updatePoi.js new file mode 100644 index 000000000..0eb9eeed3 --- /dev/null +++ b/pages/api back30/talas_v5_DB/pois/updatePoi.js @@ -0,0 +1,46 @@ +// pages/api/talas_v5_DB/pois/updatePoi.js +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, +}; + +const connection = mysql.createConnection(dbConfig); +connection.connect((err) => { + if (err) { + console.error("Fehler beim Verbinden:", err.stack); + return; + } + //console.log("Verbunden als ID", connection.threadId); +}); + +export default function handler(req, res) { + if (req.method !== "POST") { + return res.status(405).json({ error: "Nur POST Methode erlaubt" }); + } + + const { idPoi, description, idPoiTyp, idLD } = req.body; // Stellen Sie sicher, dass die Felder korrekt benannt sind + + //console.log("Empfangene Daten:", req.body); // Loggen der empfangenen Daten zur Überprüfung + + if (!idPoi) { + return res.status(400).json({ error: "POI ID ist erforderlich" }); + } + + const query = "UPDATE talas_v5.poi SET description = ?, idPoiTyp = ?, idLD = ? WHERE idPoi = ?"; + connection.query(query, [description, idPoiTyp, idLD, idPoi], (error, results) => { + if (error) { + console.error("Fehler beim Aktualisieren des POI:", error); + return res.status(500).json({ error: "Fehler beim Aktualisieren des POI" }); + } + if (results.affectedRows > 0) { + res.json({ message: "POI erfolgreich aktualisiert" }); + } else { + res.status(404).json({ error: "POI nicht gefunden" }); + } + }); +} diff --git a/pages/api back30/talas_v5_DB/priorityConfig.js b/pages/api back30/talas_v5_DB/priorityConfig.js new file mode 100644 index 000000000..06bfefe3d --- /dev/null +++ b/pages/api back30/talas_v5_DB/priorityConfig.js @@ -0,0 +1,40 @@ +// pages/api/talas_v5_DB/priorityConfig.js +// in tals5 http://10.10.0.13/talas5/Management/PriorityConfig.aspx beinhaltet die Tabelle prio die Prioritäten der Meldungen (Level 1-4) oder (0-4) je nachdem DB-Design +// das ist die API, die die Prioritäten zurückgibt + +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 idprio, level, name, color FROM prio ", (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(); + }); + }); +} diff --git a/pages/api.zip b/pages/api.zip new file mode 100644 index 000000000..345e83d41 Binary files /dev/null and b/pages/api.zip differ diff --git a/pages/api/[...path].js b/pages/api/[...path].js index febda1fa8..b270661b1 100644 --- a/pages/api/[...path].js +++ b/pages/api/[...path].js @@ -1,11 +1,14 @@ // 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: "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", diff --git a/pages/api/gis-proxy.js b/pages/api/gis-proxy.js new file mode 100644 index 000000000..b76883298 --- /dev/null +++ b/pages/api/gis-proxy.js @@ -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") || ""; + }); +}; diff --git a/pages/api/linesColorApi.js b/pages/api/linesColorApi.js index 8240e17af..57ee59262 100644 --- a/pages/api/linesColorApi.js +++ b/pages/api/linesColorApi.js @@ -19,7 +19,7 @@ export default async function handler(req, res) { Zeitstempel: new Date().toISOString(), // Aktuellen Zeitstempel hinzufügen IdMap: "10", Statis: [ - { + /* { IdLD: 50922, Modul: 1, DpName: "KUE01_Ausfall", @@ -30,7 +30,7 @@ export default async function handler(req, res) { Level: 4, PrioColor: "#FFFF00", PrioName: "system", - Value: "?", + Value: "10 MOhm", }, { IdLD: 25440, @@ -43,7 +43,7 @@ export default async function handler(req, res) { Level: 4, PrioColor: "#FF0000", PrioName: "system", - Value: "?", + Value: "10 MOhm", }, { IdLD: 25440, @@ -55,8 +55,8 @@ export default async function handler(req, res) { Level: 4, PrioColor: "#FF00FF", PrioName: "system", - Value: "?", - }, + Value: "10 MOhm", + }, */ ], }; diff --git a/pages/api/talas5/area.js b/pages/api/talas5/area.js index fac90b0da..69f571c97 100644 --- a/pages/api/talas5/area.js +++ b/pages/api/talas5/area.js @@ -1,43 +1,24 @@ // 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"; +import getPool from "../../utils/mysqlPool"; // Verwende den Singleton-Pool -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); +export default async function handler(req, res) { + let connection; - connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - res.status(500).json({ error: "Verbindungsfehler zur Datenbank" }); - return; - } + try { + const pool = getPool(); // Hole den Pool + connection = await pool.getConnection(); // Hole die Verbindung - 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; - } + // Führe die Abfrage aus + const [results] = await connection.query("SELECT id, name FROM area WHERE id = ?", [req.query.id]); - // Wichtig: Senden Sie die Antwort zurück - res.status(200).json(results); - - connection.end(); - } - ); - }); + // Sende die Antwort zurück + res.status(200).json(results); + } catch (error) { + console.error("Fehler beim Abrufen der API", error); + res.status(500).json({ error: "Fehler bei der Abfrage" }); + } finally { + if (connection) connection.release(); // Gib die Verbindung zurück in den Pool + } } diff --git a/pages/api/talas5/location_device.js b/pages/api/talas5/location_device.js index 8a41f779e..40e901412 100644 --- a/pages/api/talas5/location_device.js +++ b/pages/api/talas5/location_device.js @@ -1,42 +1,36 @@ -// pages/api/talas_v5/location_device.js -// talas_v5 Datenbank -> location_device Tabelle enthält DAUZ Geräte +// /pages/api/talas5/location_device.js +import getPool from "../../../utils/mysqlPool"; // Import Singleton-Pool -import mysql from "mysql"; +// API-Handler +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden -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); + let connection; + try { + // SQL-Query, um die Geräteinformationen aus location_device und devices zu erhalten + const sql = ` + SELECT ld.idLD, ld.iddevice, ld.name, d.idsystem_typ + FROM location_device ld + JOIN devices d ON ld.iddevice = d.iddevice + ORDER BY ld.name + `; - connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - res.status(500).json({ error: "Verbindungsfehler zur Datenbank" }); - return; + connection = await pool.getConnection(); + + // Führe die Abfrage durch + const [results] = await connection.query(sql); + + if (!results.length) { + return res.status(404).json({ error: "Keine Geräte gefunden" }); } - console.log("Verbunden als ID", connection.threadId); - //Fehler weil, existiertdie Tabelle auf localhost:3000 nicht - connection.query( - "SELECT idLD, iddevice, iddevice, name FROM location_device WHERE iddevice = 160", - (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(); - } - ); - }); + // Geben Sie die Daten zurück + res.status(200).json(results); + } catch (error) { + // Loggen Sie den Fehler und geben Sie ihn zurück + console.error("Fehler beim Abrufen der Geräteinformationen:", error); + res.status(500).json({ error: "Fehler beim Abrufen der Geräteinformationen" }); + } finally { + if (connection) connection.release(); + } } diff --git a/pages/api/talas5/webserviceMap/GisStationsStatusDistrict.js b/pages/api/talas5/webserviceMap/GisStationsStatusDistrict.js index 9d0f2024c..27b0b442b 100644 --- a/pages/api/talas5/webserviceMap/GisStationsStatusDistrict.js +++ b/pages/api/talas5/webserviceMap/GisStationsStatusDistrict.js @@ -1,47 +1,36 @@ -import mysql from "mysql2/promise"; - -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, -}; +// /pages/api/talas5/webserviceMap/GisStationsStatusDistrict.js +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden + let connection; // Verbindung deklarieren + const { idMap, idUser } = req.query; if (!idMap || !idUser) { - res.status(400).json({ error: "idMap and idUser are required" }); - return; + return res.status(400).json({ error: "idMap and idUser are required" }); } - let connection; try { - connection = await mysql.createConnection(dbConfig); + // Verbindung aus dem Pool holen + connection = await pool.getConnection(); let onlySystem = -1; let districtCounter = 0; // Get onlySystem - const [mapResult] = await connection.execute( - "SELECT idsystem_typ FROM maps WHERE id = ?", - [idMap] - ); + const [mapResult] = await connection.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 connection.execute( - "SELECT count(*) as count FROM user_User_layer1 WHERE iduser = ?", - [idUser] - ); + const [userLayerResult] = await connection.query("SELECT count(*) as count FROM user_User_layer1 WHERE iduser = ?", [idUser]); districtCounter = userLayerResult[0].count; } - // Get GisStatusStations + // Query erstellen let query = ` SELECT ld.idLD, dc.message, p.level, p.name, p.color, ld.idDevice, de.isService, dc.idIcon FROM location as l @@ -55,25 +44,18 @@ export default async function handler(req, res) { WHERE p.level < 100 AND co.X > 0 `; - if (districtCounter > 0) { - query += ` AND a.iddistrict IN (SELECT iddistrict FROM user_user_layer1 WHERE iduser = ?)`; - } - - if (onlySystem >= 0) { - query += ` AND de.idsystem_typ = ?`; - } - - query += ` ORDER BY p.level desc`; - 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 connection.execute(query, queryParams); + const [results] = await connection.query(query, queryParams); const mpss = { IdMap: idMap.toString(), @@ -93,8 +75,7 @@ export default async function handler(req, res) { console.error("Fehler beim Laden der Daten:", error); res.status(500).json({ error: "Interner Serverfehler" }); } finally { - if (connection) { - await connection.end(); - } + // Stelle sicher, dass die Verbindung zurück in den Pool gegeben wird + if (connection) connection.release(); } } diff --git a/pages/api/talas5/webserviceMap/gisStationsMeasurementsSQL.js b/pages/api/talas5/webserviceMap/gisStationsMeasurementsSQL.js index de3670b6d..7912816d4 100644 --- a/pages/api/talas5/webserviceMap/gisStationsMeasurementsSQL.js +++ b/pages/api/talas5/webserviceMap/gisStationsMeasurementsSQL.js @@ -1,29 +1,15 @@ -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, -}; - -const connection = mysql.createConnection(dbConfig); -connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - return; - } - console.log("Database connected successfully."); -}); +// /pages/api/talas5/webserviceMap/gisStationsMeasurementsSQL.js +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren export default function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden + const idMap = req.query.idMap; if (req.method !== "GET") { return res.status(405).json({ error: "Nur GET Methode erlaubt" }); } - connection.query(` + const sqlQuery = ` SELECT ld.idLD, dp.idDP, @@ -34,37 +20,37 @@ export default function handler(req, res) { 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 = ${idMap} + 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 - `, (error, results) => { + `; + + 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" }); + 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) => ({ + 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, + IdLocation: row.idLocation, Area_Name: row.Area_Name, })), }; res.json(response); }); -} \ No newline at end of file +} diff --git a/pages/api/talas_v5_DB/device/getAllStationsNames.js b/pages/api/talas_v5_DB/device/getAllStationsNames.js new file mode 100644 index 000000000..68299296c --- /dev/null +++ b/pages/api/talas_v5_DB/device/getAllStationsNames.js @@ -0,0 +1,39 @@ +// /pages/api/talas_v5_DB/device/getAllStationsNames.js +import getPool from "../../../../utils/mysqlPool"; // Importiere den Singleton-Pool + +export default async function handler(req, res) { + const pool = getPool(); // Verwende den Singleton-Pool + + if (req.method !== "GET") { + res.setHeader("Allow", ["GET"]); + return res.status(405).end(`Method ${req.method} Not Allowed`); + } + + let connection; + + try { + connection = await pool.getConnection(); // Hole eine Verbindung aus dem Pool + + // Abrufen aller idLD und ihrer Namen + const [results] = await connection.query("SELECT idLD, name FROM location_device"); + + if (results.length === 0) { + return res.status(404).json({ error: "No data found" }); + } + + // Struktur der Antwort anpassen + const namesMap = results.reduce((map, { idLD, name }) => { + if (!map[idLD]) { + map[idLD] = name; // Stelle sicher, dass hier keine Duplikate oder Überschreibungen entstehen + } + return map; + }, {}); + + res.status(200).json(namesMap); + } catch (err) { + console.error("Fehler beim Abrufen der Daten:", err); + res.status(500).json({ error: "Error retrieving data from the database" }); + } finally { + if (connection) connection.release(); // Gib die Verbindung zurück in den Pool + } +} diff --git a/pages/api/talas_v5_DB/device/getAllStationsNamesMock.js b/pages/api/talas_v5_DB/device/getAllStationsNamesMock.js new file mode 100644 index 000000000..34b80f812 --- /dev/null +++ b/pages/api/talas_v5_DB/device/getAllStationsNamesMock.js @@ -0,0 +1,46 @@ +// /pages/api/talas_v5_DB/device/getAllStationsNamesMock.js + +export default function handler(req, res) { + // JSON-Daten hier + const stationNames = { + 50035: "CPL Schulungssystem", + 50036: "CPL Varel", + 50039: "MIO Schulungssystem", + 50040: "LTE-Modem Belecke", + 50041: "LTE-Modem Halver", + 50042: "LTE-Modem Lipperbruch", + 50043: "GMA Bunde", + 50044: "GMA Albrechtsplatz", + 50045: "Cisco Router Engelbert", + 50046: "Cisco-Router Schmallenberg", + 50050: "GMA Testgerät", + 50051: "GMA Beleke", + 50052: "Router 1", + 50055: "Testgerät 2", + 50063: "Testgerät 1", + 50064: "CPL Meldestation A", + 50066: "CPL USV Raum", + 50067: "Kontrollmodul 1", + 50068: "Kontrollmodul 2", + 50071: "Testgerät MIK-245", + 50076: "SMS Funkmodem", + 50077: "Notrufserver", + 50078: "OGETest", + 50079: "OGETest", + 50080: "Insel", + 50081: "CPL Test", + 50082: "Buchhaim", + 50083: "Zählstelle B35", + 50084: "TEST JOL", + 50085: "KH Westerstede (Master CPL 232)", + 50086: "KH Oldenburg CPL 2 (Master CPL 233)", + 50087: "PWC Gebäude A (LON, Slave von 232)", + 50088: "PWC Gebäude B (CPL 231, Slave von 232)", + 50089: "LR 77", + 50091: "DC Server", + 50092: "DZ WIS 1", + }; + + // Sende die JSON-Daten als Antwort + res.status(200).json(stationNames); +} diff --git a/pages/api/talas_v5_DB/device/getAllStationsNamesMock.json b/pages/api/talas_v5_DB/device/getAllStationsNamesMock.json new file mode 100644 index 000000000..ad867d096 --- /dev/null +++ b/pages/api/talas_v5_DB/device/getAllStationsNamesMock.json @@ -0,0 +1,751 @@ +{ + "Name": "Liste aller Statis der Linien", + "Zeitstempel": "2024-09-09T12:29:42.5075786+02:00", + "IdMap": "12", + "Statis": [ + { + "IdLD": 50035, + "Modul": 4, + "DpName": "KUE04_Messwertalarm", + "ModulName": "Ost LWL", + "ModulTyp": "Kü605µF", + "Message": "KÜG 04: Isolationsminderung kommend", + "Level": 2, + "PrioColor": "#FF9900", + "PrioName": "major", + "Value": "True" + }, + { + "IdLD": 50035, + "Modul": 3, + "DpName": "KUE03_Aderbruch", + "ModulName": "Ost", + "ModulTyp": "Kü705-FO", + "Message": "KÜG 03: Aderbruch kommend", + "Level": 1, + "PrioColor": "#FF0000", + "PrioName": "critical", + "Value": "?" + }, + { + "IdLD": 50035, + "Modul": 4, + "DpName": "KUE04_Aderbruch", + "ModulName": "Ost LWL", + "ModulTyp": "Kü605µF", + "Message": "KÜG 04: Aderbruch kommend", + "Level": 1, + "PrioColor": "#FF0000", + "PrioName": "critical", + "Value": "?" + }, + { + "IdLD": 50035, + "Modul": 5, + "DpName": "KUE05_Aderbruch", + "ModulName": " West", + "ModulTyp": "Kü605µC", + "Message": "KÜG 05: Aderbruch kommend", + "Level": 1, + "PrioColor": "#FF0000", + "PrioName": "critical", + "Value": "?" + }, + { + "IdLD": 50035, + "Modul": 6, + "DpName": "KUE06_Aderbruch", + "ModulName": "K54 AP12", + "ModulTyp": "Kü705-FO", + "Message": "KÜG 06: Aderbruch kommend", + "Level": 1, + "PrioColor": "#FF0000", + "PrioName": "critical", + "Value": "?" + }, + { + "IdLD": 50035, + "Modul": 1, + "DpName": "KUE01_Messwert", + "ModulName": "Nord", + "ModulTyp": "Kü705-FO", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "51.5 MOhm" + }, + { + "IdLD": 50035, + "Modul": 2, + "DpName": "KUE02_Messwert", + "ModulName": "Süd", + "ModulTyp": "Kü705-FO", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "30 MOhm" + }, + { + "IdLD": 50035, + "Modul": 6, + "DpName": "KUE06_Messwert", + "ModulName": "K54 AP12", + "ModulTyp": "Kü705-FO", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0 MOhm" + }, + { + "IdLD": 50035, + "Modul": 7, + "DpName": "KUE07_Messwert", + "ModulName": "Kreuzung 50Hz", + "ModulTyp": "KÜSS V2", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0 MOhm" + }, + { + "IdLD": 50035, + "Modul": 8, + "DpName": "KUE08_Messwert", + "ModulName": "Querung EWE", + "ModulTyp": "KÜSS V2", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0 MOhm" + }, + { + "IdLD": 50035, + "Modul": 21, + "DpName": "KUE21_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.61 MOhm" + }, + { + "IdLD": 50035, + "Modul": 22, + "DpName": "KUE22_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.72 MOhm" + }, + { + "IdLD": 50035, + "Modul": 1, + "DpName": "KUE01_Schleifenwert", + "ModulName": "Nord", + "ModulTyp": "Kü705-FO", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.61 kOhm" + }, + { + "IdLD": 50035, + "Modul": 2, + "DpName": "KUE02_Schleifenwert", + "ModulName": "Süd", + "ModulTyp": "Kü705-FO", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.79 kOhm" + }, + { + "IdLD": 50035, + "Modul": 4, + "DpName": "KUE04_Schleifenwert", + "ModulName": "Ost LWL", + "ModulTyp": "Kü605µF", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "64.01 kOhm" + }, + { + "IdLD": 50035, + "Modul": 5, + "DpName": "KUE05_Schleifenwert", + "ModulName": " West", + "ModulTyp": "Kü605µC", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "64.01 kOhm" + }, + { + "IdLD": 50035, + "Modul": 6, + "DpName": "KUE06_Schleifenwert", + "ModulName": "K54 AP12", + "ModulTyp": "Kü705-FO", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0 kOhm" + }, + { + "IdLD": 50035, + "Modul": 7, + "DpName": "KUE07_Schleifenwert", + "ModulName": "Kreuzung 50Hz", + "ModulTyp": "KÜSS V2", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0 kOhm" + }, + { + "IdLD": 50035, + "Modul": 8, + "DpName": "KUE08_Schleifenwert", + "ModulName": "Querung EWE", + "ModulTyp": "KÜSS V2", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0 kOhm" + }, + { + "IdLD": 50036, + "Modul": 1, + "DpName": "KUE01_Messwert", + "ModulName": "Friedrichsfehn", + "ModulTyp": "Kü705-FO", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "10.5 MOhm" + }, + { + "IdLD": 50036, + "Modul": 2, + "DpName": "KUE02_Messwert", + "ModulName": "Köln", + "ModulTyp": "Kü605µC", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "10 MOhm" + }, + { + "IdLD": 50036, + "Modul": 3, + "DpName": "KUE03_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "200 MOhm" + }, + { + "IdLD": 50036, + "Modul": 4, + "DpName": "KUE04_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0 MOhm" + }, + { + "IdLD": 50036, + "Modul": 5, + "DpName": "KUE05_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "11.5 MOhm" + }, + { + "IdLD": 50036, + "Modul": 8, + "DpName": "KUE08_Messwert", + "ModulName": "Köln", + "ModulTyp": "KÜSS V2", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0 Events" + }, + { + "IdLD": 50036, + "Modul": 9, + "DpName": "KUE09_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "11 MOhm" + }, + { + "IdLD": 50036, + "Modul": 10, + "DpName": "KUE10_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "11 MOhm" + }, + { + "IdLD": 50036, + "Modul": 11, + "DpName": "KUE11_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "11 MOhm" + }, + { + "IdLD": 50036, + "Modul": 12, + "DpName": "KUE12_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "11 MOhm" + }, + { + "IdLD": 50036, + "Modul": 1, + "DpName": "KUE01_Schleifenwert", + "ModulName": "Friedrichsfehn", + "ModulTyp": "Kü705-FO", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "2.32 kOhm" + }, + { + "IdLD": 50036, + "Modul": 2, + "DpName": "KUE02_Schleifenwert", + "ModulName": "Köln", + "ModulTyp": "Kü605µC", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "2.15 kOhm" + }, + { + "IdLD": 50036, + "Modul": 6, + "DpName": "KUE06_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "64.01 kOhm" + }, + { + "IdLD": 50036, + "Modul": 7, + "DpName": "KUE07_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "64.01 kOhm" + }, + { + "IdLD": 50036, + "Modul": 8, + "DpName": "KUE08_Schleifenwert", + "ModulName": "Köln", + "ModulTyp": "KÜSS V2", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0 kOhm" + }, + { + "IdLD": 50071, + "Modul": 1, + "DpName": "KUE01_Messwert", + "ModulName": "Test 1", + "ModulTyp": "Kü705-FO", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.1 MOhm" + }, + { + "IdLD": 50071, + "Modul": 2, + "DpName": "KUE02_Messwert", + "ModulName": "Test 2", + "ModulTyp": "Kü705-FO", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.1 MOhm" + }, + { + "IdLD": 50071, + "Modul": 3, + "DpName": "KUE03_Messwert", + "ModulName": "Test 3", + "ModulTyp": "Kü705-FO", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.1 MOhm" + }, + { + "IdLD": 50071, + "Modul": 4, + "DpName": "KUE04_Messwert", + "ModulName": "Test 4", + "ModulTyp": "Kü605µF", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.1 MOhm" + }, + { + "IdLD": 50071, + "Modul": 5, + "DpName": "KUE05_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.1 MOhm" + }, + { + "IdLD": 50071, + "Modul": 6, + "DpName": "KUE06_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.1 MOhm" + }, + { + "IdLD": 50071, + "Modul": 7, + "DpName": "KUE07_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.1 Events" + }, + { + "IdLD": 50071, + "Modul": 8, + "DpName": "KUE08_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "51 Events" + }, + { + "IdLD": 50071, + "Modul": 11, + "DpName": "KUE11_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.59 kOhm" + }, + { + "IdLD": 50071, + "Modul": 12, + "DpName": "KUE12_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.61 kOhm" + }, + { + "IdLD": 50071, + "Modul": 13, + "DpName": "KUE13_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.58 kOhm" + }, + { + "IdLD": 50071, + "Modul": 14, + "DpName": "KUE14_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.6 kOhm" + }, + { + "IdLD": 50071, + "Modul": 15, + "DpName": "KUE15_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.6 kOhm" + }, + { + "IdLD": 50071, + "Modul": 16, + "DpName": "KUE16_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0.57 kOhm" + }, + { + "IdLD": 50082, + "Modul": 6, + "DpName": "KUE06_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0 MOhm" + }, + { + "IdLD": 50082, + "Modul": 7, + "DpName": "KUE07_Messwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "10 MOhm" + }, + { + "IdLD": 50082, + "Modul": 6, + "DpName": "KUE06_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0 kOhm" + }, + { + "IdLD": 50082, + "Modul": 7, + "DpName": "KUE07_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "2.74 kOhm" + }, + { + "IdLD": 50086, + "Modul": 1, + "DpName": "KUE01_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "201 kOhm" + }, + { + "IdLD": 50086, + "Modul": 2, + "DpName": "KUE02_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "201 kOhm" + }, + { + "IdLD": 50086, + "Modul": 3, + "DpName": "KUE03_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "201 kOhm" + }, + { + "IdLD": 50086, + "Modul": 4, + "DpName": "KUE04_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "0 kOhm" + }, + { + "IdLD": 50086, + "Modul": 11, + "DpName": "KUE11_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "4.01 kOhm" + }, + { + "IdLD": 50086, + "Modul": 12, + "DpName": "KUE12_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "4.01 kOhm" + }, + { + "IdLD": 50086, + "Modul": 13, + "DpName": "KUE13_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "4.01 kOhm" + }, + { + "IdLD": 50086, + "Modul": 14, + "DpName": "KUE14_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "4.01 kOhm" + }, + { + "IdLD": 50086, + "Modul": 15, + "DpName": "KUE15_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "4.01 kOhm" + }, + { + "IdLD": 50086, + "Modul": 16, + "DpName": "KUE16_Schleifenwert", + "ModulName": "?", + "ModulTyp": "?", + "Message": "?", + "Level": -1, + "PrioColor": "#ffffff", + "PrioName": "?", + "Value": "4.01 kOhm" + } + ] +} \ No newline at end of file diff --git a/pages/api/talas_v5_DB/device/getDevices.js b/pages/api/talas_v5_DB/device/getDevices.js new file mode 100644 index 000000000..4bc41e534 --- /dev/null +++ b/pages/api/talas_v5_DB/device/getDevices.js @@ -0,0 +1,32 @@ +// /pages/api/talas_v5_DB/device/getDevices.js +import getPool from "../../../../utils/mysqlPool"; // Import Singleton-Pool + +// API-Handler +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden + + let connection; + try { + // Lade die Daten der aktiven Systeme aus localStorage, z.B. über einen Parameter oder Body + const { activeSystems } = req.body || []; // Array von aktiven system_typ IDs + + // SQL-Query: Verknüpfe die Tabellen location_device, devices und system_typ + const sql = `SELECT * FROM devices`; + + connection = await pool.getConnection(); + + // Führe die Abfrage mit den aktiven Systems durch + const [results] = await connection.query(sql); + + if (!results.length) { + return res.status(404).json({ error: "Keine passenden Geräte gefunden" }); + } + + res.status(200).json(results); + } catch (error) { + console.error("Fehler beim Abrufen der gefilterten Geräteinformationen:", error); + res.status(500).json({ error: "Fehler beim Abrufen der Geräteinformationen" }); + } finally { + if (connection) connection.release(); + } +} diff --git a/pages/api/talas_v5_DB/gisLines/readGisLines.js b/pages/api/talas_v5_DB/gisLines/readGisLines.js index 709feeb2d..5bb3ce7f7 100644 --- a/pages/api/talas_v5_DB/gisLines/readGisLines.js +++ b/pages/api/talas_v5_DB/gisLines/readGisLines.js @@ -1,39 +1,30 @@ // /pages/api/talas_v5_DB/gisLines/readGisLines.js -import mysql from "mysql"; +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren -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, -}; +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden + let connection; -const connection = mysql.createConnection(dbConfig); -connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - return; - } - console.log("Database connected successfully."); -}); - -export default 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;"; - connection.query(query, (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" }); - } + + try { + // Verbindung aus dem Pool holen + connection = await pool.getConnection(); + // Abfrage ausführen + const [results] = await connection.query(query); if (results.length > 0) { - res.json(results); + 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" }); + } finally { + if (connection) connection.release(); // Verbindung freigeben + } } diff --git a/pages/api/talas_v5_DB/gisLines/readGisLinesMock.js b/pages/api/talas_v5_DB/gisLines/readGisLinesMock.js new file mode 100644 index 000000000..bad20059e --- /dev/null +++ b/pages/api/talas_v5_DB/gisLines/readGisLinesMock.js @@ -0,0 +1,303 @@ +// /pages/api/talas_v5_DB/gisLines/readGisLines.js + +export default function handler(req, res) { + // JSON-Daten hier + const data = [ + { + idLD: 50035, + idModul: 1, + points: [ + { + x: 53.246185, + y: 8.162953, + }, + { + x: 53.264596890603144, + y: 8.176574707031252, + }, + ], + }, + { + idLD: 50035, + idModul: 2, + points: [ + { + x: 53.246185, + y: 8.162953, + }, + { + x: 53.258949437816085, + y: 8.157176971435549, + }, + { + x: 53.27568426437073, + y: 8.163356781005861, + }, + ], + }, + { + idLD: 50035, + idModul: 3, + points: [ + { + x: 53.246185, + y: 8.162953, + }, + { + x: 53.25735774823773, + y: 8.213653564453127, + }, + ], + }, + { + idLD: 50035, + idModul: 4, + points: [ + { + x: 53.246185, + y: 8.162953, + }, + { + x: 53.241488959365725, + y: 8.184814453125002, + }, + { + x: 53.232550546124244, + y: 8.200263977050783, + }, + { + x: 53.23049547461783, + y: 8.230476379394533, + }, + { + x: 53.23666039320915, + y: 8.264122009277346, + }, + { + x: 53.242413516276585, + y: 8.217430114746096, + }, + { + x: 53.247138717452785, + y: 8.21880340576172, + }, + { + x: 53.253917442602265, + y: 8.233737945556642, + }, + ], + }, + { + idLD: 50035, + idModul: 5, + points: [ + { + x: 53.246185, + y: 8.162953, + }, + { + x: 53.257922548093866, + y: 8.179321289062502, + }, + { + x: 53.27075689767353, + y: 8.199234008789064, + }, + { + x: 53.269730291457705, + y: 8.237171173095705, + }, + { + x: 53.26665032490112, + y: 8.288583755493166, + }, + ], + }, + { + idLD: 50035, + idModul: 6, + points: [ + { + x: 53.246185, + y: 8.162953, + }, + { + x: 53.243594865485605, + y: 8.169021606445314, + }, + { + x: 53.24015345301049, + y: 8.171596527099611, + }, + { + x: 53.236352168364164, + y: 8.18035125732422, + }, + { + x: 53.23049547461783, + y: 8.185672760009767, + }, + { + x: 53.229159625240165, + y: 8.192882537841799, + }, + { + x: 53.22576843579022, + y: 8.19957733154297, + }, + { + x: 53.21898525115505, + y: 8.201808929443361, + }, + { + x: 53.20891126768285, + y: 8.205413818359377, + }, + { + x: 53.19739524287978, + y: 8.217945098876955, + }, + ], + }, + { + idLD: 50035, + idModul: 7, + points: [ + { + x: 53.246185, + y: 8.162953, + }, + { + x: 53.25063092211432, + y: 8.205242156982424, + }, + { + x: 53.255149822694534, + y: 8.223438262939455, + }, + ], + }, + { + idLD: 50035, + idModul: 8, + points: [ + { + x: 53.246185, + y: 8.162953, + }, + { + x: 53.26048972617302, + y: 8.199234008789064, + }, + { + x: 53.2577171671909, + y: 8.203182220458986, + }, + ], + }, + { + idLD: 50036, + idModul: 1, + points: [ + { + x: 53.39605, + y: 8.10297, + }, + { + x: 53.40605, + y: 8.11297, + }, + ], + }, + { + idLD: 50036, + idModul: 2, + points: [ + { + x: 53.39605, + y: 8.10297, + }, + { + x: 53.40605, + y: 8.12297, + }, + ], + }, + { + idLD: 50036, + idModul: 8, + points: [ + { + x: 53.39605, + y: 8.10297, + }, + { + x: 53.405233950076024, + y: 8.136577606201174, + }, + ], + }, + { + idLD: 50071, + idModul: 1, + points: [ + { + x: 53.45257, + y: 7.91525, + }, + { + x: 53.46257, + y: 7.92525, + }, + ], + }, + { + idLD: 50071, + idModul: 2, + points: [ + { + x: 53.45257, + y: 7.91525, + }, + { + x: 53.46257, + y: 7.93525, + }, + ], + }, + { + idLD: 50071, + idModul: 3, + points: [ + { + x: 53.45257, + y: 7.91525, + }, + { + x: 53.46257, + y: 7.94525, + }, + ], + }, + { + idLD: 50071, + idModul: 4, + points: [ + { + x: 53.45257, + y: 7.91525, + }, + { + x: 53.4516692168179, + y: 7.936935424804688, + }, + { + x: 53.45718897904939, + y: 7.958908081054688, + }, + ], + }, + ]; + // Sende die JSON-Daten als Antwort + res.status(200).json(data); +} diff --git a/pages/api/talas_v5_DB/gisLines/updateLineCoordinates.js b/pages/api/talas_v5_DB/gisLines/updateLineCoordinates.js index d6fa5179f..df5c425e8 100644 --- a/pages/api/talas_v5_DB/gisLines/updateLineCoordinates.js +++ b/pages/api/talas_v5_DB/gisLines/updateLineCoordinates.js @@ -1,24 +1,9 @@ // /pages/api/talas_v5_DB/gisLines/updateLineCoordinates.js -import mysql from "mysql"; +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren -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, -}; +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden -const connection = mysql.createConnection(dbConfig); -connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - return; - } - console.log("Database connected successfully."); -}); - -export default function handler(req, res) { if (req.method !== "POST") { return res.status(405).json({ error: "Nur POST Methode erlaubt" }); } @@ -30,39 +15,34 @@ export default function handler(req, res) { const newLineString = `LINESTRING(${newCoordinates.map((coord) => `${coord[0]} ${coord[1]}`).join(",")})`; - const query = - "UPDATE talas_v5.gis_lines SET points = ST_GeomFromText(?) WHERE idLD = ? AND idModul = ?;"; + const query = "UPDATE talas_v5.gis_lines SET points = ST_GeomFromText(?) WHERE idLD = ? AND idModul = ?;"; - connection.beginTransaction((err) => { - if (err) { - throw err; - } - connection.query( - query, - [newLineString, idLD, idModul], - (error, results, fields) => { - if (error) { - return connection.rollback(() => { - console.error("Fehler beim Aktualisieren der gis_lines:", error); - res - .status(500) - .json({ error: "Fehler beim Aktualisieren der gis_lines" }); - }); - } + let connection; - connection.commit((err) => { - if (err) { - return connection.rollback(() => { - throw err; - }); - } - console.log("Transaction Complete."); - res.status(200).json({ - success: "Updated successfully.", - affectedRows: results.affectedRows, - }); - }); - } - ); - }); + 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 { + if (connection) connection.release(); + } } diff --git a/pages/api/talas_v5_DB/gisLines/webserviceGisLinesStatusUrlMock.js b/pages/api/talas_v5_DB/gisLines/webserviceGisLinesStatusUrlMock.js new file mode 100644 index 000000000..b4f9edcfd --- /dev/null +++ b/pages/api/talas_v5_DB/gisLines/webserviceGisLinesStatusUrlMock.js @@ -0,0 +1,758 @@ +// /pages/api/talas_v5_DB/gisLines/webserviceGisLinesStatusUrlMock.js + +export default function handler(req, res) { + // Deine JSON-Daten hier + const data = { + Name: "Liste aller Statis der Linien", + Zeitstempel: "2024-09-09T12:29:42.5075786+02:00", + IdMap: "12", + Statis: [ + { + IdLD: 50035, + Modul: 4, + DpName: "KUE04_Messwertalarm", + ModulName: "Ost LWL", + ModulTyp: "Kü605µF", + Message: "KÜG 04: Isolationsminderung kommend", + Level: 2, + PrioColor: "#FF9900", + PrioName: "major", + Value: "True", + }, + { + IdLD: 50035, + Modul: 3, + DpName: "KUE03_Aderbruch", + ModulName: "Ost", + ModulTyp: "Kü705-FO", + Message: "KÜG 03: Aderbruch kommend", + Level: 1, + PrioColor: "#FF0000", + PrioName: "critical", + Value: "?", + }, + { + IdLD: 50035, + Modul: 4, + DpName: "KUE04_Aderbruch", + ModulName: "Ost LWL", + ModulTyp: "Kü605µF", + Message: "KÜG 04: Aderbruch kommend", + Level: 1, + PrioColor: "#FF0000", + PrioName: "critical", + Value: "?", + }, + { + IdLD: 50035, + Modul: 5, + DpName: "KUE05_Aderbruch", + ModulName: " West", + ModulTyp: "Kü605µC", + Message: "KÜG 05: Aderbruch kommend", + Level: 1, + PrioColor: "#FF0000", + PrioName: "critical", + Value: "?", + }, + { + IdLD: 50035, + Modul: 6, + DpName: "KUE06_Aderbruch", + ModulName: "K54 AP12", + ModulTyp: "Kü705-FO", + Message: "KÜG 06: Aderbruch kommend", + Level: 1, + PrioColor: "#FF0000", + PrioName: "critical", + Value: "?", + }, + { + IdLD: 50035, + Modul: 1, + DpName: "KUE01_Messwert", + ModulName: "Nord", + ModulTyp: "Kü705-FO", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "51.5 MOhm", + }, + { + IdLD: 50035, + Modul: 2, + DpName: "KUE02_Messwert", + ModulName: "Süd", + ModulTyp: "Kü705-FO", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "30 MOhm", + }, + { + IdLD: 50035, + Modul: 6, + DpName: "KUE06_Messwert", + ModulName: "K54 AP12", + ModulTyp: "Kü705-FO", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0 MOhm", + }, + { + IdLD: 50035, + Modul: 7, + DpName: "KUE07_Messwert", + ModulName: "Kreuzung 50Hz", + ModulTyp: "KÜSS V2", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0 MOhm", + }, + { + IdLD: 50035, + Modul: 8, + DpName: "KUE08_Messwert", + ModulName: "Querung EWE", + ModulTyp: "KÜSS V2", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0 MOhm", + }, + { + IdLD: 50035, + Modul: 21, + DpName: "KUE21_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.61 MOhm", + }, + { + IdLD: 50035, + Modul: 22, + DpName: "KUE22_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.72 MOhm", + }, + { + IdLD: 50035, + Modul: 1, + DpName: "KUE01_Schleifenwert", + ModulName: "Nord", + ModulTyp: "Kü705-FO", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.61 kOhm", + }, + { + IdLD: 50035, + Modul: 2, + DpName: "KUE02_Schleifenwert", + ModulName: "Süd", + ModulTyp: "Kü705-FO", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.79 kOhm", + }, + { + IdLD: 50035, + Modul: 4, + DpName: "KUE04_Schleifenwert", + ModulName: "Ost LWL", + ModulTyp: "Kü605µF", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "64.01 kOhm", + }, + { + IdLD: 50035, + Modul: 5, + DpName: "KUE05_Schleifenwert", + ModulName: " West", + ModulTyp: "Kü605µC", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "64.01 kOhm", + }, + { + IdLD: 50035, + Modul: 6, + DpName: "KUE06_Schleifenwert", + ModulName: "K54 AP12", + ModulTyp: "Kü705-FO", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0 kOhm", + }, + { + IdLD: 50035, + Modul: 7, + DpName: "KUE07_Schleifenwert", + ModulName: "Kreuzung 50Hz", + ModulTyp: "KÜSS V2", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0 kOhm", + }, + { + IdLD: 50035, + Modul: 8, + DpName: "KUE08_Schleifenwert", + ModulName: "Querung EWE", + ModulTyp: "KÜSS V2", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0 kOhm", + }, + { + IdLD: 50036, + Modul: 1, + DpName: "KUE01_Messwert", + ModulName: "Friedrichsfehn", + ModulTyp: "Kü705-FO", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "10.5 MOhm", + }, + { + IdLD: 50036, + Modul: 2, + DpName: "KUE02_Messwert", + ModulName: "Köln", + ModulTyp: "Kü605µC", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "10 MOhm", + }, + { + IdLD: 50036, + Modul: 3, + DpName: "KUE03_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "200 MOhm", + }, + { + IdLD: 50036, + Modul: 4, + DpName: "KUE04_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0 MOhm", + }, + { + IdLD: 50036, + Modul: 5, + DpName: "KUE05_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "11.5 MOhm", + }, + { + IdLD: 50036, + Modul: 8, + DpName: "KUE08_Messwert", + ModulName: "Köln", + ModulTyp: "KÜSS V2", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0 Events", + }, + { + IdLD: 50036, + Modul: 9, + DpName: "KUE09_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "11 MOhm", + }, + { + IdLD: 50036, + Modul: 10, + DpName: "KUE10_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "11 MOhm", + }, + { + IdLD: 50036, + Modul: 11, + DpName: "KUE11_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "11 MOhm", + }, + { + IdLD: 50036, + Modul: 12, + DpName: "KUE12_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "11 MOhm", + }, + { + IdLD: 50036, + Modul: 1, + DpName: "KUE01_Schleifenwert", + ModulName: "Friedrichsfehn", + ModulTyp: "Kü705-FO", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "2.32 kOhm", + }, + { + IdLD: 50036, + Modul: 2, + DpName: "KUE02_Schleifenwert", + ModulName: "Köln", + ModulTyp: "Kü605µC", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "2.15 kOhm", + }, + { + IdLD: 50036, + Modul: 6, + DpName: "KUE06_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "64.01 kOhm", + }, + { + IdLD: 50036, + Modul: 7, + DpName: "KUE07_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "64.01 kOhm", + }, + { + IdLD: 50036, + Modul: 8, + DpName: "KUE08_Schleifenwert", + ModulName: "Köln", + ModulTyp: "KÜSS V2", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0 kOhm", + }, + { + IdLD: 50071, + Modul: 1, + DpName: "KUE01_Messwert", + ModulName: "Test 1", + ModulTyp: "Kü705-FO", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.1 MOhm", + }, + { + IdLD: 50071, + Modul: 2, + DpName: "KUE02_Messwert", + ModulName: "Test 2", + ModulTyp: "Kü705-FO", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.1 MOhm", + }, + { + IdLD: 50071, + Modul: 3, + DpName: "KUE03_Messwert", + ModulName: "Test 3", + ModulTyp: "Kü705-FO", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.1 MOhm", + }, + { + IdLD: 50071, + Modul: 4, + DpName: "KUE04_Messwert", + ModulName: "Test 4", + ModulTyp: "Kü605µF", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.1 MOhm", + }, + { + IdLD: 50071, + Modul: 5, + DpName: "KUE05_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.1 MOhm", + }, + { + IdLD: 50071, + Modul: 6, + DpName: "KUE06_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.1 MOhm", + }, + { + IdLD: 50071, + Modul: 7, + DpName: "KUE07_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.1 Events", + }, + { + IdLD: 50071, + Modul: 8, + DpName: "KUE08_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "51 Events", + }, + { + IdLD: 50071, + Modul: 11, + DpName: "KUE11_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.59 kOhm", + }, + { + IdLD: 50071, + Modul: 12, + DpName: "KUE12_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.61 kOhm", + }, + { + IdLD: 50071, + Modul: 13, + DpName: "KUE13_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.58 kOhm", + }, + { + IdLD: 50071, + Modul: 14, + DpName: "KUE14_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.6 kOhm", + }, + { + IdLD: 50071, + Modul: 15, + DpName: "KUE15_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.6 kOhm", + }, + { + IdLD: 50071, + Modul: 16, + DpName: "KUE16_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0.57 kOhm", + }, + { + IdLD: 50082, + Modul: 6, + DpName: "KUE06_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0 MOhm", + }, + { + IdLD: 50082, + Modul: 7, + DpName: "KUE07_Messwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "10 MOhm", + }, + { + IdLD: 50082, + Modul: 6, + DpName: "KUE06_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0 kOhm", + }, + { + IdLD: 50082, + Modul: 7, + DpName: "KUE07_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "2.74 kOhm", + }, + { + IdLD: 50086, + Modul: 1, + DpName: "KUE01_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "201 kOhm", + }, + { + IdLD: 50086, + Modul: 2, + DpName: "KUE02_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "201 kOhm", + }, + { + IdLD: 50086, + Modul: 3, + DpName: "KUE03_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "201 kOhm", + }, + { + IdLD: 50086, + Modul: 4, + DpName: "KUE04_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "0 kOhm", + }, + { + IdLD: 50086, + Modul: 11, + DpName: "KUE11_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "4.01 kOhm", + }, + { + IdLD: 50086, + Modul: 12, + DpName: "KUE12_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "4.01 kOhm", + }, + { + IdLD: 50086, + Modul: 13, + DpName: "KUE13_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "4.01 kOhm", + }, + { + IdLD: 50086, + Modul: 14, + DpName: "KUE14_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "4.01 kOhm", + }, + { + IdLD: 50086, + Modul: 15, + DpName: "KUE15_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "4.01 kOhm", + }, + { + IdLD: 50086, + Modul: 16, + DpName: "KUE16_Schleifenwert", + ModulName: "?", + ModulTyp: "?", + Message: "?", + Level: -1, + PrioColor: "#ffffff", + PrioName: "?", + Value: "4.01 kOhm", + }, + ], + }; + // Sende die JSON-Daten als Antwort + res.status(200).json(data); +} diff --git a/pages/api/talas_v5_DB/locationDevice/getDeviceId.js b/pages/api/talas_v5_DB/locationDevice/getDeviceId.js index fa373c80c..00b36b4ed 100644 --- a/pages/api/talas_v5_DB/locationDevice/getDeviceId.js +++ b/pages/api/talas_v5_DB/locationDevice/getDeviceId.js @@ -1,40 +1,38 @@ // API in /api/talas_v5_DB/locationDevice/getDeviceId.js -import mysql from "mysql"; +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren -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, -}; +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden -const connection = mysql.createConnection(dbConfig); -connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - return; - } -}); - -export default 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 = ?"; - connection.query(query, [deviceName], (error, results) => { - if (error) { - console.error("Fehler beim Abrufen der Geräte-ID:", error); - return res - .status(500) - .json({ error: "Fehler beim Abrufen der Geräte-ID" }); - } + + let connection; + + try { + connection = await pool.getConnection(); // Hole eine Verbindung aus dem Pool + + // Ausführen der Abfrage + const [results] = await connection.query(query, [deviceName]); + if (results.length > 0) { - res.json({ idLD: results[0].idLD }); + 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" }); + } finally { + if (connection) connection.release(); // Gib die Verbindung in den Pool zurück + } } diff --git a/pages/api/talas_v5_DB/locationDevice/locationDeviceNameById.js b/pages/api/talas_v5_DB/locationDevice/locationDeviceNameById.js index aaf24778d..3649343e2 100644 --- a/pages/api/talas_v5_DB/locationDevice/locationDeviceNameById.js +++ b/pages/api/talas_v5_DB/locationDevice/locationDeviceNameById.js @@ -1,43 +1,36 @@ // API in /api/talas_v5_DB/locationDevice/locationDeviceNameById.js -import mysql from "mysql"; +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren -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, -}; +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden -const connection = mysql.createConnection(dbConfig); -connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - return; - } -}); - -export default function handler(req, res) { if (req.method !== "GET") { return res.status(405).json({ error: "Nur GET Methode erlaubt" }); } + const { idLD } = req.query; - const query = "SELECT name FROM location_device WHERE idLD = ?"; - connection.query(query, [idLD], (error, results) => { - if (error) { - console.error( - "Fehler beim Abrufen des Gerätenamens in locationDeviceNameById.js :", - error - ); - return res - .status(500) - .json({ error: "Fehler beim Abrufen des Gerätenamens" }); - } + if (!idLD) { + return res.status(400).json({ error: "idLD ist erforderlich" }); + } + + let connection; + + try { + connection = await pool.getConnection(); // Hole eine Verbindung aus dem Pool + + const query = "SELECT name FROM location_device WHERE idLD = ?"; + const [results] = await connection.query(query, [idLD]); + if (results.length > 0) { - res.json({ name: results[0].name }); + res.status(200).json({ name: results[0].name }); } else { - res.status(404).json({ error: "Gerät nicht gefunden" }); + 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" }); + } finally { + if (connection) connection.release(); // Gib die Verbindung in den Pool zurück + } } diff --git a/pages/api/talas_v5_DB/locationDevice/locationDevices.js b/pages/api/talas_v5_DB/locationDevice/locationDevices.js index bfaf57654..df6d4abea 100644 --- a/pages/api/talas_v5_DB/locationDevice/locationDevices.js +++ b/pages/api/talas_v5_DB/locationDevice/locationDevices.js @@ -1,35 +1,29 @@ // API in /api/talas_v5_DB/locationDevice/locationDevices.js -import mysql from "mysql"; +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren -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, -}; +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden -const connection = mysql.createConnection(dbConfig); -connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - return; - } -}); - -export default 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"; - connection.query(query, (error, results) => { - if (error) { - console.error("Fehler beim Abrufen der Geräteinformationen:", error); - return res - .status(500) - .json({ error: "Fehler beim Abrufen der Geräteinformationen" }); - } - res.json(results); - }); + //const query = "SELECT * FROM location_device WHERE iddevice = 160"; + const query = "SELECT * FROM location_device ORDER BY name"; + + let connection; + + try { + connection = await pool.getConnection(); // Hole eine Verbindung aus dem Pool + + // Ausführen der Abfrage + const [results] = await connection.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" }); + } finally { + if (connection) connection.release(); // Gib die Verbindung in den Pool zurück + } } diff --git a/pages/api/talas_v5_DB/poiTyp/readPoiTyp.js b/pages/api/talas_v5_DB/poiTyp/readPoiTyp.js index 062c442cd..34fb06aaf 100644 --- a/pages/api/talas_v5_DB/poiTyp/readPoiTyp.js +++ b/pages/api/talas_v5_DB/poiTyp/readPoiTyp.js @@ -1,33 +1,33 @@ // pages/api/talas_v5_DB/poiTyp/readPoiTyp.js -import mysql from "mysql"; +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren -const pool = mysql.createPool({ - //connectionLimit: 10, - 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, -}); +export default async function handler(req, res) { + const pool = getPool(); // Verwende den Singleton-Pool -export default function handler(req, res) { - if (req.method === "GET") { - const query = "SELECT * FROM poityp"; - - pool.query(query, (error, results) => { - if (error) { - console.error("Fehler beim Abfragen der Datenbank:", error); - return res.status(500).json({ error: "Ein Fehler ist aufgetreten" }); - } - - if (results.length === 0) { - return res.status(404).json({ message: "Keine Einträge gefunden" }); - } - - res.status(200).json(results); - }); - } else { + if (req.method !== "GET") { res.setHeader("Allow", ["GET"]); - res.status(405).end(`Method ${req.method} Not Allowed`); + return res.status(405).end(`Method ${req.method} Not Allowed`); + } + + const query = "SELECT * FROM poityp"; + + let connection; + + try { + connection = await pool.getConnection(); // Hole eine Verbindung aus dem Pool + + // Führe die Abfrage aus + const [results] = await connection.query(query); + + if (results.length === 0) { + return res.status(404).json({ message: "Keine Einträge gefunden" }); + } + + res.status(200).json(results); + } catch (error) { + console.error("Fehler beim Abfragen der Datenbank:", error); + res.status(500).json({ error: "Ein Fehler ist aufgetreten" }); + } finally { + if (connection) connection.release(); // Gib die Verbindung zurück in den Pool } } diff --git a/pages/api/talas_v5_DB/pois/addLocation.js b/pages/api/talas_v5_DB/pois/addLocation.js index 118704d7d..7c66f7760 100644 --- a/pages/api/talas_v5_DB/pois/addLocation.js +++ b/pages/api/talas_v5_DB/pois/addLocation.js @@ -1,36 +1,35 @@ // pages/api/talas_v5_DB/pois/addLocation.js -import mysql from "mysql"; +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren -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, -}; +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden -export default function handler(req, res) { if (req.method === "POST") { const { name, poiTypeId, latitude, longitude, idLD } = req.body; console.log("Received data:", req.body); // Überprüfen der empfangenen Daten - const connection = mysql.createConnection(dbConfig); - const query = - "INSERT INTO poi (description, idPoiTyp, position, idLD) VALUES (?, ?, ST_GeomFromText(?),?)"; + const query = "INSERT INTO poi (description, idPoiTyp, position, idLD) VALUES (?, ?, ST_GeomFromText(?),?)"; const point = `POINT(${longitude} ${latitude})`; - const values = [name, poiTypeId, point, idLD]; // Stellen Sie sicher, dass poiTypeId korrekt ist + const values = [name, poiTypeId, point, idLD]; + + let connection; + + try { + connection = await pool.getConnection(); // Hole eine Verbindung aus dem Pool + + // Verwende die Verbindung, um die Query auszuführen + const [results] = await connection.query(query, values); - connection.query(query, values, (error, results) => { - connection.end(); - if (error) { - console.error("Fehler beim Einfügen des Standorts:", error); - return res.status(500).json({ error: "Ein Fehler ist aufgetreten" }); - } res.status(200).json({ id: results.insertId, message: "Standort erfolgreich hinzugefügt", }); - }); + } catch (error) { + console.error("Fehler beim Einfügen des Standorts:", error); + res.status(500).json({ error: "Ein Fehler ist aufgetreten" }); + } finally { + if (connection) connection.release(); // Gib die Verbindung in den Pool zurück + } } else { res.setHeader("Allow", ["POST"]); res.status(405).end(`Method ${req.method} Not Allowed`); diff --git a/pages/api/talas_v5_DB/pois/deletePoi.js b/pages/api/talas_v5_DB/pois/deletePoi.js index ca1cc77a0..43ac96a9a 100644 --- a/pages/api/talas_v5_DB/pois/deletePoi.js +++ b/pages/api/talas_v5_DB/pois/deletePoi.js @@ -1,25 +1,9 @@ // pages/api/talas_v5_DB/pois/deletePoi.js -import mysql from "mysql"; +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren -// Datenbankkonfiguration -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, -}; +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden -const connection = mysql.createConnection(dbConfig); -connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - return; - } - console.log("Verbunden als ID", connection.threadId); -}); - -export default function handler(req, res) { if (req.method !== "DELETE") { return res.status(405).json({ error: "Nur DELETE Methode erlaubt" }); } @@ -31,15 +15,24 @@ export default function handler(req, res) { } const query = "DELETE FROM poi WHERE idPoi = ?"; - connection.query(query, [id], (error, results) => { - if (error) { - console.error("Fehler beim Löschen des POI:", error); - return res.status(500).json({ error: "Fehler beim Löschen des POI" }); - } + + let connection; + + try { + connection = await pool.getConnection(); // Hole eine Verbindung aus dem Pool + + // Ausführen der Abfrage mit dem Verbindungspool + const [results] = await connection.query(query, [id]); + if (results.affectedRows > 0) { - res.json({ message: "POI erfolgreich gelöscht" }); + res.status(200).json({ message: "POI erfolgreich gelöscht" }); } else { res.status(404).json({ error: "POI nicht gefunden" }); } - }); + } catch (error) { + console.error("Fehler beim Löschen des POI:", error); + res.status(500).json({ error: "Fehler beim Löschen des POI" }); + } finally { + if (connection) connection.release(); // Gib die Verbindung in den Pool zurück + } } diff --git a/pages/api/talas_v5_DB/pois/getPoiById.js b/pages/api/talas_v5_DB/pois/getPoiById.js index 4ebf5b62c..d06e1d86f 100644 --- a/pages/api/talas_v5_DB/pois/getPoiById.js +++ b/pages/api/talas_v5_DB/pois/getPoiById.js @@ -1,42 +1,39 @@ // pages/api/talas_v5_DB/pois/getPoiById.js -import mysql from "mysql"; +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren -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, -}; +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden -export default function handler(req, res) { - if (req.method === "GET") { - const { idPoi } = req.query; - const connection = mysql.createConnection(dbConfig); - - connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - return res - .status(500) - .json({ error: "Verbindungsfehler zur Datenbank" }); - } - - const query = "SELECT description FROM poi WHERE idPoi = ?"; - connection.query(query, [idPoi], (error, results) => { - connection.end(); - if (error) { - console.error("Fehler bei der Abfrage:", error); - return res.status(500).json({ error: "Fehler bei der Abfrage" }); - } - if (results.length === 0) { - return res.status(404).json({ error: "POI nicht gefunden" }); - } - res.status(200).json(results[0]); - }); - }); - } else { + if (req.method !== "GET") { res.setHeader("Allow", ["GET"]); - res.status(405).end(`Method ${req.method} Not Allowed`); + return res.status(405).end(`Method ${req.method} Not Allowed`); + } + + const { idPoi } = req.query; + + if (!idPoi) { + return res.status(400).json({ error: "idPoi ist erforderlich" }); + } + + const query = "SELECT description FROM poi WHERE idPoi = ?"; + + let connection; + + try { + connection = await pool.getConnection(); // Hole eine Verbindung aus dem Pool + + // Ausführen der Abfrage mit dem Verbindungspool + const [results] = await connection.query(query, [idPoi]); + + if (results.length === 0) { + return res.status(404).json({ error: "POI nicht gefunden" }); + } + + res.status(200).json(results[0]); + } catch (error) { + console.error("Fehler bei der Abfrage:", error); + res.status(500).json({ error: "Fehler bei der Abfrage" }); + } finally { + if (connection) connection.release(); // Gib die Verbindung in den Pool zurück } } diff --git a/pages/api/talas_v5_DB/pois/poi-icons.js b/pages/api/talas_v5_DB/pois/poi-icons.js index ee092c226..742260fb9 100644 --- a/pages/api/talas_v5_DB/pois/poi-icons.js +++ b/pages/api/talas_v5_DB/pois/poi-icons.js @@ -1,42 +1,32 @@ // pages/api/talas_v5_DB/pois/poi-icons.js -import mysql from "mysql"; +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren -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, -}; +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden -const connection = mysql.createConnection(dbConfig); - -connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - return; - } -}); - -export default function handler(req, res) { if (req.method !== "GET") { return res.status(405).json({ error: "Nur GET Methode erlaubt" }); } - const query = `SELECT p.idPoi, i.path - FROM poi p - JOIN poiTyp pt ON p.idPoiTyp = pt.idPoiTyp - JOIN poiicons i ON pt.icon = i.idpoiicons;`; + const query = ` + SELECT p.idPoi, i.path + FROM poi p + JOIN poiTyp pt ON p.idPoiTyp = pt.idPoiTyp + JOIN poiicons i ON pt.icon = i.idpoiicons; + `; - connection.query(query, (error, results) => { - try { - if (error) { - throw error; - } - res.json(results); - } catch (err) { - console.error("Fehler beim Abrufen der icons:", err); - res.status(500).json({ error: "Fehler beim Abrufen der icons" }); - } - }); + let connection; + + try { + connection = await pool.getConnection(); // Hole eine Verbindung aus dem Pool + + // Ausführen der Abfrage mit dem Verbindungspool + const [results] = await connection.query(query); + res.status(200).json(results); + } catch (error) { + console.error("Fehler beim Abrufen der Icons:", error); + res.status(500).json({ error: "Fehler beim Abrufen der Icons" }); + } finally { + if (connection) connection.release(); // Gib die Verbindung in den Pool zurück + } } diff --git a/pages/api/talas_v5_DB/pois/readLocations.js b/pages/api/talas_v5_DB/pois/readLocations.js index a5922ef50..464d0df5e 100644 --- a/pages/api/talas_v5_DB/pois/readLocations.js +++ b/pages/api/talas_v5_DB/pois/readLocations.js @@ -1,45 +1,27 @@ // pages/api/talas_v5_DB/pois/readLocations.js -import mysql from "mysql"; +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren -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); +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden - connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - res.status(500).json({ error: "Verbindungsfehler zur Datenbank" }); - return; - } + const query = ` + SELECT idPoi, description, idPoiTyp, idLD, ST_AsText(position) AS position + FROM poi + `; - console.log("Verbunden als ID", connection.threadId); + let connection; - connection.query( - "SELECT idPoi, description, idPoiTyp, idLD, ST_AsText(position) AS position FROM poi", - (error, results) => { - if (error) { - console.error("Fehler beim Abrufen der API", error); - res.status(500).json({ error: "Fehler bei der Abfrage" }); - return; - } + try { + connection = await pool.getConnection(); // Hole eine Verbindung aus dem Pool - // Wichtig: Senden Sie die Antwort zurück - res.status(200).json(results); - console.log( - "--------------- location.js ---------------", - "results in location.js : ", - results, - "---------------------- location.js end ---------------------------" - ); - connection.end(); - } - ); - }); + const [results] = await connection.query(query); + + // Senden der Antwort zurück + res.status(200).json(results); + } catch (error) { + console.error("Fehler beim Abrufen der API:", error); + res.status(500).json({ error: "Fehler bei der Abfrage" }); + } finally { + if (connection) connection.release(); // Gib die Verbindung in den Pool zurück + } } diff --git a/pages/api/talas_v5_DB/pois/updateLocation.js b/pages/api/talas_v5_DB/pois/updateLocation.js index 625be5a75..dafa9ce20 100644 --- a/pages/api/talas_v5_DB/pois/updateLocation.js +++ b/pages/api/talas_v5_DB/pois/updateLocation.js @@ -1,17 +1,9 @@ // pages/api/talas_v5_DB/pois/updateLocation.js -import mysql from "mysql"; -import util from "util"; - -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, - charset: "utf8mb4", -}; +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden + if (req.method !== "POST") { res.setHeader("Allow", ["POST"]); return res.status(405).end(`Method ${req.method} Not Allowed`); @@ -19,21 +11,28 @@ export default async function handler(req, res) { const { id, latitude, longitude } = req.body; - const connection = mysql.createConnection(dbConfig); - // Promisify the query method - const query = util.promisify(connection.query).bind(connection); + if (!id || latitude === undefined || longitude === undefined) { + return res.status(400).json({ error: "id, latitude, und longitude sind erforderlich" }); + } + + const query = "UPDATE poi SET position = POINT(?, ?) WHERE idPoi = ?"; + + let connection; try { - await query("UPDATE poi SET position = POINT(?, ?) WHERE idPoi = ?", [ - longitude, - latitude, - id, - ]); - res.status(200).json({ success: true }); + connection = await pool.getConnection(); // Hole eine Verbindung aus dem Pool + + const [result] = await connection.query(query, [longitude, latitude, id]); + + if (result.affectedRows > 0) { + res.status(200).json({ success: true }); + } else { + res.status(404).json({ error: "POI nicht gefunden" }); + } } catch (error) { - console.error(error); + console.error("Fehler beim Aktualisieren der Position:", error); res.status(500).json({ error: "Ein Fehler ist aufgetreten" }); } finally { - connection.end(); + if (connection) connection.release(); // Gib die Verbindung in den Pool zurück } } diff --git a/pages/api/talas_v5_DB/pois/updatePoi.js b/pages/api/talas_v5_DB/pois/updatePoi.js index ad9c52b60..1b46ec65e 100644 --- a/pages/api/talas_v5_DB/pois/updatePoi.js +++ b/pages/api/talas_v5_DB/pois/updatePoi.js @@ -1,53 +1,41 @@ // pages/api/talas_v5_DB/pois/updatePoi.js -import mysql from "mysql"; +import getPool from "../../../../utils/mysqlPool"; // Singleton-Pool importieren -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, -}; +export default async function handler(req, res) { + const pool = getPool(); // Verwende den Singleton-Pool -const connection = mysql.createConnection(dbConfig); -connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - return; - } - console.log("Verbunden als ID", connection.threadId); -}); - -export default function handler(req, res) { if (req.method !== "POST") { return res.status(405).json({ error: "Nur POST Methode erlaubt" }); } - const { idPoi, description, idPoiTyp, idLD } = req.body; // Stellen Sie sicher, dass die Felder korrekt benannt sind - - console.log("Empfangene Daten:", req.body); // Loggen der empfangenen Daten zur Überprüfung + const { idPoi, description, idPoiTyp, idLD } = req.body; if (!idPoi) { return res.status(400).json({ error: "POI ID ist erforderlich" }); } - const query = - "UPDATE talas_v5.poi SET description = ?, idPoiTyp = ?, idLD = ? WHERE idPoi = ?"; - connection.query( - query, - [description, idPoiTyp, idLD, idPoi], - (error, results) => { - if (error) { - console.error("Fehler beim Aktualisieren des POI:", error); - return res - .status(500) - .json({ error: "Fehler beim Aktualisieren des POI" }); - } - if (results.affectedRows > 0) { - res.json({ message: "POI erfolgreich aktualisiert" }); - } else { - res.status(404).json({ error: "POI nicht gefunden" }); - } + const query = ` + UPDATE talas_v5.poi + SET description = ?, idPoiTyp = ?, idLD = ? + WHERE idPoi = ? + `; + + let connection; + + try { + connection = await pool.getConnection(); // Hole eine Verbindung aus dem Pool + + const [results] = await connection.query(query, [description, idPoiTyp, idLD, idPoi]); + + if (results.affectedRows > 0) { + res.status(200).json({ message: "POI erfolgreich aktualisiert" }); + } else { + res.status(404).json({ error: "POI nicht gefunden" }); } - ); + } catch (error) { + console.error("Fehler beim Aktualisieren des POI:", error); + res.status(500).json({ error: "Fehler beim Aktualisieren des POI" }); + } finally { + if (connection) connection.release(); // Gib die Verbindung zurück in den Pool + } } diff --git a/pages/api/talas_v5_DB/priorityConfig.js b/pages/api/talas_v5_DB/priorityConfig.js index dc239f619..beefcd091 100644 --- a/pages/api/talas_v5_DB/priorityConfig.js +++ b/pages/api/talas_v5_DB/priorityConfig.js @@ -2,42 +2,27 @@ // in tals5 http://10.10.0.13/talas5/Management/PriorityConfig.aspx beinhaltet die Tabelle prio die Prioritäten der Meldungen (Level 1-4) oder (0-4) je nachdem DB-Design // das ist die API, die die Prioritäten zurückgibt -import mysql from "mysql"; +import getPool from "../../../utils/mysqlPool"; // Singleton-Pool importieren -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); +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden + let connection; - connection.connect((err) => { - if (err) { - console.error("Fehler beim Verbinden:", err.stack); - res.status(500).json({ error: "Verbindungsfehler zur Datenbank" }); - return; - } + try { + // Verbindung abrufen + connection = await pool.getConnection(); - console.log("Verbunden als ID", connection.threadId); - //Fehler weil, existiertdie Tabelle auf localhost:3000 nicht - connection.query( - "SELECT idprio, level, name, color FROM prio ", - (error, results) => { - if (error) { - console.error("Fehler beim Abrufen der API", error); - res.status(500).json({ error: "Fehler bei der Abfrage" }); - return; - } + // Ausführen der Datenbankabfrage + const query = "SELECT idprio, level, name, color FROM prio"; + const [results] = await connection.query(query); - // Wichtig: Senden Sie die Antwort zurück - res.status(200).json(results); - - connection.end(); - } - ); - }); + // Senden Sie die Antwort zurück + res.status(200).json(results); + } catch (error) { + console.error("Fehler beim Abrufen der API", error); + res.status(500).json({ error: "Fehler bei der Abfrage" }); + } finally { + // Verbindung freigeben + if (connection) connection.release(); + } } diff --git a/pages/api/talas_v5_DB/station/getAllStationsNames.js b/pages/api/talas_v5_DB/station/getAllStationsNames.js new file mode 100644 index 000000000..1bf158cb2 --- /dev/null +++ b/pages/api/talas_v5_DB/station/getAllStationsNames.js @@ -0,0 +1,39 @@ +// /pages/api/talas_v5_DB/station/getAllStationsNames.js +import getPool from "../../../../utils/mysqlPool"; // Importiere den Singleton-Pool + +export default async function handler(req, res) { + const pool = getPool(); // Verwende den Singleton-Pool + + if (req.method !== "GET") { + res.setHeader("Allow", ["GET"]); + return res.status(405).end(`Method ${req.method} Not Allowed`); + } + + let connection; + + try { + connection = await pool.getConnection(); // Hole eine Verbindung aus dem Pool + + // Abrufen aller idLD und ihrer Namen + const [results] = await connection.query("SELECT idLD, name FROM location_device"); + + if (results.length === 0) { + return res.status(404).json({ error: "No data found" }); + } + + // Struktur der Antwort anpassen + const namesMap = results.reduce((map, { idLD, name }) => { + if (!map[idLD]) { + map[idLD] = name; // Stelle sicher, dass hier keine Duplikate oder Überschreibungen entstehen + } + return map; + }, {}); + + res.status(200).json(namesMap); + } catch (err) { + console.error("Fehler beim Abrufen der Daten:", err); + res.status(500).json({ error: "Error retrieving data from the database" }); + } finally { + if (connection) connection.release(); // Gib die Verbindung zurück in den Pool + } +} diff --git a/pages/api/talas_v5_DB/station/getDevices.js b/pages/api/talas_v5_DB/station/getDevices.js new file mode 100644 index 000000000..4bc41e534 --- /dev/null +++ b/pages/api/talas_v5_DB/station/getDevices.js @@ -0,0 +1,32 @@ +// /pages/api/talas_v5_DB/device/getDevices.js +import getPool from "../../../../utils/mysqlPool"; // Import Singleton-Pool + +// API-Handler +export default async function handler(req, res) { + const pool = getPool(); // Singleton-Pool verwenden + + let connection; + try { + // Lade die Daten der aktiven Systeme aus localStorage, z.B. über einen Parameter oder Body + const { activeSystems } = req.body || []; // Array von aktiven system_typ IDs + + // SQL-Query: Verknüpfe die Tabellen location_device, devices und system_typ + const sql = `SELECT * FROM devices`; + + connection = await pool.getConnection(); + + // Führe die Abfrage mit den aktiven Systems durch + const [results] = await connection.query(sql); + + if (!results.length) { + return res.status(404).json({ error: "Keine passenden Geräte gefunden" }); + } + + res.status(200).json(results); + } catch (error) { + console.error("Fehler beim Abrufen der gefilterten Geräteinformationen:", error); + res.status(500).json({ error: "Fehler beim Abrufen der Geräteinformationen" }); + } finally { + if (connection) connection.release(); + } +} diff --git a/pages/index.js b/pages/index.js index 6376dacff..40b1c50e1 100644 --- a/pages/index.js +++ b/pages/index.js @@ -4,10 +4,9 @@ import { useRecoilState, useRecoilValue } from "recoil"; import { readPoiMarkersStore } from "../store/selectors/readPoiMarkersStore"; import { poiReadFromDbTriggerAtom } from "../store/atoms/poiReadFromDbTriggerAtom"; -const MapComponentWithNoSSR = dynamic( - () => import("../components/MapComponent"), - { ssr: false } -); +const MapComponentWithNoSSR = dynamic(() => import("../components/MapComponent"), { ssr: false }); +// TestScript ohne SSR +const TestScriptWithNoSSR = dynamic(() => import("../components/TestScript"), { ssr: false }); export default function Home() { const poiReadTrigger = useRecoilValue(poiReadFromDbTriggerAtom); @@ -49,7 +48,7 @@ export default function Home() { if (!response.ok) { throw new Error("Fehler beim Hinzufügen des Standorts"); } - console.log("Standort erfolgreich hinzugefügt"); + //console.log("Standort erfolgreich hinzugefügt"); loadData(); } catch (error) { console.error(error.message); @@ -57,13 +56,7 @@ export default function Home() { }; const handleLocationUpdate = (id, newLatitude, newLongitude) => { - setLocations((prevLocations) => - prevLocations.map((location) => - location.idPoi === id - ? { ...location, position: `POINT(${newLongitude} ${newLatitude})` } - : location - ) - ); + setLocations((prevLocations) => prevLocations.map((location) => (location.idPoi === id ? { ...location, position: `POINT(${newLongitude} ${newLatitude})` } : location))); }; useEffect(() => { @@ -72,11 +65,8 @@ export default function Home() { return (
- + +
); } diff --git a/public/Web.config.13 b/public/Web.config.13 new file mode 100644 index 000000000..6e9b0f62c --- /dev/null +++ b/public/Web.config.13 @@ -0,0 +1,152 @@ + + + + +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/Web.config.30 b/public/Web.config.30 new file mode 100644 index 000000000..543d70382 --- /dev/null +++ b/public/Web.config.30 @@ -0,0 +1,140 @@ + + + + +
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/img/icons/Stationsausfall-marker-icon-0.png b/public/img/icons/Stationsausfall-marker-icon-0.png new file mode 100644 index 000000000..451bb134d Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-0.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-1.png b/public/img/icons/Stationsausfall-marker-icon-1.png new file mode 100644 index 000000000..bb44e86d9 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-1.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-10.png b/public/img/icons/Stationsausfall-marker-icon-10.png new file mode 100644 index 000000000..7d749eb66 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-10.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-11.png b/public/img/icons/Stationsausfall-marker-icon-11.png new file mode 100644 index 000000000..ccfb2bea5 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-11.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-12.png b/public/img/icons/Stationsausfall-marker-icon-12.png new file mode 100644 index 000000000..9ad35abf0 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-12.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-13.png b/public/img/icons/Stationsausfall-marker-icon-13.png new file mode 100644 index 000000000..eb8a3a9c1 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-13.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-14.png b/public/img/icons/Stationsausfall-marker-icon-14.png new file mode 100644 index 000000000..c1b0d380a Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-14.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-15.png b/public/img/icons/Stationsausfall-marker-icon-15.png new file mode 100644 index 000000000..945b4719d Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-15.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-16.png b/public/img/icons/Stationsausfall-marker-icon-16.png new file mode 100644 index 000000000..94f76d0c5 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-16.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-17.png b/public/img/icons/Stationsausfall-marker-icon-17.png new file mode 100644 index 000000000..fee351ddc Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-17.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-18.png b/public/img/icons/Stationsausfall-marker-icon-18.png new file mode 100644 index 000000000..8623d5a87 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-18.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-19.png b/public/img/icons/Stationsausfall-marker-icon-19.png new file mode 100644 index 000000000..4f54f28a5 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-19.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-2.png b/public/img/icons/Stationsausfall-marker-icon-2.png new file mode 100644 index 000000000..78822a5a9 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-2.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-20.png b/public/img/icons/Stationsausfall-marker-icon-20.png new file mode 100644 index 000000000..fa12ff6ae Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-20.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-21.png b/public/img/icons/Stationsausfall-marker-icon-21.png new file mode 100644 index 000000000..bfd0ed7b0 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-21.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-22.png b/public/img/icons/Stationsausfall-marker-icon-22.png new file mode 100644 index 000000000..ae9f8075c Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-22.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-23.png b/public/img/icons/Stationsausfall-marker-icon-23.png new file mode 100644 index 000000000..4b32975e7 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-23.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-24.png b/public/img/icons/Stationsausfall-marker-icon-24.png new file mode 100644 index 000000000..ad3807d23 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-24.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-25.png b/public/img/icons/Stationsausfall-marker-icon-25.png new file mode 100644 index 000000000..edf581437 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-25.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-26.png b/public/img/icons/Stationsausfall-marker-icon-26.png new file mode 100644 index 000000000..0400d6811 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-26.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-27.png b/public/img/icons/Stationsausfall-marker-icon-27.png new file mode 100644 index 000000000..ba1ed3ed0 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-27.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-28.png b/public/img/icons/Stationsausfall-marker-icon-28.png new file mode 100644 index 000000000..56a5ece18 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-28.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-29.png b/public/img/icons/Stationsausfall-marker-icon-29.png new file mode 100644 index 000000000..8c9d188da Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-29.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-3.png b/public/img/icons/Stationsausfall-marker-icon-3.png new file mode 100644 index 000000000..682e0596c Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-3.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-30.png b/public/img/icons/Stationsausfall-marker-icon-30.png new file mode 100644 index 000000000..ac05a2fa6 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-30.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-31.png b/public/img/icons/Stationsausfall-marker-icon-31.png new file mode 100644 index 000000000..5e90fb5a3 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-31.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-32.png b/public/img/icons/Stationsausfall-marker-icon-32.png new file mode 100644 index 000000000..c8680ebc2 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-32.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-4.png b/public/img/icons/Stationsausfall-marker-icon-4.png new file mode 100644 index 000000000..5e90fb5a3 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-4.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-5.png b/public/img/icons/Stationsausfall-marker-icon-5.png new file mode 100644 index 000000000..858c125b8 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-5.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-6.png b/public/img/icons/Stationsausfall-marker-icon-6.png new file mode 100644 index 000000000..aca5b1b00 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-6.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-7.png b/public/img/icons/Stationsausfall-marker-icon-7.png new file mode 100644 index 000000000..d924b8cca Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-7.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-8.png b/public/img/icons/Stationsausfall-marker-icon-8.png new file mode 100644 index 000000000..d78369d22 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-8.png differ diff --git a/public/img/icons/Stationsausfall-marker-icon-9.png b/public/img/icons/Stationsausfall-marker-icon-9.png new file mode 100644 index 000000000..57fbb0fa4 Binary files /dev/null and b/public/img/icons/Stationsausfall-marker-icon-9.png differ diff --git a/public/img/icons/critical-marker-icon-31.png b/public/img/icons/critical-marker-icon-31.png new file mode 100644 index 000000000..43fae1790 Binary files /dev/null and b/public/img/icons/critical-marker-icon-31.png differ diff --git a/public/img/icons/critical-marker-icon-32.png b/public/img/icons/critical-marker-icon-32.png new file mode 100644 index 000000000..cf3663cf7 Binary files /dev/null and b/public/img/icons/critical-marker-icon-32.png differ diff --git a/public/img/icons/gisLines/add-support-point.svg b/public/img/icons/gisLines/add-support-point.svg new file mode 100644 index 000000000..7aaf86289 --- /dev/null +++ b/public/img/icons/gisLines/add-support-point.svg @@ -0,0 +1,4 @@ + + + + + diff --git a/public/img/icons/gisLines/remove-support-point.svg b/public/img/icons/gisLines/remove-support-point.svg new file mode 100644 index 000000000..aa5ab6b46 --- /dev/null +++ b/public/img/icons/gisLines/remove-support-point.svg @@ -0,0 +1,4 @@ + + + - + diff --git a/public/img/icons/major-marker-icon-31.png b/public/img/icons/major-marker-icon-31.png new file mode 100644 index 000000000..9abdcc487 Binary files /dev/null and b/public/img/icons/major-marker-icon-31.png differ diff --git a/public/img/icons/major-marker-icon-32.png b/public/img/icons/major-marker-icon-32.png new file mode 100644 index 000000000..a28a3a103 Binary files /dev/null and b/public/img/icons/major-marker-icon-32.png differ diff --git a/public/img/icons/marker-icon-31.png b/public/img/icons/marker-icon-31.png new file mode 100644 index 000000000..ec96a02cf Binary files /dev/null and b/public/img/icons/marker-icon-31.png differ diff --git a/public/img/icons/marker-icon-32.png b/public/img/icons/marker-icon-32.png new file mode 100644 index 000000000..58c3e68ff Binary files /dev/null and b/public/img/icons/marker-icon-32.png differ diff --git a/public/img/icons/minor-marker-icon-31.png b/public/img/icons/minor-marker-icon-31.png new file mode 100644 index 000000000..d6601650d Binary files /dev/null and b/public/img/icons/minor-marker-icon-31.png differ diff --git a/public/img/icons/minor-marker-icon-32.png b/public/img/icons/minor-marker-icon-32.png new file mode 100644 index 000000000..0e9453530 Binary files /dev/null and b/public/img/icons/minor-marker-icon-32.png differ diff --git a/public/img/icons/system-marker-icon-31.png b/public/img/icons/system-marker-icon-31.png new file mode 100644 index 000000000..95ebd5fe2 Binary files /dev/null and b/public/img/icons/system-marker-icon-31.png differ diff --git a/public/img/icons/system-marker-icon-32.png b/public/img/icons/system-marker-icon-32.png new file mode 100644 index 000000000..fb79e7ac1 Binary files /dev/null and b/public/img/icons/system-marker-icon-32.png differ diff --git a/redux/actions.js b/redux/actions.js new file mode 100644 index 000000000..d147d7d35 --- /dev/null +++ b/redux/actions.js @@ -0,0 +1,9 @@ +// /redux/actions.js +export const connectWebSocket = (url) => ({ + type: "WS_CONNECT", + payload: { url }, +}); + +export const disconnectWebSocket = () => ({ + type: "WS_DISCONNECT", +}); diff --git a/redux/reducer.js b/redux/reducer.js new file mode 100644 index 000000000..008b8d138 --- /dev/null +++ b/redux/reducer.js @@ -0,0 +1,18 @@ +// /redux/reducer.js +const initialState = { + messages: [], +}; + +const websocketReducer = (state = initialState, action) => { + switch (action.type) { + case "WS_MESSAGE_RECEIVED": + return { + ...state, + messages: [...state.messages, action.payload], + }; + default: + return state; + } +}; + +export default websocketReducer; diff --git a/redux/store.js b/redux/store.js new file mode 100644 index 000000000..a12ad9d77 --- /dev/null +++ b/redux/store.js @@ -0,0 +1,12 @@ +// /redux/store.js +import { configureStore } from "@reduxjs/toolkit"; +import websocketMiddleware from "./websocketMiddleware"; +import websocketReducer from "./reducer"; + +// Erstelle den Store mit configureStore +const store = configureStore({ + reducer: websocketReducer, + middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(websocketMiddleware), +}); + +export default store; diff --git a/redux/websocketMiddleware.js b/redux/websocketMiddleware.js new file mode 100644 index 000000000..75c39637d --- /dev/null +++ b/redux/websocketMiddleware.js @@ -0,0 +1,29 @@ +// /redux/websocketMiddleware.js +const websocketMiddleware = () => { + let socket; + + return ({ dispatch }) => + (next) => + (action) => { + if (action.type === "WS_CONNECT") { + socket = new WebSocket(action.payload.url); + + socket.onmessage = (event) => { + const data = JSON.parse(event.data); + dispatch({ type: "WS_MESSAGE_RECEIVED", payload: data }); + }; + + socket.onclose = () => { + dispatch({ type: "WS_DISCONNECTED" }); + }; + } + + if (action.type === "WS_DISCONNECT" && socket) { + socket.close(); + } + + return next(action); + }; +}; + +export default websocketMiddleware; diff --git a/services/apiService.js b/services/apiService.js index 9a86cbfc4..930a9565f 100644 --- a/services/apiService.js +++ b/services/apiService.js @@ -1,27 +1,63 @@ // services/apiService.js import * as config from "../config/config"; -import { setPriorityConfig } from "../utils/utils"; import * as urls from "../config/urls"; -export const fetchGisStatusStations = async (idMap, idUser) => { +let timeoutId; + +const fetchWithTimeout = async (url, options, timeout = 5000) => { + const controller = new AbortController(); + const id = setTimeout(() => controller.abort(), timeout); + try { - const response = await fetch( - `/api/talas5/webserviceMap/GisStationsStatusDistrict?idMap=${idMap}&idUser=${idUser}` - ); - if (!response.ok) { - throw new Error(`Error: ${response.statusText}`); - } - const data = await response.json(); - console.log("GisStatusStations:", data); - return data; + const response = await fetch(url, { + ...options, + signal: controller.signal, + }); + clearTimeout(id); + return response; } catch (error) { - console.error("Fehler beim Abrufen der Daten:", error); - throw error; // Fehler weiter werfen, um ihn in der Komponente behandeln zu können + clearTimeout(id); // Im Falle eines Fehlers den Timeout abbrechen + throw error; } }; +export const fetchGisStatusStations = async (idMap, idUser) => { + // Verhindere wiederholte schnelle API-Aufrufe durch Debouncing + if (timeoutId) { + clearTimeout(timeoutId); + } + + timeoutId = setTimeout(async () => { + const SERVER_URL = process.env.NEXT_PUBLIC_SERVER_URL; + + try { + // Verwende das Timeout für die API-Anfrage + const response = await fetchWithTimeout( + `${SERVER_URL}/talas5/ClientData/WebServiceMap.asmx/GisStationsStatusDistrict?idMap=${idMap}&idUser=${idUser}`, + { + method: "GET", + headers: { + Connection: "close", // Dieser Header stellt sicher, dass die Verbindung nach dem Abruf geschlossen wird + }, + }, + 5000 // Timeout auf 5 Sekunden gesetzt + ); + + if (!response.ok) { + throw new Error(`Error: ${response.statusText}`); + } + + const data = await response.json(); + return data; + } catch (error) { + console.error("Fehler beim Abrufen der Daten:", error); + throw error; + } + }, 500); // Debounce-Zeit auf 500ms gesetzt +}; + // ---------------------------------------------- -export const fetchPriorityConfig = async () => { +/* export const fetchPriorityConfig = async () => { try { const response = await fetch("/api/talas_v5_DB/priorityConfig"); const data = await response.json(); @@ -30,14 +66,12 @@ export const fetchPriorityConfig = async () => { } catch (error) { console.error("Fehler beim Laden der Prioritätskonfiguration:", error); } -}; +}; */ // ---------------------------------------------- export const fetchPoiData = async (idPoi) => { try { - const response = await fetch( - `/api/talas_v5_DB/pois/getPoiById?idPoi=${idPoi}` - ); + const response = await fetch(`/api/talas_v5_DB/pois/getPoiById?idPoi=${idPoi}`); if (!response.ok) { throw new Error("Fehler beim Abrufen der POI-Daten"); } @@ -46,6 +80,7 @@ export const fetchPoiData = async (idPoi) => { idPoi, name: data.name, description: data.description, + idLD: data.idLD, }; } catch (error) { console.error("Fehler beim Abrufen der POI-Daten", error); @@ -54,11 +89,7 @@ export const fetchPoiData = async (idPoi) => { }; // ---------------------------------------------- // Funktion zum Aktualisieren der Position 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" }, @@ -88,20 +119,16 @@ export const checkInternet = () => { // ---------------------------------------------- export const fetchDeviceNameById = async (idLD) => { try { - const response = await fetch( - `/api/talas_v5_DB/locationDevice/locationDeviceNameById?idLD=${idLD}` - ); + const response = await fetch(`/api/talas_v5_DB/locationDevice/locationDeviceNameById?idLD=${idLD}`); const data = await response.json(); if (response.ok) { return data.name; } else { - throw new Error(data.error || "Gerät nicht gefunden"); + //throw new Error(data.error || "Gerät nicht gefunden"); + throw new Error("Gerät nicht gefunden in apiService.js"); } } catch (error) { - /* console.error( - "Fehler beim Abrufen des Gerätenamens in MapComponent.js:", - error - ); */ + console.error("Fehler beim Abrufen des Gerätenamens in apiService.js:", error); return "Unbekannt"; } }; @@ -109,17 +136,25 @@ export const fetchDeviceNameById = async (idLD) => { // ---------------------------------------------- // services/apiService.js export const fetchUserRights = async () => { + // Zähler für API-Aufrufe in localStorage speichern + let userRightsRequestCount = localStorage.getItem("userRightsRequestCount") || 0; + userRightsRequestCount++; + localStorage.setItem("userRightsRequestCount", userRightsRequestCount); + console.log(`fetchUserRights wurde ${userRightsRequestCount} Mal aufgerufen.`); + try { - const response = await fetch( - `${urls.SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic?idMap=${config.idMap}&idUser=${config.idUser}` - ); + const response = await fetch(`${process.env.NEXT_PUBLIC_SERVER_URL}/talas5/ClientData/WebserviceMap.asmx/GisSystemStatic?idMap=${config.idMap}&idUser=${config.idUser}`, { + method: "GET", + headers: { + Connection: "close", + }, + }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); - // console.log("Benutzerrechte in fetchRights:", data); // Überprüfen der Struktur der Antwort if (!data || !data.Rights || !Array.isArray(data.Rights)) { @@ -127,13 +162,8 @@ export const fetchUserRights = async () => { } const rightsArray = data.Rights; // Nehmen an, dass 'Rights' das Array von Rechten ist - //console.log("rightsArray in apiService:", rightsArray); - - // Speichert die IDs der Rechte in einem Array const userRightsIds = rightsArray.map((right) => right.IdRight); - // Wenn alles gut geht, logge die erfolgreichen Abschluss - // console.log("Benutzerrechte erfolgreich abgerufen:", userRightsIds); return userRightsIds; } catch (error) { console.error("Fehler beim Abrufen der Benutzerrechte", error); diff --git a/services/fetchData.js b/services/fetchData.js new file mode 100644 index 000000000..2b036abb5 --- /dev/null +++ b/services/fetchData.js @@ -0,0 +1,62 @@ +// services/fetchData.js +export const fetchGisStationsStaticDistrict = async (url, setGisStationsStaticDistrict) => { + try { + const response = await fetch(url); + const jsonResponse = await response.json(); + if (jsonResponse && jsonResponse.Points) { + setGisStationsStaticDistrict(jsonResponse.Points); + } else { + console.error('Erwartete Daten im "Points"-Array nicht gefunden', jsonResponse); + setGisStationsStaticDistrict([]); + } + } catch (error) { + console.error("Fehler beim Laden der Daten: ", error); + setGisStationsStaticDistrict([]); + } +}; +export const fetchGisStationsStatusDistrict = async (url, setGisStationsStatusDistrict) => { + try { + const response = await fetch(url); + const jsonResponse = await response.json(); + if (jsonResponse && jsonResponse.Statis) { + setGisStationsStatusDistrict(jsonResponse.Statis); + } else { + console.error('Erwartete Daten im "Statis"-Array nicht gefunden', jsonResponse); + setGisStationsStatusDistrict([]); + } + } catch (error) { + console.error("Fehler beim Laden der Daten: ", error); + setGisStationsStatusDistrict([]); + } +}; +export const fetchGisStationsMeasurements = async (url, setGisStationsMeasurements) => { + try { + const response = await fetch(url); + const jsonResponse = await response.json(); + if (jsonResponse && jsonResponse.Statis) { + setGisStationsMeasurements(jsonResponse.Statis); + } else { + console.error('Erwartete Daten im "Statis"-Array nicht gefunden', jsonResponse); + setGisStationsMeasurements([]); + } + } catch (error) { + console.error("Fehler beim Laden der Daten: ", error); + setGisStationsMeasurements([]); + } +}; +export const fetchGisSystemStatic = async (url, setGisSystemStatic, setGisSystemStaticLoaded) => { + try { + const response = await fetch(url); + const jsonResponse = await response.json(); + if (jsonResponse && jsonResponse.Systems) { + setGisSystemStatic(jsonResponse.Systems); + setGisSystemStaticLoaded(true); + } else { + console.error('Erwartete Daten im "Systems"-Array nicht gefunden', jsonResponse); + setGisSystemStatic([]); + } + } catch (error) { + console.error("Fehler beim Laden der Daten: ", error); + setGisSystemStatic([]); + } +}; diff --git a/store/atoms/gisSystemState.js b/store/atoms/gisSystemState.js index 784b41776..e31c490d8 100644 --- a/store/atoms/gisSystemState.js +++ b/store/atoms/gisSystemState.js @@ -1,4 +1,4 @@ -// Pfad: store/atoms/gisStationState.js +// Pfad: store/atoms/gisSystemtate.js import { atom } from "recoil"; export const gisSystemStaticState = atom({ diff --git a/store/atoms/mapAtom.js b/store/atoms/mapAtom.js new file mode 100644 index 000000000..aa6514fe2 --- /dev/null +++ b/store/atoms/mapAtom.js @@ -0,0 +1,7 @@ +// store/atoms/mapAtom.js +import { atom } from "recoil"; + +export const mapAtom = atom({ + key: "mapAtom", // Ein eindeutiger Schlüssel für Recoil + default: null, // Standardwert ist null, da die Karte noch nicht erstellt wurde +}); diff --git a/store/atoms/poiDeviceNameState.js b/store/atoms/poiDeviceNameState.js new file mode 100644 index 000000000..b368995c9 --- /dev/null +++ b/store/atoms/poiDeviceNameState.js @@ -0,0 +1,7 @@ +// store/atoms/poiDeviceNameState.js +import { atom } from "recoil"; + +export const poiDeviceNameState = atom({ + key: "poiDeviceNameState", + default: "", +}); diff --git a/store/atoms/poiLayerVisibleState.js b/store/atoms/poiLayerVisibleState.js new file mode 100644 index 000000000..5304cf0d7 --- /dev/null +++ b/store/atoms/poiLayerVisibleState.js @@ -0,0 +1,8 @@ +// /store/atoms/poiLayerVisibleState.js +// Recoil atom for the visibility of the POI layer +import { atom } from "recoil"; + +export const poiLayerVisibleState = atom({ + key: "poiLayerVisibleState", + default: true, +}); diff --git a/store/atoms/polylineEventsDisabledState.js b/store/atoms/polylineEventsDisabledState.js new file mode 100644 index 000000000..1cb4e1f70 --- /dev/null +++ b/store/atoms/polylineEventsDisabledState.js @@ -0,0 +1,7 @@ +// /store/atoms/polylineEventsDisabledState.js +import { atom } from "recoil"; + +export const polylineEventsDisabledState = atom({ + key: "polylineEventsDisabledState", + default: false, +}); diff --git a/store/atoms/polylineLayerVisibleState.js b/store/atoms/polylineLayerVisibleState.js new file mode 100644 index 000000000..6988d96af --- /dev/null +++ b/store/atoms/polylineLayerVisibleState.js @@ -0,0 +1,7 @@ +// /sttore/atoms/polylineLayerVisibleState.js +import { atom } from "recoil"; + +export const polylineLayerVisibleState = atom({ + key: "polylineLayerVisibleState", + default: true, // Standardmäßig auf sichtbar setzen +}); diff --git a/styles/global.css b/styles/global.css index bd47f3630..99f9fd85e 100644 --- a/styles/global.css +++ b/styles/global.css @@ -16,3 +16,16 @@ padding: 10px !important; color: white !important; } +/* GMA Farben */ +.text-blue-700 { + color: #1d4ed8; +} +.text-red-700 { + color: #dc2626; +} +.text-yellow-500 { + color: #f59e0b; +} +.text-green-700 { + color: #10b981; +} diff --git a/tailwind.config.js b/tailwind.config.js index 3e3153dc0..f0ab949f8 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,9 +1,6 @@ /** @type {import('tailwindcss').Config} */ module.exports = { - content: [ - "./pages/**/*.{js,ts,jsx,tsx}", - "./components/**/*.{js,ts,jsx,tsx}", - ], + content: ["./pages/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}", "./hooks/**/*.{js,ts,jsx,tsx}"], theme: { extend: { zIndex: { diff --git a/tree_included.ps1 b/tree_included.ps1 new file mode 100644 index 000000000..269ab55eb --- /dev/null +++ b/tree_included.ps1 @@ -0,0 +1,42 @@ +param ( + [string]$Path, + [string[]]$Include +) + +function Get-IncludedTree { + param ( + [string]$Directory, + [string[]]$Include, + [int]$Indent = 0 + ) + + # Check if the current directory should be included + $includeCurrent = $false + foreach ($include in $Include) { + if ($Directory -like "*\$include*") { + $includeCurrent = $true + break + } + } + + if ($includeCurrent) { + # Output the current directory with indentation + Write-Host (" " * $Indent) + "+---" + (Split-Path -Leaf $Directory) + + # Process subdirectories and files + Get-ChildItem -Path $Directory | ForEach-Object { + if ($_.PSIsContainer) { + Get-IncludedTree -Directory $_.FullName -Include $Include -Indent ($Indent + 4) + } else { + Write-Host (" " * ($Indent + 4)) + "+---" + $_.Name + } + } + } +} + +# Start processing from the given path +Write-Host "Starting at path: $Path" +Get-ChildItem -Path $Path -Directory | ForEach-Object { + Get-IncludedTree -Directory $_.FullName -Include $Include +} +Write-Host "Processing completed." diff --git a/utils/addContextMenuToMarker.js b/utils/addContextMenuToMarker.js new file mode 100644 index 000000000..160b905ba --- /dev/null +++ b/utils/addContextMenuToMarker.js @@ -0,0 +1,11 @@ +// /utils/addContextMenuToMarker.js + +export function addContextMenuToMarker(marker) { + marker.unbindContextMenu(); // Entferne das Kontextmenü, um Duplikate zu vermeiden + + marker.bindContextMenu({ + contextmenu: true, + contextmenuWidth: 140, + contextmenuItems: [], + }); +} diff --git a/utils/createAndSetDevices.js b/utils/createAndSetDevices.js new file mode 100644 index 000000000..6674f3310 --- /dev/null +++ b/utils/createAndSetDevices.js @@ -0,0 +1,123 @@ +// /utils/createAndSetDevices.js +import circleIcon from "../components/gisPolylines/icons/CircleIcon"; +import { saveLineData, redrawPolyline } from "./mapUtils"; +import L from "leaflet"; +import "leaflet.smooth_marker_bouncing"; +import { toast } from "react-toastify"; +import * as config from "../config/config.js"; +import { disablePolylineEvents, enablePolylineEvents } from "./setupPolylines"; // Importiere die Funktion zum Deaktivieren der Polyline-Ereignisse +import { setPolylineEventsDisabled } from "../store/atoms/polylineEventsDisabledState"; // Importiere den Recoil-Atom-Zustand + +// Funktion zum Bestimmen der Priorität basierend auf dem Icon-Pfad +const determinePriority = (iconPath, priorityConfig) => { + for (let priority of priorityConfig) { + if (iconPath.includes(priority.name.toLowerCase())) { + return priority.level; + } + } + return 5; // Standardpriorität (niedrigste) +}; + +// Funktion zum Erstellen und Setzen von Markern +export const createAndSetDevices = async (systemId, setMarkersFunction, GisSystemStatic, priorityConfig) => { + try { + // Zähler für externe API-Aufrufe in localStorage speichern + let requestCount = localStorage.getItem("gisStationsStaticRequestCount-createDevice") || 0; + requestCount++; + localStorage.setItem("gisStationsStaticRequestCount-createDevice", requestCount); + //console.log(`config.mapGisStationsStaticDistrictUrl in createAndSetDevice wurde ${requestCount} Mal aufgerufen.`); + + const response1 = await fetch(config.mapGisStationsStaticDistrictUrl); + const jsonResponse = await response1.json(); + const response2 = await fetch(config.mapGisStationsStatusDistrictUrl); + const statusResponse = await response2.json(); + const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL; + + const getIdSystemAndAllowValueMap = new Map(GisSystemStatic.map((system) => [system.IdSystem, system.Allow])); + + if (jsonResponse.Points && statusResponse.Statis) { + console.log("jsonResponse.Points: ", jsonResponse.Points); + console.log("statusResponse.Statis: ", statusResponse.Statis); + const statisMap = new Map(statusResponse.Statis.map((s) => [s.IdLD, s])); + let markersData = jsonResponse.Points.filter((station) => station.System === systemId && getIdSystemAndAllowValueMap.get(station.System) === 1).map((station) => { + const statis = statisMap.get(station.IdLD); + const iconPath = statis ? `img/icons/${statis.Na}-marker-icon-${station.Icon}.png` : `img/icons/marker-icon-${station.Icon}.png`; + + const priority = determinePriority(iconPath, priorityConfig); + const zIndexOffset = 100 * (5 - priority); // Adjusted for simplicity and positive values + + const marker = L.marker([station.X, station.Y], { + icon: L.icon({ + iconUrl: iconPath, + iconSize: [25, 41], + iconAnchor: [12, 41], + popupAnchor: [1, -34], + }), + areaName: station.Area_Name, // Stelle sicher, dass dieser Bereich gesetzt wird + link: station.Link, + zIndexOffset: zIndexOffset, + }); + + // Deaktiviere Polyline-Ereignisse beim Überfahren des Markers + marker.on("mouseover", function () { + this.openPopup(); + }); + + // Verwende das `contextmenu`-Ereignis für den Rechtsklick + + marker.on("contextmenu", function (event) { + if (event && event.preventDefault) { + event.preventDefault(); // Verhindert das Standard-Kontextmenü + } + //setPolylineEventsDisabled(true); + //disablePolylineEvents(window.polylines); + this.openPopup(); + }); + + document.addEventListener("mouseout", function (event) { + if (event.relatedTarget === null || event.relatedTarget.nodeName === "BODY") { + //setPolylineEventsDisabled(false); + enablePolylineEvents(window.polylines, window.lineColors); + } + }); + marker.on("mouseout", function () { + this.closePopup(); + }); + + // Überprüfe, ob die bounce-Funktion verfügbar ist und verwende sie + if (typeof marker.bounce === "function" && statis) { + marker.on("add", () => marker.bounce(3)); + } + + const statusInfo = statusResponse.Statis.filter((status) => status.IdLD === station.IdLD) + .reverse() + .map( + (status) => ` +
+
+ ${status.Me} (${status.Na}) +
+ ` + ) + .join(""); + + marker.bindPopup(` +
+ ${station.LD_Name} + ${station.Device}
+ ${station.Area_Short} (${station.Area_Name})
+ ${station.Location_Short} (${station.Location_Name}) +
${statusInfo}
+
+ `); + + + return marker; + }); + + setMarkersFunction(markersData); + } + } catch (error) { + console.error("Error fetching data: ", error); + } +}; diff --git a/utils/geometryUtils.js b/utils/geometryUtils.js index 1240d216f..893e0bec7 100644 --- a/utils/geometryUtils.js +++ b/utils/geometryUtils.js @@ -1,17 +1,32 @@ +// utils/geometryUtils.js + +/** + * Parses a point string in the format "POINT (longitude latitude)" and returns an object with latitude and longitude as numbers. + * @param {string} position - The position string in the format "POINT (longitude latitude)". + * @returns {{latitude: number, longitude: number}} An object containing the latitude and longitude as numbers. + */ export const parsePoint = (position) => { const [longitude, latitude] = position.slice(6, -1).split(" "); return { latitude: parseFloat(latitude), longitude: parseFloat(longitude) }; }; +/** + * Finds the closest points on a polyline to a new point. + * @param {Array} coordinates - The coordinates of the polyline. + * @param {Object} newPoint - The new point (with latitude and longitude). + * @param {Object} map - The map object. + * @returns {Array} The closest pair of points on the polyline. + */ export const findClosestPoints = (coordinates, newPoint, map) => { + if (!map) { + console.error("Map is not defined. Cannot find closest points."); + return []; + } + let minDist = Infinity; let closestPair = []; for (let i = 1; i < coordinates.length; i++) { - const dist = L.LineUtil.pointToSegmentDistance( - map.latLngToLayerPoint(newPoint), - map.latLngToLayerPoint(coordinates[i - 1]), - map.latLngToLayerPoint(coordinates[i]) - ); + const dist = L.LineUtil.pointToSegmentDistance(map.latLngToLayerPoint(newPoint), map.latLngToLayerPoint(coordinates[i - 1]), map.latLngToLayerPoint(coordinates[i])); if (dist < minDist) { minDist = dist; closestPair = [coordinates[i - 1], coordinates[i], i]; @@ -19,3 +34,37 @@ export const findClosestPoints = (coordinates, newPoint, map) => { } return closestPair; }; +// Hilfsfunktion zur Berechnung der Entfernung zwischen zwei Punkten (LatLng) +export function getDistance(latlng1, latlng2) { + const R = 6371e3; // Erdradius in Metern + const lat1 = latlng1.lat * (Math.PI / 180); + const lat2 = latlng2.lat * (Math.PI / 180); + const deltaLat = (latlng2.lat - latlng1.lat) * (Math.PI / 180); + const deltaLng = (latlng2.lng - latlng1.lng) * (Math.PI / 180); + + const a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(deltaLng / 2) * Math.sin(deltaLng / 2); + const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + + return R * c; // Entfernung in Metern +} + +// Funktion zum Finden der nächsten Linie basierend auf der Mausposition +export function findNearestPolyline(map, mouseLatLng) { + let nearestPolyline = null; + let minDistance = Infinity; + + map.eachLayer(function (layer) { + if (layer instanceof L.Polyline) { + const latlngs = layer.getLatLngs(); + latlngs.forEach((latlng) => { + const distance = getDistance(mouseLatLng, latlng); + if (distance < minDistance) { + minDistance = distance; + nearestPolyline = layer; + } + }); + } + }); + + return nearestPolyline; +} diff --git a/utils/handlePoiSelect.js b/utils/handlePoiSelect.js new file mode 100644 index 000000000..46252b236 --- /dev/null +++ b/utils/handlePoiSelect.js @@ -0,0 +1,37 @@ +// utils/handlePoiSelect.js +const handlePoiSelect = async (poiData, setSelectedPoi, setLocationDeviceData, setDeviceName, poiLayerRef, poiTypMap) => { + setSelectedPoi(poiData); // Setzt das ausgewählte POI + + try { + const response = await fetch("/api/talas_v5_DB/locationDevice/locationDevices"); + const data = await response.json(); + setLocationDeviceData(data); + + const currentDevice = data.find((device) => device.idLD === poiData.deviceId); + if (currentDevice) { + setDeviceName(currentDevice.name); + + // Hier speichern wir den POI-Typ im localStorage + const poiTypeName = poiTypMap.get(poiData.idPoiTyp); + localStorage.setItem("selectedPoiType", poiTypeName); + + // Optional: Update des Markers mit dem POI-Typ + const marker = poiLayerRef.current.getLayers().find((m) => m.options.id === poiData.id); + if (marker) { + marker.setPopupContent(` +
+ ${poiData.description || "Unbekannt"}
+ ${currentDevice.name}
+ ${poiTypeName || "Unbekannt"}
+
+ `); + marker.openPopup(); + } + } + } catch (error) { + console.error("Fehler beim Abrufen der Gerätedaten:", error); + setLocationDeviceData([]); + } +}; + +export default handlePoiSelect; diff --git a/utils/initializeMap.js b/utils/initializeMap.js new file mode 100644 index 000000000..582210a83 --- /dev/null +++ b/utils/initializeMap.js @@ -0,0 +1,73 @@ +// utils/initializeMap.js +import L from "leaflet"; +import "leaflet-contextmenu"; +import "leaflet/dist/leaflet.css"; +import "leaflet-contextmenu/dist/leaflet.contextmenu.css"; +import * as urls from "../config/urls.js"; +import * as layers from "../config/layers.js"; +import { openInNewTab } from "./openInNewTab.js"; + +export const initializeMap = (mapRef, setMap, setOms, setMenuItemAdded, addItemsToMapContextMenu, hasRights, setPolylineEventsDisabled) => { + if (mapRef.current) { + const initMap = L.map(mapRef.current, { + center: [53.111111, 8.4625], + zoom: 12, + layers: [layers.MAP_LAYERS.TALAS, layers.MAP_LAYERS.ECI, layers.MAP_LAYERS.ULAF, layers.MAP_LAYERS.GSMModem], + minZoom: 5, + maxZoom: 15, + zoomControl: false, + contextmenu: true, + contextmenuItems: [ + { + text: "Station öffnen (Tab)", + icon: "/img/screen_new.png", + callback: (e) => { + const link = localStorage.getItem("polylineLink"); + const clickedElement = e.relatedTarget; + + // Überprüfe, ob Karte und contextmenu existieren + if (initMap && initMap.contextmenu) { + // Verarbeite Kontextmenü-Callback + if (link) { + const newTab = window.open(link, "_blank"); + if (newTab) { + // Lösche Einträge im localStorage + localStorage.removeItem("polylineLink"); + localStorage.removeItem("lastElementType"); + } else { + console.error("Fehler: Das neue Tab konnte nicht geöffnet werden."); + } + } else if (clickedElement instanceof L.Marker || clickedElement instanceof L.Polyline) { + openInNewTab(e, clickedElement); + } else { + console.error("Kein gültiges Ziel für den Kontextmenüeintrag"); + } + } else { + console.error("Karte oder Kontextmenü nicht verfügbar."); + } + }, + }, + "-", + ], + }); + + // Füge die Tile-Layer hinzu + L.tileLayer(urls.ONLINE_TILE_LAYER, { + attribution: '© OpenStreetMap contributors', + }).addTo(initMap); + + // Initialisiere OverlappingMarkerSpiderfier + const overlappingMarkerSpiderfier = new OverlappingMarkerSpiderfier(initMap, { + nearbyDistance: 20, + }); + + // Setze die Map und OMS in den State + setMap(initMap); + setOms(overlappingMarkerSpiderfier); + + // Wenn Rechte geladen sind und es noch nicht hinzugefügt wurde, füge das Kontextmenü hinzu + if (hasRights && !setMenuItemAdded) { + addItemsToMapContextMenu(initMap, setMenuItemAdded, setPolylineEventsDisabled); + } + } +}; diff --git a/utils/mapUtils.js b/utils/mapUtils.js index b9d7d85f7..56e344cdf 100644 --- a/utils/mapUtils.js +++ b/utils/mapUtils.js @@ -13,8 +13,7 @@ export const redrawPolyline = (lineData, lineColors, tooltipContents, map) => { } const color = lineColors[lineData.idModul] || "#000000"; - const tooltipContent = - tooltipContents[lineData.idModul] || "Standard-Tooltip-Inhalt"; + const tooltipContent = tooltipContents[lineData.idModul] || "Standard-Tooltip-Inhalt"; if (lineData.polyline) map.removeLayer(lineData.polyline); @@ -56,7 +55,7 @@ export const saveLineData = (lineData) => { return response.json(); }) .then((data) => { - console.log("Linienänderungen gespeichert:", data); + //console.log("Linienänderungen gespeichert:", data); }) .catch((error) => { console.error("Fehler beim Speichern der Linienänderungen:", error); @@ -82,7 +81,7 @@ export const restoreMapSettings = (map) => { export const checkOverlappingMarkers = (map, markers, plusIcon) => { // Ensure markers is always an array if (!Array.isArray(markers)) { - //console.error("The `markers` argument is not an array:", markers); + console.error("The `markers` argument is not an array:", markers); return; } @@ -105,7 +104,8 @@ export const checkOverlappingMarkers = (map, markers, plusIcon) => { const plusMarker = L.marker(latLng, { icon: plusIcon }); plusMarker.addTo(map); - //console.log("Adding plus icon marker at", latLng); + console.log("Adding plus icon marker at", latLng); } } + console.log("overlappingGroups", overlappingGroups); }; diff --git a/utils/mysqlPool.js b/utils/mysqlPool.js new file mode 100644 index 000000000..80b5f98ef --- /dev/null +++ b/utils/mysqlPool.js @@ -0,0 +1,52 @@ +import mysql from "mysql2/promise"; +// Variablen für den Singleton-Pool +let cachedPool; +let connectionCount = 0; // Zähler für die aktiven Verbindungen + +// Funktion zum Abrufen des Pools +function getPool() { + if (!cachedPool) { + cachedPool = 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, + connectionLimit: 20, // Setze ein Limit für gleichzeitige Verbindungen + waitForConnections: true, + queueLimit: 10, // Warteschlangenlimit für Verbindungen + connectTimeout: 5000, // Timeout für Verbindungsversuche (5 Sekunden) + acquireTimeout: 10000, // Timeout für Verbindungsanforderungen aus dem Pool (10 Sekunden) + idleTimeout: 60000, // 1 Minute + }); + + // Ereignisse für das Protokollieren der Verbindungsstatistiken + cachedPool.on("acquire", () => { + connectionCount++; + console.log(`[ACQUIRE] Active connections: ${connectionCount}`); + }); + + cachedPool.on("release", () => { + connectionCount--; + console.log(`[RELEASE] Active connections: ${connectionCount}`); + }); + + cachedPool.on("enqueue", () => { + console.log(`[ENQUEUE] Waiting for available connection slot.`); + }); + } + + return cachedPool; +} + +// Optionale Funktion zum Schließen aller Verbindungen im Pool (manuell aufzurufen) +export function closePool() { + if (cachedPool) { + cachedPool.end(() => { + console.log("All pool connections closed."); + }); + cachedPool = null; // Setze den Pool auf null, um sicherzustellen, dass er neu erstellt wird, falls benötigt. + } +} + +export default getPool; diff --git a/utils/openInNewTab.js b/utils/openInNewTab.js new file mode 100644 index 000000000..51d0f667b --- /dev/null +++ b/utils/openInNewTab.js @@ -0,0 +1,38 @@ +// utils/openInNewTab.js + +export function openInNewTab(e, target) { + const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL; + let link; + + // Prüfen, ob der Kontextmenü-Eintrag aufgerufen wird, ohne dass ein Marker oder Polyline direkt angesprochen wird + if (!target) { + // Verwende den in localStorage gespeicherten Link + const lastElementType = localStorage.getItem("lastElementType"); + if (lastElementType === "polyline") { + link = localStorage.getItem("polylineLink"); + } + } + + if (target instanceof L.Marker && target.options.link) { + link = `${BASE_URL}${target.options.link}`; + } else if (target instanceof L.Polyline) { + const idLD = target.options.idLD; + console.log("idLD der Linie", idLD); + if (idLD) { + link = `${BASE_URL}cpl.aspx?id=${idLD}`; + } else { + console.error("Keine gültige 'idLD' für die Linie gefunden."); + return; + } + } else if (!link) { + console.error("Fehler: Es wurde kein gültiger Link gefunden."); + return; + } + + // Öffne den Link in einem neuen Tab + if (link) { + window.open(link, "_blank"); + } else { + console.error("Fehler: Es wurde kein gültiger Link gefunden."); + } +} diff --git a/utils/poiUtils.js b/utils/poiUtils.js new file mode 100644 index 000000000..229e10a0b --- /dev/null +++ b/utils/poiUtils.js @@ -0,0 +1,119 @@ +// /utils/poiUtils.js +import circleIcon from "../components/gisPolylines/icons/CircleIcon.js"; +import { saveLineData, redrawPolyline } from "./mapUtils.js"; +import L from "leaflet"; +import "leaflet.smooth_marker_bouncing"; +import { toast } from "react-toastify"; +import * as config from "../config/config.js"; + +export const insertNewPOI = (closestPoints, newPoint, lineData, map) => { + const newMarker = L.marker(newPoint, { + icon: circleIcon, + draggable: true, + }).addTo(map); + lineData.coordinates.splice(closestPoints[2], 0, [newPoint.lat, newPoint.lng]); + + // Hier direkt speichern nach Einfügen + saveLineData(lineData); + + redrawPolyline(lineData); + + // Event-Listener für das Verschieben des Markers hinzufügen + newMarker.on("dragend", () => { + console.log("Marker wurde verschoben in insertNewPOI"); + const newCoords = newMarker.getLatLng(); + setNewCoords(newCoords); + const newCoordinates = [...lineData.coordinates]; + newCoordinates[closestPoints[2]] = [newCoords.lat, newCoords.lng]; + lineData.coordinates = newCoordinates; + redrawPolyline(lineData); + + updateMarkerPosition(newMarker.getLatLng(), lineData, newMarker); + saveLineData(lineData); // Speichern der neuen Koordinaten nach dem Verschieben + }); +}; + +export const removePOI = (marker, lineData, currentZoom, currentCenter) => { + // Save zoom and center to localStorage + //localStorage.setItem("mapZoom", currentZoom); + //localStorage.setItem("mapCenter", JSON.stringify(currentCenter)); + + // Find the index of the coordinate that matches the marker's position + const index = lineData.coordinates.findIndex((coord) => L.latLng(coord[0], coord[1]).equals(marker.getLatLng())); + + if (index !== -1) { + // Remove the coordinate from the line data + lineData.coordinates.splice(index, 1); + + // Redraw the polyline with the updated coordinates + redrawPolyline(lineData); + + // Remove the marker from the map + marker.remove(); + + // Save the updated line data + saveLineData(lineData); + + // Refresh the browser + window.location.reload(); + } +}; + +export const handleEditPoi = ( + marker, + userRights, + setCurrentPoiData, + setShowPoiUpdateModal, + fetchPoiData, + toast // Hier toast als Parameter erhalten +) => { + const editMode = localStorage.getItem("editMode") === "true"; + userRights = editMode ? userRights : undefined; + //console.log("Selected Marker ID (idPoi):", marker.options.id); + //console.log("Selected Marker Description:", marker.options.description); + //console.log("User Rights:", userRights); + + // Sicherstellen, dass userRights ein Array ist + if (!Array.isArray(userRights)) { + console.error("User Rights is not an array:", userRights); + toast.error("Benutzerrechte sind ungültig.", { + position: "top-center", + autoClose: 5000, + hideProgressBar: false, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + progress: undefined, + }); + return; + } + + console.log("User Rights includes 56:", userRights.includes(56)); + + // Prüfung, ob der Benutzer die notwendigen Rechte hat + if (!userRights.includes(56)) { + toast.error("Benutzer hat keine Berechtigung zum Bearbeiten.", { + position: "top-center", + autoClose: 5000, + hideProgressBar: false, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + progress: undefined, + }); + console.log("Benutzer hat keine Berechtigung zum Bearbeiten."); + return; // Beendet die Funktion frühzeitig, wenn keine Berechtigung vorliegt + } + + setCurrentPoiData({ + idPoi: marker.options.id, + name: marker.options.name, + description: marker.options.description, + idLD: marker.options.idLD, + }); + + fetchPoiData(marker.options.id); + + setShowPoiUpdateModal(true); +}; +//------------------------------------------------------------------- diff --git a/utils/setupPOIs.js b/utils/setupPOIs.js new file mode 100644 index 000000000..7abc7c945 --- /dev/null +++ b/utils/setupPOIs.js @@ -0,0 +1,131 @@ +// utils/setupPOIs.js +import { findClosestPoints } from "./geometryUtils"; +import handlePoiSelect from "./handlePoiSelect"; +import { updateLocationInDatabase } from "../services/apiService"; +import { handleEditPoi, insertNewPOI, removePOI } from "./poiUtils"; +import { parsePoint } from "./geometryUtils"; +import circleIcon from "../components/gisPolylines/icons/CircleIcon"; +import startIcon from "../components/gisPolylines/icons/StartIcon"; +import endIcon from "../components/gisPolylines/icons/EndIcon"; +import { redrawPolyline } from "./mapUtils"; +import { openInNewTab } from "../utils/openInNewTab"; +import { disablePolylineEvents, enablePolylineEvents } from "./setupPolylines"; // Importiere die Funktionen + +export const setupPOIs = async ( + map, + locations, + poiData, + poiTypMap, + userRights, + poiLayerRef, + setSelectedPoi, + setLocationDeviceData, + setDeviceName, + setCurrentPoi, + poiLayerVisible, + fetchPoiData, + toast, + setShowPoiUpdateModal, + setCurrentPoiData, + deviceName +) => { + const editMode = localStorage.getItem("editMode") === "true"; // Prüfen, ob der Bearbeitungsmodus aktiv ist + userRights = editMode ? userRights : undefined; // Nur Berechtigungen anwenden, wenn editMode true ist + + if (map && poiLayerRef.current) { + map.removeLayer(poiLayerRef.current); + poiLayerRef.current = new L.LayerGroup().addTo(map); + + for (const location of locations) { + try { + const { latitude, longitude } = parsePoint(location.position); + const poiTypName = poiTypMap.get(location.idPoiTyp) || "Unbekannt"; + const canDrag = userRights ? userRights.includes(56) : false; + const matchingIcon = poiData.find((poi) => poi.idPoi === location.idPoi); + const iconUrl = matchingIcon ? `/img/icons/pois/${matchingIcon.path}` : "/img/icons/pois/default-icon.png"; + + const marker = L.marker([latitude, longitude], { + icon: L.icon({ + iconUrl: iconUrl, + iconSize: [25, 41], + iconAnchor: [12, 41], + popupAnchor: [1, -34], + }), + draggable: canDrag, + id: location.idPoi, + name: location.name, + description: location.description, + idLD: location.idLD, + link: location.link, + }); + + // Nur das Kontextmenü "POI Bearbeiten" hinzufügen, wenn editMode true ist + if (editMode) { + marker.bindContextMenu({ + contextmenu: true, + contextmenuWidth: 140, + contextmenuItems: [ + { + text: "POI Bearbeiten", + icon: "/img/poi-edit.png", + callback: () => handleEditPoi(marker, userRights, setCurrentPoiData, setShowPoiUpdateModal, fetchPoiData, toast), + }, + ], + }); + } + + marker.bindPopup(` +
+ ${location.description || "Unbekannt"}
+ ${deviceName || "unbekannt"}
+ ${poiTypName}
+
+ `); + + marker.on("mouseover", function () { + console.log("Device Name:", marker); // Debugging + handlePoiSelect( + { + id: location.idPoi, + deviceId: location.idLD, + idPoiTyp: location.idPoiTyp, + typ: poiTypName, + description: location.description, + idLD: location.idLD, + }, + setSelectedPoi, + setLocationDeviceData, + setDeviceName, // Stelle sicher, dass dies korrekt funktioniert + poiLayerRef, + poiTypMap + ); + + localStorage.setItem("lastElementType", "marker"); + localStorage.setItem("markerLink", this.options.link); + }); + + marker.on("mouseout", function () { + this.closePopup(); + }); + + marker.on("dragend", (e) => { + console.log("Marker wurde verschoben in setupPOIs"); + if (canDrag) { + const newLat = e.target.getLatLng().lat; + const newLng = e.target.getLatLng().lng; + const markerId = e.target.options.id; + updateLocationInDatabase(markerId, newLat, newLng).then(() => {}); + } else { + console.error("Drag operation not allowed"); + } + }); + + if (poiLayerVisible) { + marker.addTo(poiLayerRef.current); + } + } catch (error) { + console.error("Error processing a location:", error); + } + } + } +}; diff --git a/utils/setupPolylines-back.js b/utils/setupPolylines-back.js new file mode 100644 index 000000000..3b666e340 --- /dev/null +++ b/utils/setupPolylines-back.js @@ -0,0 +1,341 @@ +// utils/setupPolylines.js +import { findClosestPoints } from "./geometryUtils"; +import handlePoiSelect from "./handlePoiSelect"; +import { updateLocationInDatabase } from "../services/apiService"; +import { handleEditPoi, insertNewPOI, removePOI } from "./poiUtils"; +import { parsePoint } from "./geometryUtils"; +import circleIcon from "../components/gisPolylines/icons/CircleIcon"; +import startIcon from "../components/gisPolylines/icons/StartIcon"; +import endIcon from "../components/gisPolylines/icons/EndIcon"; +import { redrawPolyline } from "./mapUtils"; +import { openInNewTab } from "./openInNewTab"; +import { toast } from "react-toastify"; +import { polylineLayerVisibleState } from "../store/atoms/polylineLayerVisibleState"; +import { useRecoilValue } from "recoil"; + +// Funktion zum Deaktivieren der Polyline-Ereignisse +export function disablePolylineEvents(polylines) { + polylines.forEach((polyline) => { + polyline.off("mouseover"); + polyline.off("mouseout"); + }); +} + +// Funktion zum Aktivieren der Polyline-Ereignisse +export function enablePolylineEvents(polylines, lineColors) { + // Überprüfe, ob polylines definiert ist und ob es Elemente enthält + if (!polylines || polylines.length === 0) { + //console.warn("Keine Polylinien vorhanden oder polylines ist undefined."); + return; + } + + // Falls Polylinien vorhanden sind, wende die Events an + polylines.forEach((polyline) => { + polyline.on("mouseover", (e) => { + //console.log("Mouseover on polyline", polyline.options); + polyline.setStyle({ weight: 14 }); + const link = `${process.env.NEXT_PUBLIC_BASE_URL}cpl.aspx?id=${polyline.options.idLD}`; + //localStorage.setItem("lastElementType", "polyline"); + //localStorage.setItem("polylineLink", link); + }); + + polyline.on("mouseout", (e) => { + //console.log("Mouseout from polyline", polyline.options); + polyline.setStyle({ weight: 3 }); + }); + }); +} + +export const setupPolylines = (map, linePositions, lineColors, tooltipContents, setNewCoords, tempMarker, currentZoom, currentCenter, polylineVisible) => { + if (localStorage.getItem("polylineVisible") === null) { + localStorage.setItem("polylineVisible", "true"); // Standardwert setzen + polylineVisible = true; // Wert in der Funktion initialisieren + } else { + polylineVisible = localStorage.getItem("polylineVisible") === "true"; + } + + if (!polylineVisible) { + // Entferne alle Polylinien, wenn sie ausgeblendet werden sollen + if (window.polylines) { + window.polylines.forEach((polyline) => { + if (map.hasLayer(polyline)) { + map.removeLayer(polyline); + } + }); + } + return { markers: [], polylines: [] }; + } + const markers = []; + const polylines = []; + const editMode = localStorage.getItem("editMode") === "true"; // Prüfen, ob der Bearbeitungsmodus aktiv ist + + linePositions.forEach((lineData, lineIndex) => { + const lineMarkers = []; + + lineData.coordinates.forEach((coord, index) => { + let icon = circleIcon; + if (index === 0) { + icon = startIcon; + } else if (index === lineData.coordinates.length - 1) { + icon = endIcon; + } + + // Nur Marker mit circleIcon ausblenden, wenn Bearbeitungsmodus deaktiviert ist + if (icon !== circleIcon || editMode) { + const marker = L.marker(coord, { + icon: icon, + draggable: editMode, // Nur verschiebbar, wenn Bearbeitungsmodus aktiv ist + contextmenu: true, + contextmenuInheritItems: false, + contextmenuItems: [], + }).addTo(map); + + marker.on("dragend", () => { + console.log("Marker wurde verschoben in setupPolylines.js"); + if (editMode) { + const newCoords = marker.getLatLng(); + setNewCoords(newCoords); + const newCoordinates = [...lineData.coordinates]; + newCoordinates[index] = [newCoords.lat, newCoords.lng]; + + const updatedPolyline = L.polyline(newCoordinates, { + color: lineColors[`${lineData.idLD}-${lineData.idModul}`] || "#000000", + }).addTo(map); + + updatedPolyline.bindTooltip(tooltipContents[`${lineData.idLD}-${lineData.idModul}`] || "Standard-Tooltip-Inhalt", { + permanent: false, + direction: "auto", + }); + + updatedPolyline.on("mouseover", () => { + updatedPolyline.setStyle({ weight: 20 }); + updatedPolyline.bringToFront(); + }); + + updatedPolyline.on("mouseout", () => { + updatedPolyline.setStyle({ weight: 3 }); + }); + + polylines[lineIndex].remove(); + polylines[lineIndex] = updatedPolyline; + lineData.coordinates = newCoordinates; + + const requestData = { + idModul: lineData.idModul, + idLD: lineData.idLD, + newCoordinates, + }; + + fetch("/api/talas_v5_DB/gisLines/updateLineCoordinates", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(requestData), + }) + .then((response) => { + if (!response.ok) { + return response.json().then((data) => { + throw new Error(data.error || "Unbekannter Fehler"); + }); + } + return response.json(); + }) + .then((data) => { + console.log("Koordinaten erfolgreich aktualisiert:", data); + }) + .catch((error) => { + console.error("Fehler beim Aktualisieren der Koordinaten:", error.message); + }); + } else { + toast.error("Benutzer hat keine Berechtigung zum Bearbeiten.", { + position: "top-center", + autoClose: 5000, + hideProgressBar: false, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + progress: undefined, + }); + } + }); + + marker.on("mouseover", function () { + this.bindContextMenu({ + contextmenuItems: [ + { + text: "Stützpunkt entfernen", + icon: "/img/icons/gisLines/remove-support-point.svg", + callback: () => { + if (editMode) { + const newCoords = marker.getLatLng(); + const newCoordinates = [...lineData.coordinates]; + newCoordinates[index] = [newCoords.lat, newCoords.lng]; + + removePOI(marker, lineData, currentZoom, currentCenter); + polylines[lineIndex].remove(); + lineData.coordinates = newCoordinates; + } else { + toast.error("Benutzer hat keine Berechtigung zum Bearbeiten.", { + position: "top-center", + autoClose: 5000, + hideProgressBar: false, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + progress: undefined, + }); + } + }, + }, + ], + }); + }); + + marker.on("mouseout", function () { + this.unbindContextMenu(); + }); + + lineMarkers.push(marker); + } + }); + + const polyline = L.polyline(lineData.coordinates, { + color: lineColors[`${lineData.idLD}-${lineData.idModul}`] || "#000000", + weight: 3, + contextmenu: true, + contextmenuInheritItems: false, // Standard-Kontextmenü deaktivieren + contextmenuItems: [], + }).addTo(map); + + // Füge "Stützpunkt hinzufügen" nur hinzu, wenn editMode aktiv ist + if (editMode) { + polyline.options.contextmenuItems.push( + { + text: "Station öffnen (Tab)", + icon: "/img/screen_new.png", + callback: (e) => { + const link = `${process.env.NEXT_PUBLIC_BASE_URL}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`; + window.open(link, "_blank"); + }, + }, + { separator: true }, + + { + text: "Koordinaten anzeigen", + icon: "/img/not_listed_location.png", + callback: (e) => { + alert("Breitengrad: " + e.latlng.lat.toFixed(5) + "\nLängengrad: " + e.latlng.lng.toFixed(5)); + }, + }, + { separator: true }, + { + text: "Reinzoomen", + icon: "/img/zoom_in.png", + callback: (e) => map.zoomIn(), + }, + { + text: "Rauszoomen", + icon: "/img/zoom_out.png", + callback: (e) => map.zoomOut(), + }, + { + text: "Hier zentrieren", + icon: "/img/center_focus.png", + callback: (e) => map.panTo(e.latlng), + }, + { separator: true }, + { + text: "POI hinzufügen", + icon: "/img/add_station.png", + callback: (e) => { + // Hier kannst du die Logik für das Hinzufügen eines POIs implementieren + alert("POI hinzufügen an: " + e.latlng); + }, + }, + { + text: "Stützpunkt hinzufügen", + icon: "/img/icons/gisLines/add-support-point.svg", + callback: (e) => { + if (tempMarker) { + tempMarker.remove(); + } + const newPoint = e.latlng; + const closestPoints = findClosestPoints(lineData.coordinates, newPoint, map); + insertNewPOI(closestPoints, newPoint, lineData, map); + redrawPolyline(lineData, lineColors, tooltipContents, map); + window.location.reload(); + }, + } + ); + } + + // Hier wird der Tooltip hinzugefügt + polyline.bindTooltip(tooltipContents[`${lineData.idLD}-${lineData.idModul}`] || "Standard-Tooltip-Inhalt", { + permanent: false, + direction: "auto", + }); + + polyline.on("mouseover", (e) => { + const startTime = Date.now(); // Startzeit erfassen + localStorage.setItem("contextMenuStartTime", startTime); // Speichern in localStorage + + // Starte einen Intervall-Timer, um die Differenz zu berechnen + const countdownInterval = setInterval(() => { + const currentTime = Date.now(); + const elapsedTime = (currentTime - startTime) / 1000; // Differenz in Sekunden + + // Speichern der abgelaufenen Zeit in localStorage + localStorage.setItem("contextMenuCountdown", elapsedTime); + + // Wenn die Zeit 17 Sekunden erreicht, schließe das Menü + if (elapsedTime >= 17) { + clearInterval(countdownInterval); + const contextMenu = map.contextmenu; // Zugriff auf das Kontextmenü + contextMenu.hide(); // Kontextmenü schließen + } + }, 1000); // Jede Sekunde + //console.log("Mouseover on polyline", lineData); + polyline.setStyle({ weight: 14 }); + const link = `${process.env.NEXT_PUBLIC_BASE_URL}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`; + console.log("Link der Linie:", link); + //localStorage.setItem("lastElementType", "polyline"); + //localStorage.setItem("polylineLink", link); + }); + + polyline.on("mouseout", (e) => { + // console.log("Mouseout from polyline", lineData); + polyline.setStyle({ weight: 3 }); + // Setze den Countdown auf 0, wenn mouseout ausgelöst wird + localStorage.setItem("contextMenuCountdown", 0); + }); + // Speichere den Link bei einem Rechtsklick (Kontextmenü) + /* + polyline.on("contextmenu", (e) => { + const link = `${process.env.NEXT_PUBLIC_BASE_URL}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`; + console.log("Link der Linie (via Rechtsklick):", link); + localStorage.setItem("lastElementType", "polyline"); + localStorage.setItem("polylineLink", link); + }); + */ + // Starte den Timer zum Schließen des Kontextmenüs nach 15 Sekunden + polyline.on("contextmenu", function (e) { + const contextMenu = this._map.contextmenu; // Zugriff auf das Kontextmenü + const closeMenu = () => contextMenu.hide(); // Funktion zum Schließen des Menüs + + const countdown = parseInt(localStorage.getItem("contextMenuCountdown"), 30); + if (countdown >= 28) { + closeMenu(); + } + }); + + polylines.push(polyline); + markers.push(...lineMarkers); + }); + + // Speichere Polylines und LineColors global für den Zugriff in anderen Funktionen + window.polylines = polylines; + window.lineColors = lineColors; + + return { markers, polylines }; +}; diff --git a/utils/setupPolylines.js b/utils/setupPolylines.js new file mode 100644 index 000000000..7e28edeeb --- /dev/null +++ b/utils/setupPolylines.js @@ -0,0 +1,423 @@ +// utils/setupPolylines.js +import { findClosestPoints } from "./geometryUtils"; +import handlePoiSelect from "./handlePoiSelect"; +import { updateLocationInDatabase } from "../services/apiService"; +import { handleEditPoi, insertNewPOI, removePOI } from "./poiUtils"; +import { parsePoint } from "./geometryUtils"; +import circleIcon from "../components/gisPolylines/icons/CircleIcon"; +import startIcon from "../components/gisPolylines/icons/StartIcon"; +import endIcon from "../components/gisPolylines/icons/EndIcon"; +import { redrawPolyline } from "./mapUtils"; +import { openInNewTab } from "./openInNewTab"; +import { toast } from "react-toastify"; +import { polylineLayerVisibleState } from "../store/atoms/polylineLayerVisibleState"; +import { useRecoilValue } from "recoil"; + +// Funktion zum Deaktivieren der Polyline-Ereignisse +export function disablePolylineEvents(polylines) { + polylines.forEach((polyline) => { + polyline.off("mouseover"); + polyline.off("mouseout"); + }); +} + +// Funktion zum Aktivieren der Polyline-Ereignisse +export function enablePolylineEvents(polylines, lineColors) { + // Überprüfe, ob polylines definiert ist und ob es Elemente enthält + if (!polylines || polylines.length === 0) { + //console.warn("Keine Polylinien vorhanden oder polylines ist undefined."); + return; + } + + // Falls Polylinien vorhanden sind, wende die Events an + polylines.forEach((polyline) => { + polyline.on("mouseover", (e) => { + //console.log("Mouseover on polyline", polyline.options); + polyline.setStyle({ weight: 14 }); + const link = `${process.env.NEXT_PUBLIC_BASE_URL}cpl.aspx?id=${polyline.options.idLD}`; + //localStorage.setItem("lastElementType", "polyline"); + //localStorage.setItem("polylineLink", link); + }); + + polyline.on("mouseout", (e) => { + //console.log("Mouseout from polyline", polyline.options); + polyline.setStyle({ weight: 3 }); + }); + }); +} +// Funktion zum Schließen des Kontextmenüs und Entfernen der Markierung +function closePolylineSelectionAndContextMenu(map) { + try { + // Entferne alle markierten Polylinien + if (window.selectedPolyline) { + window.selectedPolyline.setStyle({ weight: 3 }); // Originalstil wiederherstellen + window.selectedPolyline = null; + } + + // Überprüfe, ob map und map.contextmenu definiert sind + if (map && map.contextmenu) { + map.contextmenu.hide(); // Kontextmenü schließen + } else { + console.warn("Kontextmenü ist nicht verfügbar."); + } + } catch (error) { + console.error("Fehler beim Schließen des Kontextmenüs:", error); + window.location.reload(); + } + + // Countdown-Status zurücksetzen + localStorage.removeItem("contextMenuCountdown"); + localStorage.removeItem("contextMenuExpired"); +} + +// Überprüft regelmäßig den Status in localStorage +function monitorContextMenu(map) { + setInterval(() => { + const isContextMenuExpired = localStorage.getItem("contextMenuExpired") === "true"; + if (isContextMenuExpired) { + closePolylineSelectionAndContextMenu(map); + localStorage.removeItem("contextMenuExpired"); // Flagge entfernen, um wiederverwendbar zu sein + } + }, 1000); // Alle 1 Sekunde überprüfen +} + +export const setupPolylines = (map, linePositions, lineColors, tooltipContents, setNewCoords, tempMarker, currentZoom, currentCenter, polylineVisible) => { + if (localStorage.getItem("polylineVisible") === null) { + localStorage.setItem("polylineVisible", "true"); // Standardwert setzen + polylineVisible = true; // Wert in der Funktion initialisieren + } else { + polylineVisible = localStorage.getItem("polylineVisible") === "true"; + } + + if (!polylineVisible) { + // Entferne alle Polylinien, wenn sie ausgeblendet werden sollen + if (window.polylines) { + window.polylines.forEach((polyline) => { + if (map.hasLayer(polyline)) { + map.removeLayer(polyline); + } + }); + } + return { markers: [], polylines: [] }; + } + const markers = []; + const polylines = []; + const editMode = localStorage.getItem("editMode") === "true"; // Prüfen, ob der Bearbeitungsmodus aktiv ist + + linePositions.forEach((lineData, lineIndex) => { + const lineMarkers = []; + + lineData.coordinates.forEach((coord, index) => { + let icon = circleIcon; + if (index === 0) { + icon = startIcon; + } else if (index === lineData.coordinates.length - 1) { + icon = endIcon; + } + + // Nur Marker mit circleIcon ausblenden, wenn Bearbeitungsmodus deaktiviert ist + if (icon !== circleIcon || editMode) { + const marker = L.marker(coord, { + icon: icon, + draggable: editMode, // Nur verschiebbar, wenn Bearbeitungsmodus aktiv ist + contextmenu: true, + contextmenuInheritItems: false, + contextmenuItems: [], + }).addTo(map); + + marker.on("dragend", () => { + console.log("Marker wurde verschoben in setupPolylines.js"); + if (editMode) { + const newCoords = marker.getLatLng(); + setNewCoords(newCoords); + const newCoordinates = [...lineData.coordinates]; + newCoordinates[index] = [newCoords.lat, newCoords.lng]; + + const updatedPolyline = L.polyline(newCoordinates, { + color: lineColors[`${lineData.idLD}-${lineData.idModul}`] || "#000000", + }).addTo(map); + + updatedPolyline.bindTooltip(tooltipContents[`${lineData.idLD}-${lineData.idModul}`] || "Standard-Tooltip-Inhalt", { + permanent: false, + direction: "auto", + }); + + updatedPolyline.on("mouseover", () => { + updatedPolyline.setStyle({ weight: 20 }); + updatedPolyline.bringToFront(); + }); + + updatedPolyline.on("mouseout", () => { + updatedPolyline.setStyle({ weight: 3 }); + }); + + polylines[lineIndex].remove(); + polylines[lineIndex] = updatedPolyline; + lineData.coordinates = newCoordinates; + + const requestData = { + idModul: lineData.idModul, + idLD: lineData.idLD, + newCoordinates, + }; + + fetch("/api/talas_v5_DB/gisLines/updateLineCoordinates", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(requestData), + }) + .then((response) => { + if (!response.ok) { + return response.json().then((data) => { + throw new Error(data.error || "Unbekannter Fehler"); + }); + } + return response.json(); + }) + .then((data) => { + console.log("Koordinaten erfolgreich aktualisiert:", data); + }) + .catch((error) => { + console.error("Fehler beim Aktualisieren der Koordinaten:", error.message); + }); + } else { + toast.error("Benutzer hat keine Berechtigung zum Bearbeiten.", { + position: "top-center", + autoClose: 5000, + hideProgressBar: false, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + progress: undefined, + }); + } + }); + + marker.on("mouseover", function () { + this.bindContextMenu({ + contextmenuItems: [ + { + text: "Stützpunkt entfernen", + icon: "/img/icons/gisLines/remove-support-point.svg", + callback: () => { + if (editMode) { + const newCoords = marker.getLatLng(); + const newCoordinates = [...lineData.coordinates]; + newCoordinates[index] = [newCoords.lat, newCoords.lng]; + + removePOI(marker, lineData, currentZoom, currentCenter); + polylines[lineIndex].remove(); + lineData.coordinates = newCoordinates; + } else { + toast.error("Benutzer hat keine Berechtigung zum Bearbeiten.", { + position: "top-center", + autoClose: 5000, + hideProgressBar: false, + closeOnClick: true, + pauseOnHover: true, + draggable: true, + progress: undefined, + }); + } + }, + }, + ], + }); + }); + + marker.on("mouseout", function () { + this.unbindContextMenu(); + }); + + lineMarkers.push(marker); + } + }); + + const polyline = L.polyline(lineData.coordinates, { + color: lineColors[`${lineData.idLD}-${lineData.idModul}`] || "#000000", + weight: 3, + contextmenu: true, + contextmenuInheritItems: false, // Standard-Kontextmenü deaktivieren + contextmenuItems: [], + }).addTo(map); + + // Füge "Stützpunkt hinzufügen" nur hinzu, wenn editMode aktiv ist + if (editMode) { + polyline.options.contextmenuItems.push( + { + text: "Station öffnen (Tab)", + icon: "/img/screen_new.png", + callback: (e) => { + const link = `${process.env.NEXT_PUBLIC_BASE_URL}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`; + window.open(link, "_blank"); + }, + }, + { separator: true }, + + { + text: "Koordinaten anzeigen", + icon: "/img/not_listed_location.png", + callback: (e) => { + alert("Breitengrad: " + e.latlng.lat.toFixed(5) + "\nLängengrad: " + e.latlng.lng.toFixed(5)); + }, + }, + { separator: true }, + { + text: "Reinzoomen", + icon: "/img/zoom_in.png", + callback: (e) => map.zoomIn(), + }, + { + text: "Rauszoomen", + icon: "/img/zoom_out.png", + callback: (e) => map.zoomOut(), + }, + { + text: "Hier zentrieren", + icon: "/img/center_focus.png", + callback: (e) => map.panTo(e.latlng), + }, + { separator: true }, + { + text: "POI hinzufügen", + icon: "/img/add_station.png", + callback: (e) => { + // Hier kannst du die Logik für das Hinzufügen eines POIs implementieren + alert("POI hinzufügen an: " + e.latlng); + }, + }, + { + text: "Stützpunkt hinzufügen", + icon: "/img/icons/gisLines/add-support-point.svg", + callback: (e) => { + if (tempMarker) { + tempMarker.remove(); + } + const newPoint = e.latlng; + const closestPoints = findClosestPoints(lineData.coordinates, newPoint, map); + insertNewPOI(closestPoints, newPoint, lineData, map); + redrawPolyline(lineData, lineColors, tooltipContents, map); + window.location.reload(); + }, + } + ); + } else { + polyline.options.contextmenuItems.push( + { + text: "Station öffnen (Tab)", + icon: "/img/screen_new.png", + callback: (e) => { + const link = `${process.env.NEXT_PUBLIC_BASE_URL}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`; + window.open(link, "_blank"); + }, + }, + { separator: true }, + + { + text: "Koordinaten anzeigen", + icon: "/img/not_listed_location.png", + callback: (e) => { + alert("Breitengrad: " + e.latlng.lat.toFixed(5) + "\nLängengrad: " + e.latlng.lng.toFixed(5)); + }, + }, + { separator: true }, + { + text: "Reinzoomen", + icon: "/img/zoom_in.png", + callback: (e) => map.zoomIn(), + }, + { + text: "Rauszoomen", + icon: "/img/zoom_out.png", + callback: (e) => map.zoomOut(), + }, + + { + text: "Hier zentrieren", + icon: "/img/center_focus.png", + callback: (e) => map.panTo(e.latlng), + }, + { separator: true }, + { + text: "POI hinzufügen", + icon: "/img/add_station.png", + callback: (e) => { + // Hier kannst du die Logik für das Hinzufügen eines POIs implementieren + alert("POI hinzufügen an: " + e.latlng); + }, + } + ); + } + + // Hier wird der Tooltip hinzugefügt + polyline.bindTooltip(tooltipContents[`${lineData.idLD}-${lineData.idModul}`] || "Standard-Tooltip-Inhalt", { + permanent: false, + direction: "auto", + }); + + polyline.on("mouseover", (e) => { + const startTime = Date.now(); // Startzeit erfassen + localStorage.setItem("contextMenuStartTime", startTime); // Speichern in localStorage + + // Starte einen Intervall-Timer, um die Differenz zu berechnen + /* const countdownInterval = setInterval(() => { + const currentTime = Date.now(); + const elapsedTime = (currentTime - startTime) / 1000; // Differenz in Sekunden + + // Speichern der abgelaufenen Zeit in localStorage + localStorage.setItem("contextMenuCountdown", elapsedTime); + + // Wenn die Zeit 17 Sekunden erreicht, schließe das Menü + if (elapsedTime >= 17) { + clearInterval(countdownInterval); + const contextMenu = map.contextmenu; // Zugriff auf das Kontextmenü + contextMenu.hide(); // Kontextmenü schließen + } + }, 1000); */ + // Jede Sekunde + //console.log("Mouseover on polyline", lineData); + polyline.setStyle({ weight: 14 }); + const link = `${process.env.NEXT_PUBLIC_BASE_URL}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`; + console.log("Link der Linie:", link); + //localStorage.setItem("lastElementType", "polyline"); + //localStorage.setItem("polylineLink", link); + }); + + polyline.on("mouseout", (e) => { + // console.log("Mouseout from polyline", lineData); + polyline.setStyle({ weight: 3 }); + // Setze den Countdown auf 0, wenn mouseout ausgelöst wird + localStorage.setItem("contextMenuCountdown", 0); + }); + // Speichere den Link bei einem Rechtsklick (Kontextmenü) + /* + polyline.on("contextmenu", (e) => { + const link = `${process.env.NEXT_PUBLIC_BASE_URL}cpl.aspx?ver=35&kue=24&id=${lineData.idLD}`; + console.log("Link der Linie (via Rechtsklick):", link); + localStorage.setItem("lastElementType", "polyline"); + localStorage.setItem("polylineLink", link); + }); + */ + // Starte den Timer zum Schließen des Kontextmenüs nach 15 Sekunden + polyline.on("contextmenu", function (e) { + const contextMenu = this._map.contextmenu; // Zugriff auf das Kontextmenü + const closeMenu = () => contextMenu.hide(); // Funktion zum Schließen des Menüs + + const countdown = parseInt(localStorage.getItem("contextMenuCountdown"), 30); + if (countdown >= 28) { + closeMenu(); + } + }); + + polylines.push(polyline); + markers.push(...lineMarkers); + }); + + // Speichere Polylines und LineColors global für den Zugriff in anderen Funktionen + window.polylines = polylines; + window.lineColors = lineColors; + monitorContextMenu(map); + return { markers, polylines }; +}; diff --git a/utils/zoomAndCenterUtils.js b/utils/zoomAndCenterUtils.js index dcb01772c..5bd87b9e2 100644 --- a/utils/zoomAndCenterUtils.js +++ b/utils/zoomAndCenterUtils.js @@ -14,9 +14,14 @@ export const zoomIn = (e, map) => { console.error("map is not defined in zoomIn"); return; } - map.flyTo(e.latlng, 12); - localStorage.setItem("mapZoom", map.getZoom()); - localStorage.setItem("mapCenter", JSON.stringify(map.getCenter())); + + const currentZoom = map.getZoom(); + + if (currentZoom < 14) { + map.flyTo(e.latlng, 14); + localStorage.setItem("mapZoom", 16); + localStorage.setItem("mapCenter", JSON.stringify(map.getCenter())); + } }; export const zoomOut = (map) => { @@ -24,14 +29,18 @@ export const zoomOut = (map) => { console.error("map is not defined in zoomOut"); return; } - const x = 51.41321407879154; - const y = 7.739617925303934; - const zoom = 7; - console.log("map"); - console.log(map); - map.flyTo([x, y], zoom); - localStorage.setItem("mapZoom", map.getZoom()); - localStorage.setItem("mapCenter", JSON.stringify(map.getCenter())); + + const currentZoom = map.getZoom(); + + if (currentZoom > 7) { + const x = 51.41321407879154; + const y = 7.739617925303934; + const zoom = 7; + + map.flyTo([x, y], zoom); + localStorage.setItem("mapZoom", zoom); + localStorage.setItem("mapCenter", JSON.stringify(map.getCenter())); + } }; export const centerHere = (e, map) => { diff --git a/websocket-server.js b/websocket-server.js new file mode 100644 index 000000000..d233ed4cb --- /dev/null +++ b/websocket-server.js @@ -0,0 +1,24 @@ +const WebSocket = require("ws"); + +// Starte den WebSocket-Server auf Port 3001 +const wss = new WebSocket.Server({ port: 3001 }); + +wss.on("connection", (ws) => { + console.log("New WebSocket connection"); + + ws.on("message", (message) => { + console.log("Received:", message); + const parsedMessage = JSON.parse(message); + + // Beispielnachricht an den Client zurücksenden + if (parsedMessage.type === "test") { + ws.send(JSON.stringify({ message: `Hallo zurück, ${parsedMessage.message}` })); + } + }); + + ws.on("close", () => { + console.log("WebSocket connection closed"); + }); +}); + +console.log("WebSocket-Server läuft auf ws://localhost:3001");