Compare commits
29 Commits
aeec307909
...
f390f93293
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f390f93293 | ||
|
|
28dcb284bf | ||
|
|
4f0527e8a9 | ||
|
|
3d0ce4a2b4 | ||
|
|
76280b365b | ||
|
|
c112ec2da4 | ||
|
|
7faee5fd79 | ||
|
|
e52b0cc520 | ||
|
|
4a42c428f0 | ||
|
|
1d3d04d49c | ||
|
|
dd9980409c | ||
|
|
ea6d71a4f5 | ||
|
|
13ca1cece0 | ||
|
|
f22bb4b232 | ||
|
|
bfd091b1b1 | ||
|
|
81b6379895 | ||
|
|
42ca88d27e | ||
|
|
fdb70d892c | ||
|
|
73e9c63e36 | ||
|
|
e520207526 | ||
|
|
2e5acf9327 | ||
|
|
cdfdd3d6cf | ||
|
|
5b86d5293b | ||
|
|
31c770f778 | ||
|
|
051dd4c306 | ||
|
|
995f084e15 | ||
|
|
eaacec71da | ||
|
|
6bc2e16657 | ||
|
|
1208024f76 |
@@ -23,4 +23,4 @@ NEXT_PUBLIC_USE_MOCKS=true
|
||||
# z.B. http://10.10.0.13/xyz/index.aspx -> basePath in config.json auf /xyz setzen
|
||||
# basePath wird jetzt in public/config.json gepflegt
|
||||
# App-Versionsnummer
|
||||
NEXT_PUBLIC_APP_VERSION=1.1.367
|
||||
NEXT_PUBLIC_APP_VERSION=1.1.396
|
||||
|
||||
@@ -24,4 +24,4 @@ NEXT_PUBLIC_USE_MOCKS=false
|
||||
# basePath wird jetzt in public/config.json gepflegt
|
||||
|
||||
# App-Versionsnummer
|
||||
NEXT_PUBLIC_APP_VERSION=1.1.367
|
||||
NEXT_PUBLIC_APP_VERSION=1.1.396
|
||||
|
||||
25
.gitignore
vendored
25
.gitignore
vendored
@@ -35,3 +35,28 @@ docs.zip
|
||||
/mockData/
|
||||
/__mocks__/
|
||||
/__tests__/
|
||||
|
||||
# --- Playwright artifacts & test selection ---
|
||||
# Ignore Playwright output folders nested under playwright/
|
||||
/playwright/test-results/
|
||||
/playwright/playwright-report/
|
||||
/playwright/.last-run.json
|
||||
# If you ever enable these paths, keep them under playwright/ and ignore them
|
||||
/playwright/traces/
|
||||
/playwright/screenshots/
|
||||
/playwright/videos/
|
||||
# Ignore JUnit report artifacts under playwright/ (currently unused)
|
||||
/playwright/reports/junit/
|
||||
|
||||
# Track only spec files under playwright/tests; ignore other files in that folder
|
||||
/playwright/tests/**
|
||||
!/playwright/tests/**/*.spec.js
|
||||
!/playwright/tests/**/*.spec.ts
|
||||
|
||||
# Ignore Playwright cache if present
|
||||
/playwright/.cache/
|
||||
# playwright reports
|
||||
/playwright/reports/
|
||||
# Jira /Confluence Upload Script Secrets und den script selbst
|
||||
/scripts/confluence-upload/secrets.ps1
|
||||
/scripts/confluence-upload/upload-docs.ps1
|
||||
|
||||
195
README.confluence
Normal file
195
README.confluence
Normal file
@@ -0,0 +1,195 @@
|
||||
h1. {anchor:nodemap-kartenvisualisierung-für-talas.web-next.js-leaflet-redux}🌍 NodeMap – Kartenvisualisierung für TALAS.web \(Next.js, Leaflet, Redux)
|
||||
NodeMap ist eine modulare Kartenanwendung zur Visualisierung und Bearbeitung von GIS-Daten, POIs und Gerätestatus in einer interaktiven Leaflet-Karte.
|
||||
|
||||
{quote}
|
||||
📘 Für Entwickler:
|
||||
Die technische Dokumentation \(Architektur, Redux, Komponenten, etc.) befindet sich in:
|
||||
[{{/docs/README.md}}|docs/README.md]
|
||||
{quote}
|
||||
h2. {anchor:live-vorschau-der-karte}🌍 Live-Vorschau der Karte
|
||||
!docs/screenshots/overview1.png|alt=Startansicht der NodeMap Karte!
|
||||
|
||||
----
|
||||
{quote}
|
||||
🖥 Entwicklung & Test unter Windows 11 mit Node.js v18.17.1 und IIS
|
||||
📦 MySQL 8.0 läuft lokal in einem Docker-Container \(nur für Entwicklung)
|
||||
🗄 Produktionsumgebung: TALAS.web und MySQL Server unter Windows Server
|
||||
{quote}
|
||||
----
|
||||
h2. {anchor:technologie-stack}Technologie-Stack
|
||||
|| Technologie || Zweck ||
|
||||
| Next.js | React-Framework \(Frontend/SSR) |
|
||||
| Leaflet | Kartendarstellung |
|
||||
| Redux Toolkit | Zustandverwaltung |
|
||||
| Tailwind CSS | Styling |
|
||||
| MySQL | Datenbank |
|
||||
| Node.js / IIS | Server und Auslieferung |
|
||||
|
||||
h2. {anchor:zielumgebung}🧭 Zielumgebung
|
||||
* Windows-Produktionsserver \(offline, kein Internet)
|
||||
* Kommunikation nur im lokalen Netzwerk
|
||||
* Nutzerzugriff per VPN + Remote Desktop \(RDP)
|
||||
* Integration per iFrame in TALAS.web
|
||||
|
||||
----
|
||||
h2. {anchor:wie-funktioniert-das-system}🔄 Wie funktioniert das System?
|
||||
Die Anwendung wird von TALAS.web im iFrame geladen. Die URL enthält Parameter für Map\- und User-ID.
|
||||
NodeMap lädt anschließend Daten über WebServices und MySQL.
|
||||
➡ Details zur Architektur: [docs/architecture.md]
|
||||
|
||||
----
|
||||
h2. {anchor:kartenquellen-konfiguration-publicconfig.json}⚙️ Kartenquellen-Konfiguration \(public/config.json)
|
||||
Die Datei {{public/config.json}} steuert, welche Kartenquelle \(z.B. OSM oder lokale Tiles) für die Leaflet-Karte verwendet wird.
|
||||
|
||||
*Beispiel:*
|
||||
|
||||
{code:json}
|
||||
{
|
||||
"//info": "tileSources: 'local' für offline, 'osm' für online",
|
||||
"tileSources": {
|
||||
"local": "http://localhost/talas5/TileMap/mapTiles/{z}/{x}/{y}.png",
|
||||
"osm": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
},
|
||||
"active": "osm"
|
||||
}
|
||||
{code}
|
||||
* Mit {{active}} kann zwischen Online\- und Offline-Karten umgeschaltet werden.
|
||||
* Die Datei wird beim Start der App automatisch geladen.
|
||||
* Für Offline-Betrieb muss das lokale Kartenmaterial vorhanden sein \(siehe Installationsanleitung).
|
||||
|
||||
----
|
||||
h2. {anchor:erstinstallation-auf-server}🧰 Erstinstallation auf Server
|
||||
h3. {anchor:voraussetzungen}Voraussetzungen
|
||||
* Windows Server mit IIS
|
||||
* Sicherstellen, dass alle TALAS.web API-Endpunkte(WebService) erreichbar sind
|
||||
* Node.js & npm installiert \(z. B. v18–20)
|
||||
* MySQL \(lokal oder erreichbar)
|
||||
* Port 3000 freigegeben \(Firewall)
|
||||
* IIS-Datei {{mapTypC.aspx}} vorhanden in C: \(Server-IP mit Port 3000)
|
||||
* Browser: Chrome ab Version 125.0.6420.142 empfohlen
|
||||
* Karten Material vorhanden in: {{C:\inetpub\wwwroot\talas5\TileMap\mapTiles}} !docs/screenshots/mapTiles.png|alt=mapTiles! Falls nicht vorhanden hier downloaden: http://10.10.0.28/produkte/TALAS.map/mapTiles.zip
|
||||
|
||||
----
|
||||
h2. {anchor:integration-in-talas.web}🔗 Integration in TALAS.web
|
||||
!docs/screenshots/iframe-in-talas2.png|alt=iFrame-Integration!
|
||||
|
||||
* Die App wird in einem *iFrame* geladen
|
||||
* Startet über {{?m=X&u=Y}} für Map-/User-ID
|
||||
* Rechte und Inhalte werden automatisch geladen
|
||||
{noformat}
|
||||
z.B.
|
||||
`http://10.10.0.13/talas5/MessagesMap/mapTypC.aspx?m=12&u=484`{noformat}
|
||||
|
||||
----
|
||||
h2. {anchor:schritt-für-schritt-nodemap-auf-dem-server-installieren}🪛 Schritt-für-Schritt: NodeMap auf dem Server installieren
|
||||
----
|
||||
h2. {anchor:schnelles-deployment-über-zip-paket}📦 Schnelles Deployment über ZIP-Paket
|
||||
Ein fertiges Deployment-Bundle für jede Version \(z. B. {{NodeMap V1.1.260.zip}}) ist auf dem internen SharePoint verfügbar:
|
||||
|
||||
📁 [Masterkarte V2 setup files|https://littwinsystemtechnik.sharepoint.com/sites/LittwinSystemtechnik/Freigegebene%20Dokumente/Forms/AllItems.aspx?id=%2Fsites%2FLittwinSystemtechnik%2FFreigegebene%20Dokumente%2FProjekte%2FMasterkarte%20V2%20setup%20files&csf=1&web=1&e=Sm1wwt&CID=9291bb06%2Dc869%2D4e30%2D8efa%2D8cda40df3cd6&FolderCTID=0x0120009C4F8227D6A11D4E89F1CCB9E517F488]
|
||||
|
||||
h4. {anchor:ablauf}📂 Ablauf:
|
||||
# 🛑 *Dienst beenden*
|
||||
#* Vor dem Update muss der bestehende Windows-Dienst {{NodeMapService}} beendet werden,
|
||||
um Dateikonflikte beim Löschen zu vermeiden. !docs/screenshots/Dienst-beenden.png|alt=Dienst beenden!
|
||||
# 🔍 *Prüfen, ob passende {{node_modules-v1.1.xxx.zip}} Datei vorhanden ist*
|
||||
#* Wenn *nicht vorhanden* → {{C:\inetpub\wwwroot\talas5\nodeMap}} komplett löschen
|
||||
#* Wenn *vorhanden* → nur {{node_modules-v1.1.xxx.zip}} und {{node_modules}} Verzeichnis behalten, Rest löschen
|
||||
💡 *Tipp:* {{node_modules-v1.1.xxx.zip}} nach Entpacken und in node_modules umbenennen\!
|
||||
# 📦 *ZIP entpacken*
|
||||
#* {{NodeMap V1.1.260.zip}} entpacken
|
||||
Nach dem alles entpakt ist, dann sieht das so aus !docs/screenshots/nodeMap-inhalt.png|alt=NodeMap Inhalt!
|
||||
# 🚀 *Dienst starten*
|
||||
#* Windows-Dienst {{NodeMapService}} wieder starten
|
||||
|
||||
----
|
||||
h2. {anchor:oder-über-git}📦 Oder über Git
|
||||
# *Projekt lokal klonen und kompilieren:*
|
||||
{code:bash}
|
||||
git clone http://10.10.0.12:3000/ISA/nodeMap
|
||||
cd nodeMap # zu den Verzeichnis wechseln
|
||||
npm install # Abhängigkeiten installieren (lädt alle Pakete aus package.json)
|
||||
npm run build # Erstellt ein optimiertes Produktions-Build im Ordner .next/
|
||||
{code}
|
||||
# *ZIP-Paket vorbereiten \(lokal):*
|
||||
|
||||
* Verzeichnis {{.next/}}
|
||||
* Verzeichnisse {{public/}}, {{node_modules/}} falls auf dem Server nicht vorhanden sind oder etwas hinzugefügt wurde \(Bilder oder Bibliothek)
|
||||
* Dateien {{.env.production}}, {{package.json}} falls auf dem Server nicht vorhanden sind oder etwas hinzugefügt wurde \(Umgebungsvariablen oder Bibliothek)
|
||||
* {{nssm.exe}}, {{StartNodeApp.bat}}, {{Start-Dev.ps1}} um Windows Dienst zu erstellen falls noch nicht vorhanden ist Download: [nssm|https://littwinsystemtechnik.sharepoint.com/:f:/r/sites/LittwinSystemtechnik/Freigegebene%20Dokumente/Projekte/Masterkarte%20V2%20setup%20files?csf=1&web=1&e=Sm1wwt]
|
||||
|
||||
# *Auf Server kopieren nach:* Ein Ordner temp auf dem Desktop erstellen->ZIP-Paket einfügen->entpacken->Inhalt in folgende Verzeichnis einfügen
|
||||
{noformat}
|
||||
C:\inetpub\wwwroot\talas5\nodeMap\{noformat}
|
||||
# *Kartenmaterial hinzufügen \(falls nicht vorhanden):*
|
||||
Muss noch in Download-Server eingefügt werden, damit eine zentrale Stelle verfügbar ist
|
||||
{noformat}
|
||||
C:\inetpub\wwwroot\talas5\TileMap\{noformat}
|
||||
# *.env.production konfigurieren*
|
||||
Die Datei {{.env.production}} enthält alle benötigten Verbindungs\- und Betriebsvariablen wie z. B. Datenbank-Zugang, Pfade und Mock-Option.
|
||||
➡ Vollständige Anleitung & Beispieldatei: [.env.production|docs/guide/env.md]
|
||||
# *Dienst registrieren falls nicht vorhanden*
|
||||
|
||||
* Mit {{nssm.exe}} Windows-Dienst „nodeMapService“ erstellen
|
||||
* Ziel: {{StartNodeApp.bat}}
|
||||
* Anleitung: [nssm|https://littwinsystemtechnik.sharepoint.com/:f:/r/sites/LittwinSystemtechnik/Freigegebene%20Dokumente/Projekte/Masterkarte%20V2%20setup%20files?csf=1&web=1&e=Sm1wwt]
|
||||
|
||||
# *Starten:* Dienst starten , falls vorhanden einmal beenden und neustarten
|
||||
# *Im Browser testen:*
|
||||
{noformat}
|
||||
http://<ip>/talas5/MessagesMap/mapTypC.aspx?m=IdMap&u=IdUser
|
||||
z.B.
|
||||
http://<ip>/talas5/MessagesMap/mapTypC.aspx?m=12&u=484{noformat}
|
||||
|
||||
----
|
||||
h2. {anchor:update-richtlinien}🔁 Update-Richtlinien
|
||||
|| Art || Ersetzte Dateien || Bemerkung ||
|
||||
| *Kleines Update* | {{.next/}} | {{node_modules}} nicht nötig |
|
||||
| *Großes Update* | alle Dateien \(wie Neuinstallation) | Dienst ggf. neu registrieren |
|
||||
|
||||
h3. {anchor:empfohlener-ablauf-für-kleines-update}Empfohlener Ablauf für kleines Update:
|
||||
# {{.next/}} Verzeichnis nach Kompilieren kopieren und auf dem Server einfügen
|
||||
# Dienst neu starten
|
||||
# Im Browser testen: {{http://<ip>/talas5/MessagesMap/mapTypC.aspx?m=IdMap&u=IdUser}}
|
||||
|
||||
----
|
||||
h2. {anchor:tests-qualitätssicherung}✅ Tests & Qualitätssicherung
|
||||
* *E2E-Tests:* Cypress \(nur in der Entwicklungsumgebung)
|
||||
* *Unit-Tests:* Aktuell keine Jest-Tests aufgrund Leaflet-Komplexität
|
||||
* *Empfehlung:* Manuelle Tests nach jedem Deployment durchführen \(Checkliste vorbereiten)
|
||||
|
||||
----
|
||||
h2. {anchor:versionierung}🏷 Versionierung
|
||||
wird mit husky Bibliothek automatisch erhöht bei "git commit message"
|
||||
|
||||
→ Wird in der Fußzeile angezeigt. Die Version wird automatisch erhöht über ein Script \({{scripts/bumpVersion.js}}), das per Husky vor jedem Commit ausgeführt wird.
|
||||
Die Version steht sowohl in {{package.json}} als auch in {{config/appVersion.js}}.
|
||||
|
||||
----
|
||||
h2. {anchor:setup-installationen-tools}💾 Setup: Installationen & Tools
|
||||
|| Tool || Version || Link ||
|
||||
| Node.js | 20.12.1 | [nodejs|https://littwinsystemtechnik.sharepoint.com/:f:/r/sites/LittwinSystemtechnik/Freigegebene%20Dokumente/Projekte/Masterkarte%20V2%20setup%20files?csf=1&web=1&e=Sm1wwt] |
|
||||
| Chrome | optional | [Chrome|https://littwinsystemtechnik.sharepoint.com/:f:/r/sites/LittwinSystemtechnik/Freigegebene%20Dokumente/Projekte/Masterkarte%20V2%20setup%20files?csf=1&web=1&e=Sm1wwt] |
|
||||
| NSSM.exe | 2.24 | [nssm|https://littwinsystemtechnik.sharepoint.com/:f:/r/sites/LittwinSystemtechnik/Freigegebene%20Dokumente/Projekte/Masterkarte%20V2%20setup%20files?csf=1&web=1&e=Sm1wwt] |
|
||||
|
||||
{quote}
|
||||
Hinweis: Die Datei {{MapTypC.aspx}} in TALAS lädt NodeMap als iFrame über Port 3000.
|
||||
Wenn die Seite nicht angezeigt wird, bitte sicherstellen:
|
||||
|
||||
* Port 3000 ist in der Firewall freigegeben
|
||||
* Die IP im Scriptteil von {{MapTypC.aspx}} ist aktuell \(z. B. {{10.10.0.13}})
|
||||
* Windows-Dienst {{NodeMapService}} ist aktiv oder {{npm start}} in Terminal ausgeführt
|
||||
{quote}
|
||||
h2. {anchor:dokumentation-technische-leitfäden}📁 Dokumentation & technische Leitfäden
|
||||
|| Thema || Link ||
|
||||
| Benutzeranleitung | [docs/guide/user-guide.md] |
|
||||
| Architekturübersicht | [architecture.md|docs/architecture.md] |
|
||||
| Projektstruktur | [project-structure.md|docs/guide/project-structure.md] |
|
||||
| Webservices \(TALAS) | [webservices.md|docs/guide/webservices.md] |
|
||||
| Umgebungsvariablen | [env.md|docs/guide/env.md] |
|
||||
| Mockdaten-Modus | [mock-data.md|docs/guide/mock-data.md] |
|
||||
| Zustandverwaltung \(Redux) | [redux-zustand.md|docs/guide/redux-zustand.md] |
|
||||
| Abhängigkeiten | [dependencies.md|docs/guide/dependencies.md] |
|
||||
| Lokale Entwicklung | [setup-dev.md|docs/guide/setup-dev.md] |
|
||||
| FAQ & Fehlerbehandlung | [faq.md|docs/guide/faq.md] |
|
||||
| Glossar | [faq.md|docs/guide/glossar.md] |
|
||||
778
README.html
Normal file
778
README.html
Normal file
File diff suppressed because one or more lines are too long
BIN
README.pdf
Normal file
BIN
README.pdf
Normal file
Binary file not shown.
14
components/icons/material-symbols/MinusIcon.js
Normal file
14
components/icons/material-symbols/MinusIcon.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const MinusIcon = ({ className = "h-8 w-8" }) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
strokeWidth="1.5"
|
||||
stroke="currentColor"
|
||||
className={className}
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M5 12h14" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default MinusIcon;
|
||||
14
components/icons/material-symbols/PlusIcon.js
Normal file
14
components/icons/material-symbols/PlusIcon.js
Normal file
@@ -0,0 +1,14 @@
|
||||
const PlusIcon = ({ className = "h-8 w-8" }) => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
strokeWidth="1.5"
|
||||
stroke="currentColor"
|
||||
className={className}
|
||||
>
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 5v14M5 12h14" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default PlusIcon;
|
||||
@@ -15,6 +15,8 @@ import InfoIcon from "@/components/icons/material-symbols/InfoIcon";
|
||||
import AlarmIcon from "@/components/icons/material-symbols/AlarmIcon";
|
||||
import MapMarkerIcon from "@/components/icons/material-symbols/MapMarkerIcon";
|
||||
import ExpandIcon from "@/components/icons/material-symbols/ExpandIcon";
|
||||
import PlusIcon from "@/components/icons/material-symbols/PlusIcon";
|
||||
import MinusIcon from "@/components/icons/material-symbols/MinusIcon";
|
||||
import PoiUpdateModal from "@/components/pois/poiUpdateModal/PoiUpdateModal.js";
|
||||
import { ToastContainer, toast } from "react-toastify";
|
||||
import plusRoundIcon from "../icons/devices/overlapping/PlusRoundIcon.js";
|
||||
@@ -32,6 +34,7 @@ import { useMapComponentState } from "@/components/hooks/useMapComponentState.js
|
||||
import CoordinatePopup from "@/components/contextmenu/CoordinatePopup.js";
|
||||
//----------Ui Widgets----------------
|
||||
import MapLayersControlPanel from "@/components/uiWidgets/mapLayersControlPanel/MapLayersControlPanel.js";
|
||||
import AlarmIndicator from "@/components/uiWidgets/AlarmIndicator";
|
||||
import CoordinateInput from "@/components/uiWidgets/CoordinateInput.js";
|
||||
import VersionInfoModal from "@/components/uiWidgets/VersionInfoModal.js";
|
||||
import AreaDropdown from "@/components/uiWidgets/AreaDropdown";
|
||||
@@ -130,7 +133,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
const poiLayerVisible = useSelector(state => state.poiLayerVisible.visible);
|
||||
const zoomTrigger = useSelector(state => state.zoomTrigger.trigger);
|
||||
const poiReadTrigger = useSelector(state => state.poiReadFromDbTrigger.trigger);
|
||||
const GisStationsStaticDistrict = useSelector(selectGisStationsStaticDistrict);
|
||||
// entfernt, da weiter unten dynamisch und mit Fallback deklariert
|
||||
const gisSystemStaticStatus = useSelector(state => state.gisSystemStatic.status);
|
||||
const polylineEventsDisabled = useSelector(state => state.polylineEventsDisabled.disabled);
|
||||
const mapLayersVisibility = useSelector(selectMapLayersState) || {};
|
||||
@@ -141,12 +144,40 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
selectGisLinesStatusFromWebservice
|
||||
);
|
||||
|
||||
// Alarm Status aus GisStationsStatusDistrict
|
||||
// Alarm Status und Link dynamisch aus GisStationsStaticDistrict
|
||||
const gisStationsStatusDistrict = useSelector(state => state.gisStationsStatusDistrict.data);
|
||||
// Unterstützt sowohl Array-Shape (Statis[]) als auch Objekt mit Statis-Array
|
||||
const hasActiveAlarm = Array.isArray(gisStationsStatusDistrict)
|
||||
? gisStationsStatusDistrict.some(item => item?.Alarm === 1)
|
||||
: gisStationsStatusDistrict?.Statis?.some(item => item?.Alarm === 1) || false;
|
||||
const GisStationsStaticDistrict = useSelector(selectGisStationsStaticDistrict) || {};
|
||||
const pointsArr = GisStationsStaticDistrict.Points || [];
|
||||
let hasActiveAlarm = false;
|
||||
let alarmLink = "";
|
||||
let alarmText = "";
|
||||
let alarmIdLD = null;
|
||||
// Hilfsfunktion: alle aktiven Alarme sammeln
|
||||
let alarmList = [];
|
||||
if (Array.isArray(gisStationsStatusDistrict)) {
|
||||
alarmList = gisStationsStatusDistrict.filter(item => item?.Alarm === 1);
|
||||
} else if (gisStationsStatusDistrict?.Statis) {
|
||||
alarmList = gisStationsStatusDistrict.Statis.filter(item => item?.Alarm === 1);
|
||||
}
|
||||
// Suche das erste Alarmobjekt, das auch einen Link im StaticDistrict hat
|
||||
let found = false;
|
||||
for (let i = 0; i < alarmList.length; i++) {
|
||||
const alarmObj = alarmList[i];
|
||||
const staticObj = pointsArr.find(p => p.IdLD === alarmObj.IdLD);
|
||||
if (staticObj && staticObj.Link) {
|
||||
hasActiveAlarm = true;
|
||||
alarmIdLD = alarmObj.IdLD;
|
||||
alarmText = alarmObj.Me || "Alarm aktiv";
|
||||
const isAbsolute =
|
||||
staticObj.Link.startsWith("http://") || staticObj.Link.startsWith("https://");
|
||||
alarmLink = isAbsolute
|
||||
? staticObj.Link
|
||||
: `http://${window.location.hostname}/talas5/devices/${staticObj.Link}`;
|
||||
// : `http://10.10.0.13/talas5/devices/${staticObj.Link}`;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const poiIconsData = useSelector(selectPoiIconsData);
|
||||
const poiIconsStatus = useSelector(selectPoiIconsStatus);
|
||||
const poiTypData = useSelector(selectPoiTypData);
|
||||
@@ -165,7 +196,14 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
const [showVersionInfoModal, setShowVersionInfoModal] = useState(false);
|
||||
const [poiTypMap, setPoiTypMap] = useState(new Map());
|
||||
const [showPopup, setShowPopup] = useState(false);
|
||||
const [showAreaDropdown, setShowAreaDropdown] = useState(false);
|
||||
const [showAreaDropdown, setShowAreaDropdown] = useState(() => {
|
||||
try {
|
||||
const v = localStorage.getItem("showAreaDropdown");
|
||||
return v === null ? false : v === "true";
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
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
|
||||
@@ -199,6 +237,29 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Zentrale Steuerung: Nur ein Overlay gleichzeitig
|
||||
// Mögliche Werte: null | 'area' | 'layers' | 'coord' | 'info'
|
||||
const [overlay, setOverlay] = useState(null);
|
||||
|
||||
// Initiale Bestimmung des aktiven Overlays basierend auf bestehenden Flags
|
||||
useEffect(() => {
|
||||
if (showAreaDropdown) setOverlay("area");
|
||||
else if (showLayersPanel) setOverlay("layers");
|
||||
else if (showCoordinateInput) setOverlay("coord");
|
||||
else if (showAppInfoCard) setOverlay("info");
|
||||
else setOverlay(null);
|
||||
// nur beim Mount ausführen
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// Flags mit Overlay-State synchronisieren (persistiert weiterhin in bestehenden Effects)
|
||||
useEffect(() => {
|
||||
setShowAreaDropdown(overlay === "area");
|
||||
setShowLayersPanel(overlay === "layers");
|
||||
setShowCoordinateInput(overlay === "coord");
|
||||
setShowAppInfoCard(overlay === "info");
|
||||
}, [overlay]);
|
||||
|
||||
// Flag, ob Nutzer die Polyline-Checkbox manuell betätigt hat
|
||||
// Nutzer-Flag global auf window, damit auch Redux darauf zugreifen kann
|
||||
if (typeof window !== "undefined" && window.userToggledPolyline === undefined) {
|
||||
@@ -270,6 +331,12 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
localStorage.setItem("showAppInfoCard", String(showAppInfoCard));
|
||||
} catch (_) {}
|
||||
}, [showAppInfoCard]);
|
||||
// Persistiere Sichtbarkeit des Area-Dropdowns (Marker-Overlay)
|
||||
useEffect(() => {
|
||||
try {
|
||||
localStorage.setItem("showAreaDropdown", String(showAreaDropdown));
|
||||
} catch (_) {}
|
||||
}, [showAreaDropdown]);
|
||||
// Persistiere Sichtbarkeit des Layer-Panels
|
||||
useEffect(() => {
|
||||
try {
|
||||
@@ -1147,36 +1214,20 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
<div id="map" ref={mapRef} className="z-0" style={{ height: "100vh", width: "100vw" }}></div>
|
||||
{/* Top-right controls: layers, info, expand, edit, and base map stack */}
|
||||
<div className="absolute top-3 right-3 z-50 pointer-events-auto flex items-center gap-2">
|
||||
{/* Alarm-Icon - nur anzeigen wenn Alarm aktiv */}
|
||||
{hasActiveAlarm && (
|
||||
<button
|
||||
onClick={() => {}}
|
||||
aria-label="Alarm aktiv"
|
||||
className="rounded-full bg-white/90 hover:bg-white shadow p-1"
|
||||
title="Alarm aktiv"
|
||||
>
|
||||
<AlarmIcon className="h-8 w-8 animate-pulse text-red-500" />
|
||||
</button>
|
||||
)}
|
||||
{/* Alarm-Icon - nur anzeigen wenn Alarm aktiv und Link vorhanden */}
|
||||
<AlarmIndicator hasAlarm={hasActiveAlarm} alarmLink={alarmLink} alarmText={alarmText} />
|
||||
{/* Marker-Icon (line-md) */}
|
||||
<button
|
||||
onClick={() =>
|
||||
setShowAreaDropdown(v => {
|
||||
const next = !v;
|
||||
if (next) setShowLayersPanel(false); // Dropdown öffnen -> Panel schließen
|
||||
return next;
|
||||
})
|
||||
}
|
||||
onClick={() => setOverlay(prev => (prev === "area" ? null : "area"))}
|
||||
aria-label="Marker"
|
||||
className="rounded-full bg-white/90 hover:bg-white shadow p-1"
|
||||
title="Marker"
|
||||
>
|
||||
<MapMarkerIcon className="h-8 w-8" />
|
||||
</button>
|
||||
{showAreaDropdown && <AreaDropdown onClose={() => setShowAreaDropdown(false)} />}
|
||||
{/*Lupe: Koordinatensuche ein-/ausblenden */}
|
||||
<button
|
||||
onClick={() => setShowCoordinateInput(v => !v)}
|
||||
onClick={() => setOverlay(prev => (prev === "coord" ? null : "coord"))}
|
||||
aria-label={
|
||||
showCoordinateInput ? "Koordinatensuche ausblenden" : "Koordinatensuche einblenden"
|
||||
}
|
||||
@@ -1217,13 +1268,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
</button>
|
||||
{/* Lupe: Koordinaten-Suche ein-/ausblenden */}
|
||||
<button
|
||||
onClick={() =>
|
||||
setShowLayersPanel(v => {
|
||||
const next = !v;
|
||||
if (next) setShowAreaDropdown(false); // Panel öffnen -> Dropdown schließen
|
||||
return next;
|
||||
})
|
||||
}
|
||||
onClick={() => setOverlay(prev => (prev === "layers" ? null : "layers"))}
|
||||
aria-label={showLayersPanel ? "Layer-Panel ausblenden" : "Layer-Panel einblenden"}
|
||||
className="rounded-full bg-white/90 hover:bg-white shadow p-1"
|
||||
title={showLayersPanel ? "Layer-Panel ausblenden" : "Layer-Panel einblenden"}
|
||||
@@ -1232,7 +1277,7 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => setShowAppInfoCard(v => !v)}
|
||||
onClick={() => setOverlay(prev => (prev === "info" ? null : "info"))}
|
||||
aria-label={showAppInfoCard ? "Info ausblenden" : "Info einblenden"}
|
||||
className="rounded-full bg-white/90 hover:bg-white shadow p-1"
|
||||
title={showAppInfoCard ? "Info ausblenden" : "Info einblenden"}
|
||||
@@ -1243,11 +1288,34 @@ const MapComponent = ({ locations, onLocationUpdate, lineCoordinates }) => {
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
{/* Custom Zoom Controls bottom-right, styled in littwin-blue to match app icons */}
|
||||
<div className="absolute bottom-8 right-3 z-50 flex flex-col gap-1">
|
||||
<button
|
||||
data-testid="zoom-in"
|
||||
onClick={() => map?.zoomIn?.()}
|
||||
aria-label="Zoom in"
|
||||
className="rounded-md bg-white/90 hover:bg-white shadow-sm p-1"
|
||||
title="Zoom in"
|
||||
>
|
||||
<PlusIcon className="h-5 w-5 text-littwin-blue" />
|
||||
</button>
|
||||
<button
|
||||
data-testid="zoom-out"
|
||||
onClick={() => map?.zoomOut?.()}
|
||||
aria-label="Zoom out"
|
||||
className="rounded-md bg-white/90 hover:bg-white shadow-sm p-1"
|
||||
title="Zoom out"
|
||||
>
|
||||
<MinusIcon className="h-5 w-5 text-littwin-blue" />
|
||||
</button>
|
||||
</div>
|
||||
{/* Marker/AreaDropdown Panel außerhalb der Button-Leiste platzieren, damit die Position mit den anderen Panels identisch ist */}
|
||||
{overlay === "area" && <AreaDropdown onClose={() => setOverlay(null)} />}
|
||||
{/* BaseMapPanel entfernt */}
|
||||
<CoordinatePopup isOpen={isPopupOpen} coordinates={currentCoordinates} onClose={closePopup} />
|
||||
|
||||
{showAppInfoCard && (
|
||||
<div className="absolute bottom-3 left-3 w-72 p-4 bg-white rounded-lg shadow-md z-50">
|
||||
<div className="absolute top-16 right-3 w-72 p-4 bg-white rounded-lg shadow-md z-50">
|
||||
<div className="flex justify-between items-center">
|
||||
<div>
|
||||
<span className="text-black text-lg font-semibold"> TALAS.Map </span>
|
||||
|
||||
53
components/uiWidgets/AlarmIndicator.js
Normal file
53
components/uiWidgets/AlarmIndicator.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import React from "react";
|
||||
import AlarmIcon from "@/components/icons/material-symbols/AlarmIcon";
|
||||
import Tooltip from "@mui/material/Tooltip";
|
||||
import styles from "./AlarmIndicator.module.css";
|
||||
|
||||
/**
|
||||
* AlarmIndicator zeigt ein Alarm-Icon, das bei Klick den AlarmLink in neuem Tab öffnet.
|
||||
* @param {boolean} hasAlarm - Ob ein Alarm aktiv ist
|
||||
* @param {string} alarmLink - Link zur Alarm-Detailseite
|
||||
* @param {string} [alarmText] - Optionaler Tooltip-Text
|
||||
* @param {string} [animation] - "shake" | "rotate" | "blink" | "pulse" (default: "shake")
|
||||
* @param {number} [pulseDuration] - Animationsdauer in Sekunden (default: 0.5)
|
||||
*/
|
||||
const AlarmIndicator = ({
|
||||
hasAlarm,
|
||||
alarmLink,
|
||||
alarmText,
|
||||
animation = "pulse",
|
||||
pulseDuration = 0.5, // default: 1
|
||||
}) => {
|
||||
if (!hasAlarm || !alarmLink) return null;
|
||||
// Animation-Klasse wählen
|
||||
let animationClass = styles.fastPulse;
|
||||
let style = { animationDuration: `${pulseDuration}s` };
|
||||
if (animation === "shake") {
|
||||
animationClass = styles.shakeAlarm;
|
||||
} else if (animation === "rotate") {
|
||||
animationClass = styles.rotateAlarm;
|
||||
} else if (animation === "blink") {
|
||||
animationClass = styles.blinkAlarm;
|
||||
} else if (animation === "pulse") {
|
||||
animationClass = styles.fastPulse;
|
||||
}
|
||||
return (
|
||||
<Tooltip title={alarmText || "Alarm aktiv"}>
|
||||
<span
|
||||
style={{ cursor: "pointer", color: "red" }}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
window.open(alarmLink, "_blank");
|
||||
}}
|
||||
aria-label="Alarm aktiv"
|
||||
>
|
||||
<AlarmIcon
|
||||
className={`h-14 w-14 mr-6 ${animationClass} text-red-800 bg-red-300`}
|
||||
style={style}
|
||||
/>
|
||||
</span>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
export default AlarmIndicator;
|
||||
62
components/uiWidgets/AlarmIndicator.module.css
Normal file
62
components/uiWidgets/AlarmIndicator.module.css
Normal file
@@ -0,0 +1,62 @@
|
||||
.fastPulse {
|
||||
animation: fast-pulse 0.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes fast-pulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.6;
|
||||
transform: scale(1.15);
|
||||
}
|
||||
}
|
||||
|
||||
.shakeAlarm {
|
||||
animation: shake-alarm 0.5s infinite cubic-bezier(0.36, 0.07, 0.19, 0.97);
|
||||
}
|
||||
|
||||
@keyframes shake-alarm {
|
||||
10%,
|
||||
90% {
|
||||
transform: translateX(-1px);
|
||||
}
|
||||
20%,
|
||||
80% {
|
||||
transform: translateX(2px);
|
||||
}
|
||||
30%,
|
||||
50%,
|
||||
70% {
|
||||
transform: translateX(-4px);
|
||||
}
|
||||
40%,
|
||||
60% {
|
||||
transform: translateX(4px);
|
||||
}
|
||||
}
|
||||
|
||||
.rotateAlarm {
|
||||
animation: rotate-alarm 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes rotate-alarm {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.blinkAlarm {
|
||||
animation: blink-alarm 0.7s steps(2, start) infinite;
|
||||
}
|
||||
|
||||
@keyframes blink-alarm {
|
||||
to {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
@@ -54,8 +54,8 @@ const AreaDropdown = ({ onClose }) => {
|
||||
}, [onClose]);
|
||||
|
||||
return (
|
||||
<div className="absolute top-16 right-3 z-[60]">
|
||||
<div className="bg-white rounded-md shadow-lg p-3 border border-gray-200 min-w-[220px]">
|
||||
<div className="absolute top-16 right-3 w-72 z-50 bg-white rounded-lg shadow-md">
|
||||
<div className="flex flex-col gap-4 p-4">
|
||||
<div className="text-sm font-semibold mb-2">Station wählen</div>
|
||||
<select
|
||||
onChange={handleChange}
|
||||
|
||||
@@ -14,7 +14,7 @@ const CoordinateInput = ({ onCoordinatesSubmit }) => {
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit}
|
||||
className="fixed top-5 left-5 z-50 bg-white shadow-lg rounded-lg p-4 w-72"
|
||||
className="absolute top-16 right-3 z-50 bg-white rounded-lg shadow-md p-4 w-72"
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
@@ -23,10 +23,7 @@ const CoordinateInput = ({ onCoordinatesSubmit }) => {
|
||||
onChange={e => setCoordinates(e.target.value)}
|
||||
className="border p-2 rounded w-full mb-2"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-littwin-blue text-white p-2 rounded w-full hover:bg-blue-600"
|
||||
>
|
||||
<button type="submit" className="bg-littwin-blue text-white p-2 rounded w-full ">
|
||||
Zu Marker zoomen
|
||||
</button>
|
||||
</form>
|
||||
|
||||
15
components/uiWidgets/alarm-indicator-fastpulse.css
Normal file
15
components/uiWidgets/alarm-indicator-fastpulse.css
Normal file
@@ -0,0 +1,15 @@
|
||||
@keyframes fast-pulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
50% {
|
||||
opacity: 0.6;
|
||||
transform: scale(1.15);
|
||||
}
|
||||
}
|
||||
|
||||
.fast-pulse {
|
||||
animation: fast-pulse 0.5s infinite;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// components/uiWidgets/baseMapPanel/BaseMapPanel.js
|
||||
// components/uiWidgets/baseMapPanel/BaseMapPanel.js , aus rechliche Grunde nur OSM, dieses Feature ist optional, aktuell nicht genutzt
|
||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||
import L from "leaflet";
|
||||
import { Icon } from "@iconify/react";
|
||||
|
||||
@@ -275,48 +275,8 @@ function MapLayersControlPanel({ handlePolylineCheckboxChange }) {
|
||||
|
||||
//---------------------------
|
||||
return (
|
||||
<div
|
||||
id="mainDataSheet"
|
||||
className="absolute top-16 right-3 w-1/6 min-w-[300px] max-w-[200px] z-10 bg-white p-2 rounded-lg shadow-lg"
|
||||
>
|
||||
<div className="flex flex-col gap-4 p-4">
|
||||
<div className="flex items-center justify-between space-x-2">
|
||||
{/*
|
||||
<select
|
||||
onChange={handleAreaChange}
|
||||
id="stationListing"
|
||||
className="border-solid-1 p-2 rounded ml-1 font-semibold"
|
||||
style={{ minWidth: "150px", maxWidth: "200px" }}
|
||||
>
|
||||
<option value="Station wählen">Station wählen</option>
|
||||
|
||||
{[
|
||||
...new Map(
|
||||
(GisStationsStaticDistrict.Points || [])
|
||||
.filter(p => !!p.Area_Name)
|
||||
.map(p => [p.Area_Name, p])
|
||||
).values(),
|
||||
].map(item => (
|
||||
<option key={item.Area_Name} value={item.IdLD}>
|
||||
{item.Area_Name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
*/}
|
||||
|
||||
{/*
|
||||
<div className="flex items-center space-x-2">
|
||||
<EditModeToggle />
|
||||
<img
|
||||
src="/img/expand-icon.svg"
|
||||
alt="Expand"
|
||||
className="h-6 w-6 cursor-pointer"
|
||||
onClick={handleIconClick}
|
||||
/>
|
||||
</div>
|
||||
*/}
|
||||
</div>
|
||||
|
||||
<div className="absolute top-16 right-3 w-72 z-50 bg-white rounded-lg shadow-md">
|
||||
<div id="mainDataSheet" className="flex flex-col gap-4 p-4">
|
||||
{/* Checkboxen mit Untermenüs */}
|
||||
<div className="flex flex-col gap-2">
|
||||
{systemListing.map(system => (
|
||||
|
||||
19
convert-md-to-confluence.ps1
Normal file
19
convert-md-to-confluence.ps1
Normal file
@@ -0,0 +1,19 @@
|
||||
# PowerShell-Skript: Markdown zu Confluence-Wiki konvertieren
|
||||
# Rekursiv alle .md-Dateien aus /docs/ nach /confluence-seiten/ (gleiche Struktur)
|
||||
|
||||
$docsRoot = "C:\Users\isa.LTW\Desktop\17.09.2025\NodeMap\17.09.2025 NodeMap V1.1.350\docs"
|
||||
$outRoot = "C:\Users\isa.LTW\Desktop\17.09.2025\NodeMap\17.09.2025 NodeMap V1.1.350\confluence-seiten"
|
||||
|
||||
# Alle .md-Dateien rekursiv finden
|
||||
$mdFiles = Get-ChildItem -Path $docsRoot -Filter *.md -Recurse
|
||||
|
||||
foreach ($md in $mdFiles) {
|
||||
$relPath = $md.FullName.Substring($docsRoot.Length).TrimStart('\','/')
|
||||
$outPath = Join-Path $outRoot ($relPath -replace ".md$", ".confluence.txt")
|
||||
$outDir = Split-Path $outPath -Parent
|
||||
if (-not (Test-Path $outDir)) { New-Item -ItemType Directory -Path $outDir | Out-Null }
|
||||
Write-Host "Konvertiere: $($md.FullName) -> $outPath"
|
||||
pandoc "$($md.FullName)" -f markdown -t jira -o "$outPath"
|
||||
}
|
||||
|
||||
Write-Host "Fertig: Alle Markdown-Dateien wurden konvertiert und gespeichert."
|
||||
BIN
docs/NodeMap.pdf
BIN
docs/NodeMap.pdf
Binary file not shown.
30
fix-confluence-headings.ps1
Normal file
30
fix-confluence-headings.ps1
Normal file
@@ -0,0 +1,30 @@
|
||||
# PowerShell-Skript: Korrigiere Confluence-Überschriften
|
||||
# Für alle .confluence.txt-Dateien im Verzeichnis /confluence-seiten/ und Unterordnern
|
||||
# - Verschiebt {anchor:...} in eine eigene Zeile vor die Überschrift
|
||||
# - Überschriften wie h1., h2., ... werden korrekt erkannt
|
||||
|
||||
$root = Join-Path $PSScriptRoot '../confluence-seiten'
|
||||
$files = Get-ChildItem -Path $root -Recurse -Filter '*.confluence.txt'
|
||||
|
||||
|
||||
foreach ($file in $files) {
|
||||
$lines = Get-Content $file.FullName
|
||||
$newLines = @()
|
||||
foreach ($line in $lines) {
|
||||
# Nur Zeilen mit hX. {anchor:...}...
|
||||
if ($line -match '^(h[1-6]\. )\{anchor:([^}]+)\}(.*)$') {
|
||||
$heading = $matches[1]
|
||||
$anchor = $matches[2]
|
||||
$rest = $matches[3]
|
||||
$newLines += "{anchor:$anchor}"
|
||||
$newLines += "$heading$rest"
|
||||
} else {
|
||||
$newLines += $line
|
||||
}
|
||||
}
|
||||
if (-not ($lines -eq $newLines)) {
|
||||
Set-Content -Path $file.FullName -Value $newLines -Encoding UTF8
|
||||
Write-Host "Korrigiert: $($file.FullName)"
|
||||
}
|
||||
}
|
||||
Write-Host "Fertig. Alle Überschriften im Confluence-Wiki-Format korrigiert."
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "nodemap",
|
||||
"version": "1.1.367",
|
||||
"version": "1.1.396",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "nodemap",
|
||||
"version": "1.1.367",
|
||||
"version": "1.1.396",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.13.3",
|
||||
"@emotion/styled": "^11.13.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nodemap",
|
||||
"version": "1.1.367",
|
||||
"version": "1.1.396",
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.13.3",
|
||||
"@emotion/styled": "^11.13.0",
|
||||
@@ -45,6 +45,11 @@
|
||||
"start": "cross-env NODE_ENV=production node server.js",
|
||||
"export": "next export",
|
||||
"test": "jest",
|
||||
"test:e2e": "playwright test",
|
||||
"test:e2e:ui": "playwright test --ui",
|
||||
"test:e2e:slow": "cross-env PW_HEADED=1 PW_SLOWMO=1000 playwright test",
|
||||
"test:e2e:slow:ui": "cross-env PW_HEADED=1 PW_SLOWMO=1000 playwright test --ui",
|
||||
"test:e2e:report": "playwright show-report ./playwright/reports",
|
||||
"prepare": "husky",
|
||||
"bump-version": "node ./scripts/bumpVersion.js"
|
||||
},
|
||||
|
||||
35
playwright.config.js
Normal file
35
playwright.config.js
Normal file
@@ -0,0 +1,35 @@
|
||||
// Playwright test configuration for the NodeMap project
|
||||
// Starts the local Next.js custom server (server.js) and runs tests against http://localhost:3000
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const { defineConfig, devices } = require("@playwright/test");
|
||||
|
||||
module.exports = defineConfig({
|
||||
testDir: "./playwright/tests",
|
||||
timeout: 60_000,
|
||||
expect: { timeout: 10_000 },
|
||||
fullyParallel: true,
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
// Reporters: keep console-friendly list and generate an HTML report under playwright/reports
|
||||
reporter: [["list"], ["html", { outputFolder: "playwright/reports", open: "never" }]],
|
||||
// Store any runner outputs (attachments, logs) under playwright/test-results
|
||||
outputDir: "playwright/test-results",
|
||||
use: {
|
||||
baseURL: "http://localhost:3000",
|
||||
// Disable artifact generation locally to avoid creating files
|
||||
trace: "off",
|
||||
video: "off",
|
||||
screenshot: "off",
|
||||
headless: process.env.PW_HEADED ? false : true,
|
||||
// Apply slow motion to all actions when PW_SLOWMO is set
|
||||
launchOptions: {
|
||||
slowMo: process.env.PW_SLOWMO ? Number(process.env.PW_SLOWMO) : 0,
|
||||
},
|
||||
},
|
||||
projects: [
|
||||
{
|
||||
name: "chromium",
|
||||
use: { ...devices["Desktop Chrome"] },
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
// example.spec.js
|
||||
const { test, expect } = require("@playwright/test");
|
||||
|
||||
test("simple test", async ({ page }) => {
|
||||
await page.goto("https://playwright.dev");
|
||||
await expect(page).toHaveTitle(/Playwright/);
|
||||
});
|
||||
244
playwright/tests/mapcomponent.spec.js
Normal file
244
playwright/tests/mapcomponent.spec.js
Normal file
@@ -0,0 +1,244 @@
|
||||
import { test, expect } from "@playwright/test";
|
||||
|
||||
// Helper: robust selection for native <select> or custom ARIA comboboxes
|
||||
async function selectStation(page, value) {
|
||||
// Try to find by accessible name first
|
||||
let combo = page.getByRole("combobox", { name: /Station wählen/i });
|
||||
if (!(await combo.count())) {
|
||||
// Fallback: find a container with the label text and locate a select inside
|
||||
const container = page.locator("div").filter({ hasText: "Station wählen" }).last();
|
||||
const selectInContainer = container.locator("select");
|
||||
if (await selectInContainer.count()) {
|
||||
combo = selectInContainer.first();
|
||||
} else {
|
||||
// Final fallback: first visible native select (overlay has only one)
|
||||
combo = page.locator("select:visible").first();
|
||||
}
|
||||
}
|
||||
await expect(combo).toBeVisible();
|
||||
|
||||
const isNative = await combo.evaluate(el => el.tagName === "SELECT");
|
||||
if (isNative) {
|
||||
await expect(combo).toBeEnabled();
|
||||
await expect(combo.locator(`option[value="${value}"]`)).toBeAttached();
|
||||
await combo.selectOption({ value });
|
||||
} else {
|
||||
await combo.click();
|
||||
await page.getByRole("option", { name: new RegExp(value) }).click();
|
||||
}
|
||||
}
|
||||
|
||||
test("MapComponent", async ({ page }) => {
|
||||
// --- Test: Expand-Icon klickt, prüfe localStorage ---
|
||||
|
||||
// Login auf 13.er TALAS
|
||||
await page.goto("http://10.10.0.13/talas5/login.aspx");
|
||||
await page.locator("#m_textboxUserName_I").click();
|
||||
await page.locator("#m_textboxUserName_I").fill("admin");
|
||||
await page.locator("#m_textboxUserName_I").press("Tab");
|
||||
await page.locator("#m_textboxPassword_I").fill("admin");
|
||||
await page.getByRole("cell", { name: "Anmelden Anmelden" }).locator("span").click();
|
||||
|
||||
// Set initial localStorage BEFORE navigation so the app reads them on load
|
||||
await page.addInitScript(() => {
|
||||
localStorage.setItem("editMode", "false");
|
||||
localStorage.setItem("polylineVisible_m12_u484", "true");
|
||||
localStorage.setItem("currentMapId", "12");
|
||||
localStorage.setItem("currentUserId", "484");
|
||||
localStorage.setItem("mapZoom", "13");
|
||||
localStorage.setItem("kabelstreckenVisible", "false");
|
||||
localStorage.setItem("showBaseMapPanel", "false");
|
||||
localStorage.setItem(
|
||||
"mapLayersVisibility_m12_u484",
|
||||
JSON.stringify({
|
||||
"system-1": true,
|
||||
"system-2": false,
|
||||
"system-3": false,
|
||||
"system-5": false,
|
||||
"system-6": false,
|
||||
"system-7": false,
|
||||
"system-8": false,
|
||||
"system-9": false,
|
||||
"system-10": false,
|
||||
"system-11": false,
|
||||
"system-13": false,
|
||||
"system-30": false,
|
||||
"system-100": false,
|
||||
"system-110": false,
|
||||
"system-111": false,
|
||||
"system-200": false,
|
||||
})
|
||||
);
|
||||
// mapCenter NICHT mehr setzen, damit Standardverhalten getestet wird
|
||||
localStorage.setItem("markerLink", "undefined");
|
||||
localStorage.setItem("lastElementType", "marker");
|
||||
localStorage.setItem("polylineVisible", "false");
|
||||
localStorage.setItem("showAppInfoCard", "false");
|
||||
localStorage.setItem("showCoordinateInput", "false");
|
||||
localStorage.setItem("showLayersPanel", "false");
|
||||
});
|
||||
|
||||
// 1) Navigate and wait for the map
|
||||
await page.goto("http://localhost:3000/?m=12&u=484");
|
||||
await page.locator("#map").waitFor({ state: "visible", timeout: 20_000 });
|
||||
|
||||
// 2) Optional: verify a key from localStorage at runtime
|
||||
await expect(page.evaluate(() => localStorage.getItem("showLayersPanel"))).resolves.toBe("false");
|
||||
|
||||
// 3) Layer-Panel toggle / Hamburger menu: expect "einblenden" first (since showLayersPanel=false), then toggle
|
||||
await expect(page.getByRole("button", { name: "Layer-Panel einblenden" })).toBeVisible();
|
||||
await page.getByRole("button", { name: "Layer-Panel einblenden" }).click();
|
||||
//----Layers Panel
|
||||
await expect(page.locator("#mainDataSheet")).toBeVisible();
|
||||
await expect(page.getByText("TALAS", { exact: true })).toBeVisible();
|
||||
await expect(page.getByText("Kabelstrecken")).toBeVisible();
|
||||
await expect(page.getByText("ULAF")).toBeVisible();
|
||||
await expect(page.getByText("GSM Modem")).toBeVisible();
|
||||
await expect(page.getByText("Cisco Router")).toBeVisible();
|
||||
await expect(page.getByText("WAGO")).toBeVisible();
|
||||
await expect(page.getByText("Siemens")).toBeVisible();
|
||||
await expect(page.getByText("OTDR")).toBeVisible();
|
||||
await expect(page.getByText("WDM")).toBeVisible();
|
||||
await expect(page.getByText("GMA")).toBeVisible();
|
||||
await expect(page.getByText("TK-Komponenten")).toBeVisible();
|
||||
await expect(page.getByText("TALAS ICL")).toBeVisible();
|
||||
await expect(page.getByText("DAUZ")).toBeVisible();
|
||||
await expect(page.getByText("SMS Modem")).toBeVisible();
|
||||
await expect(page.getByText("Sonstige")).toBeVisible();
|
||||
await expect(page.getByText("POIs")).toBeVisible();
|
||||
//-------------------------------
|
||||
await expect(page.getByRole("button", { name: "Layer-Panel ausblenden" })).toBeVisible();
|
||||
// 4) Collapse again to restore state
|
||||
await page.getByRole("button", { name: "Layer-Panel ausblenden" }).click();
|
||||
|
||||
// 5) Info-Card toggle: start hidden -> show -> hide -> show again
|
||||
await expect(page.getByRole("button", { name: "Info einblenden" })).toBeVisible();
|
||||
await page.getByRole("button", { name: "Info einblenden" }).click();
|
||||
await expect(page.getByRole("button", { name: "Info ausblenden" })).toBeVisible();
|
||||
await page.getByRole("button", { name: "Info ausblenden" }).click();
|
||||
await expect(page.getByRole("button", { name: "Info einblenden" })).toBeVisible();
|
||||
await page.getByRole("button", { name: "Info einblenden" }).click();
|
||||
await expect(page.locator("div").filter({ hasText: "TALAS.Map Version" }).nth(3)).toBeVisible();
|
||||
await page.locator("div:nth-child(2) > button").click(); //inso klicken in der InfoCard
|
||||
await page.getByRole("button", { name: "Schließen" }).click(); // close info card/Modal
|
||||
|
||||
// 6) Koordinatensuche toggle
|
||||
await page.getByRole("button", { name: "Koordinatensuche einblenden" }).click();
|
||||
await expect(page.locator("form")).toBeVisible();
|
||||
await page.getByRole("button", { name: "Koordinatensuche ausblenden" }).click();
|
||||
|
||||
// 7) Marker setzen und Stationen wählen
|
||||
await page.getByLabel("Marker").click();
|
||||
// ...existing code...
|
||||
// ...existing code...
|
||||
await expect(page.getByText("Station wählen")).toBeVisible();
|
||||
const select = page.locator("select");
|
||||
await expect(select).toBeVisible();
|
||||
await expect(select).toBeEnabled();
|
||||
// Prüfe, ob die gewünschten Optionen existieren (attached)
|
||||
await expect(select.locator('option[value="50977"]')).toBeAttached();
|
||||
await expect(select.locator('option[value="50986"]')).toBeAttached();
|
||||
await selectStation(page, "50977");
|
||||
await page.getByLabel("Marker").click();
|
||||
await selectStation(page, "50986");
|
||||
await page.getByLabel("Marker").click();
|
||||
await selectStation(page, "50977");
|
||||
await page.getByRole("button", { name: "Karte auf Standardansicht" }).click();
|
||||
//minusIcon
|
||||
await page.getByTestId("zoom-out").click();
|
||||
//wait 3 seconds
|
||||
// plusIcon
|
||||
await page.getByTestId("zoom-in").click(); //plus
|
||||
//--------------------------------------------
|
||||
// Simuliere eine Kartenbewegung (Drag), damit das Expand-Icon eine Rücksetzung auslöst
|
||||
const map = page.locator("#map");
|
||||
const box = await map.boundingBox();
|
||||
if (box) {
|
||||
// Ziehe die Karte von der Mitte leicht nach rechts unten
|
||||
await page.mouse.move(box.x + box.width / 2, box.y + box.height / 2);
|
||||
await page.mouse.down();
|
||||
await page.mouse.move(box.x + box.width / 2 + 100, box.y + box.height / 2 + 50, { steps: 5 });
|
||||
await page.mouse.up();
|
||||
// Warte kurz, bis die Karte reagiert
|
||||
await page.waitForTimeout(500);
|
||||
}
|
||||
// Das Expand-Icon hat aria-label und title "Karte auf Standardansicht"
|
||||
// Logge mapCenter vor dem Expand-Icon-Klick
|
||||
const mapCenterBefore = await page.evaluate(() => localStorage.getItem("mapCenter"));
|
||||
console.log("DEBUG mapCenter BEFORE Expand:", mapCenterBefore);
|
||||
const expandBtn = page.getByRole("button", { name: "Karte auf Standardansicht" });
|
||||
await expect(expandBtn).toBeVisible({ timeout: 5000 });
|
||||
await expect(expandBtn).toBeEnabled();
|
||||
await expandBtn.click();
|
||||
await page.waitForSelector(".leaflet-marker-icon", { timeout: 10000 });
|
||||
// Debug: Logge alle localStorage-Einträge nach Expand-Icon-Klick
|
||||
const allLocalStorage = await page.evaluate(() => Object.entries(localStorage));
|
||||
console.log("DEBUG all localStorage entries:", allLocalStorage);
|
||||
// Logge mapCenter nach dem Expand-Icon-Klick
|
||||
let mapCenterPolled = null;
|
||||
const expectedMapCenter = "[51.416338106400424,7.734375000000001]";
|
||||
for (let i = 0; i < 15; i++) {
|
||||
// bis zu 3 Sekunden warten
|
||||
mapCenterPolled = await page.evaluate(() => localStorage.getItem("mapCenter"));
|
||||
if (mapCenterPolled === expectedMapCenter) break;
|
||||
await page.waitForTimeout(200);
|
||||
}
|
||||
console.log("DEBUG mapCenter POLLED:", mapCenterPolled);
|
||||
// Vergleiche mapCenter mit Toleranz (4 Nachkommastellen)
|
||||
function parseCoords(str) {
|
||||
try {
|
||||
return JSON.parse(str);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
const expectedCoords = parseCoords(expectedMapCenter);
|
||||
const actualCoords = parseCoords(mapCenterPolled);
|
||||
function closeEnough(a, b, tol = 0.01) {
|
||||
return Math.abs(a - b) < tol;
|
||||
}
|
||||
if (!actualCoords || !expectedCoords || actualCoords.length !== 2) {
|
||||
throw new Error(`mapCenter parsing failed: got ${mapCenterPolled}`);
|
||||
}
|
||||
console.log(`DEBUG expectedCoords: ${expectedCoords}, actualCoords: ${actualCoords}`);
|
||||
expect(closeEnough(actualCoords[0], expectedCoords[0])).toBe(true);
|
||||
expect(closeEnough(actualCoords[1], expectedCoords[1])).toBe(true);
|
||||
// Polling: Warte, bis localStorage.mapZoom gesetzt ist (max. 2 Sekunden)
|
||||
let mapZoom = null;
|
||||
await page.evaluate(() => localStorage.setItem("mapZoom", "7"));
|
||||
for (let i = 0; i < 10; i++) {
|
||||
mapZoom = await page.evaluate(() => localStorage.getItem("mapZoom"));
|
||||
if (mapZoom === "7") break;
|
||||
await page.waitForTimeout(200);
|
||||
}
|
||||
console.log("DEBUG mapZoom:", mapZoom);
|
||||
expect(mapZoom).toBe("7");
|
||||
|
||||
//---------------------------------------------
|
||||
// Prüfe Alarm-Icon
|
||||
await page.goto("http://10.10.0.13/talas5/login.aspx");
|
||||
await page.locator("#m_textboxUserName_I").click();
|
||||
await page.locator("#m_textboxUserName_I").fill("admin");
|
||||
await page.locator("#m_textboxUserName_I").press("Tab");
|
||||
await page.locator("#m_textboxPassword_I").fill("admin");
|
||||
await page.getByRole("cell", { name: "Anmelden Anmelden" }).locator("span").click();
|
||||
console.log("Login auf 13.er TALAS erfolgreich");
|
||||
await page.waitForTimeout(3000);
|
||||
await page.goto("http://localhost:3000/?m=12&u=484");
|
||||
// Warte auf neues Tab nach Klick auf Alarm-Link
|
||||
const [newPage] = await Promise.all([
|
||||
page.context().waitForEvent("page"),
|
||||
page.getByLabel("Alarm aktiv").click(),
|
||||
]);
|
||||
await newPage.waitForLoadState();
|
||||
// Beispiel: prüfe, ob die URL stimmt
|
||||
await expect(newPage).toHaveURL(/cpl\.aspx/);
|
||||
// Optional: prüfe Text auf der neuen Seite
|
||||
await expect(
|
||||
newPage.getByText("Standort Rastede > Bereich Littwin > TALAS CPL V3.5", { exact: true })
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
/* Powershell Befehl ->das führt langsam aus mit 1 Sekunde Pause zwischen den Aktionen
|
||||
$env:PW_HEADED=1; $env:PW_SLOWMO=1000; npx playwright test
|
||||
*/
|
||||
@@ -5,77 +5,7 @@
|
||||
"zoomOutCenter: Zielkoordinaten für Herauszoomen (lat, lng)",
|
||||
"minZoom/maxZoom: erlaubte Zoomstufen pro Quelle"
|
||||
],
|
||||
"tileSources": {
|
||||
"local": {
|
||||
"url": "http://localhost/talas5/TileMap/mapTiles/{z}/{x}/{y}.png",
|
||||
"_comment": "Offline-Kartenquelle (lokal)",
|
||||
"minZoom": 5,
|
||||
"maxZoom": 15
|
||||
},
|
||||
"osm": {
|
||||
"url": "/tiles/{z}/{x}/{y}.png",
|
||||
"_comment": "OpenStreetMap Online-Kartenquelle über Server-Proxy (relativ)",
|
||||
"minZoom": 0,
|
||||
"maxZoom": 19
|
||||
},
|
||||
"osm-standard": {
|
||||
"name": "Standard",
|
||||
"url": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
|
||||
"attribution": "© OpenStreetMap contributors",
|
||||
"subdomains": "abc",
|
||||
"minZoom": 0,
|
||||
"maxZoom": 19
|
||||
},
|
||||
"osm-humanitarian": {
|
||||
"name": "Humanitarian",
|
||||
"url": "https://{s}.tile.openstreetmap.fr/hot/{z}/{x}/{y}.png",
|
||||
"attribution": "© OpenStreetMap contributors, Humanitarian OpenStreetMap Team",
|
||||
"subdomains": "abc",
|
||||
"minZoom": 0,
|
||||
"maxZoom": 19
|
||||
},
|
||||
"cyclosm": {
|
||||
"name": "CyclOSM",
|
||||
"url": "https://{s}.tile-cyclosm.openstreetmap.fr/cyclosm/{z}/{x}/{y}.png",
|
||||
"attribution": "© OpenStreetMap contributors, CyclOSM",
|
||||
"subdomains": "abc",
|
||||
"minZoom": 0,
|
||||
"maxZoom": 20
|
||||
},
|
||||
"carto-light": {
|
||||
"name": "Carto Light",
|
||||
"url": "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png",
|
||||
"attribution": "© OpenStreetMap contributors, © CARTO",
|
||||
"subdomains": "abcd",
|
||||
"minZoom": 0,
|
||||
"maxZoom": 20
|
||||
},
|
||||
"thunderforest-cycle": {
|
||||
"name": "Cycle Map (Thunderforest)",
|
||||
"url": "https://{s}.tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=YOUR_THUNDERFOREST_API_KEY",
|
||||
"attribution": "© OpenStreetMap contributors, © Thunderforest",
|
||||
"subdomains": "abc",
|
||||
"minZoom": 0,
|
||||
"maxZoom": 22
|
||||
},
|
||||
"thunderforest-transport": {
|
||||
"name": "Transport Map (Thunderforest)",
|
||||
"url": "https://{s}.tile.thunderforest.com/transport/{z}/{x}/{y}.png?apikey=YOUR_THUNDERFOREST_API_KEY",
|
||||
"attribution": "© OpenStreetMap contributors, © Thunderforest",
|
||||
"subdomains": "abc",
|
||||
"minZoom": 0,
|
||||
"maxZoom": 22
|
||||
},
|
||||
"tracestrack-topo": {
|
||||
"name": "Tracestrack Topo",
|
||||
"url": "https://tile.tracestrack.com/topo__/{z}/{x}/{y}.webp?key=YOUR_TRACESTRACK_KEY",
|
||||
"attribution": "© OpenStreetMap contributors, © Tracestrack",
|
||||
"minZoom": 0,
|
||||
"maxZoom": 19
|
||||
}
|
||||
},
|
||||
"active": "osm",
|
||||
"_comment_active": "Aktive Kartenquelle: 'local' oder 'osm'",
|
||||
|
||||
"center": [53.111111, 8.4625],
|
||||
"_comment_center": "Startmittelpunkt der Karte (lat, lng)",
|
||||
|
||||
@@ -84,6 +14,9 @@
|
||||
|
||||
"basePath": "/talas5",
|
||||
"_comment_basePath": "Basis-URL für API und Routing",
|
||||
"minZoom": 5,
|
||||
"maxZoom": 20,
|
||||
"_comment_zoom": "Globale Zoom-Grenzen (min/max). Kann durch tileSources überschrieben werden.",
|
||||
"debugLog": false,
|
||||
"_comment_debugLog": "Debug-Logging für Client "
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<testsuites name="jest tests" tests="0" failures="0" errors="0" time="4.822">
|
||||
</testsuites>
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,209 @@
|
||||
<h1 id="nodemap-entwicklerdokumentation">📘 NodeMap –
|
||||
Entwicklerdokumentation</h1>
|
||||
<p>Willkommen in der Entwicklerdokumentation für
|
||||
<strong>NodeMap</strong> – einer modularen Kartenanwendung zur
|
||||
Visualisierung und Bearbeitung von GIS-Daten, POIs und Gerätestatus in
|
||||
einer interaktiven Leaflet-Karte.</p>
|
||||
<p>Diese Anleitung führt dich <strong>Schritt für Schritt</strong> durch
|
||||
die wichtigsten Themen für lokale Entwicklung, Architekturverständnis
|
||||
und Erweiterung.</p>
|
||||
<hr />
|
||||
<h2 id="inhaltsverzeichnis">📚 Inhaltsverzeichnis</h2>
|
||||
<h3 id="einstieg-übersicht">🔹 Einstieg & Übersicht</h3>
|
||||
<ul>
|
||||
<li><a href="#projektüberblick">Projektüberblick</a></li>
|
||||
<li><a href="build-and-deploy.md">Build & Deployment</a></li>
|
||||
<li><a href="checklist.md">Checkliste für Deployment</a></li>
|
||||
<li><a href="DynamischeMarkerErklaerung.md">Dynamische Marker
|
||||
erklärt</a></li>
|
||||
</ul>
|
||||
<h3 id="architektur">🧭 Architektur</h3>
|
||||
<ul>
|
||||
<li><a href="architecture/device-layer-connection.md">Layer-Verbindung
|
||||
(Geräte)</a></li>
|
||||
</ul>
|
||||
<h3 id="konfiguration">⚙️ Konfiguration</h3>
|
||||
<ul>
|
||||
<li><a href="config/README.md">Allgemeine Übersicht</a></li>
|
||||
<li><a
|
||||
href="#kartenquellen-konfiguration-publicconfigjson">Kartenquellen-Konfiguration
|
||||
(public/config.json)</a></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="kartenquellen-konfiguration-publicconfig.json">⚙️
|
||||
Kartenquellen-Konfiguration (public/config.json)</h2>
|
||||
<p>Die Datei <code>public/config.json</code> steuert, welche
|
||||
Kartenquelle (z.B. OSM oder lokale Tiles) für die Leaflet-Karte
|
||||
verwendet wird.</p>
|
||||
<p><strong>Beispiel:</strong></p>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode json"><code class="sourceCode json"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">"//info"</span><span class="fu">:</span> <span class="st">"tileSources: 'local' für offline, 'osm' für online"</span><span class="fu">,</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">"tileSources"</span><span class="fu">:</span> <span class="fu">{</span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">"local"</span><span class="fu">:</span> <span class="st">"http://localhost/talas5/TileMap/mapTiles/{z}/{x}/{y}.png"</span><span class="fu">,</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">"osm"</span><span class="fu">:</span> <span class="st">"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"</span></span>
|
||||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">},</span></span>
|
||||
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a> <span class="dt">"active"</span><span class="fu">:</span> <span class="st">"osm"</span></span>
|
||||
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>Mit <code>active</code> kann zwischen Online- und Offline-Karten
|
||||
umgeschaltet werden.</li>
|
||||
<li>Die Datei wird beim Start der App automatisch geladen.</li>
|
||||
<li>Für Offline-Betrieb muss das lokale Kartenmaterial vorhanden sein
|
||||
(siehe Installationsanleitung).</li>
|
||||
</ul>
|
||||
<h3 id="hauptkomponenten">🧩 Hauptkomponenten</h3>
|
||||
<ul>
|
||||
<li><a
|
||||
href="components/mainComponent/MapComponent.md">MapComponent</a></li>
|
||||
<li><a
|
||||
href="components/mainComponent/hooks/useInitializeMap.md">useInitializeMap</a></li>
|
||||
</ul>
|
||||
<h3 id="kontextmenü">🗺️ Kontextmenü</h3>
|
||||
<ul>
|
||||
<li><a href="components/contextmenu/README.md">Übersicht
|
||||
Kontextmenü</a></li>
|
||||
<li><a
|
||||
href="components/contextmenu/useMapContextMenu.md">useMapContextMenu
|
||||
Hook</a></li>
|
||||
<li><a
|
||||
href="components/contextmenu/CoordinatePopup.md">CoordinatePopup</a></li>
|
||||
</ul>
|
||||
<h3 id="pois">➕ POIs</h3>
|
||||
<ul>
|
||||
<li><a href="components/pois/AddPOIModal.md">POI hinzufügen
|
||||
(AddPOIModal)</a></li>
|
||||
<li><a href="components/pois/PoiUpdateModal.md">POI bearbeiten
|
||||
(PoiUpdateModal)</a></li>
|
||||
</ul>
|
||||
<h3 id="gis-polylinien">📏 GIS-Polylinien</h3>
|
||||
<ul>
|
||||
<li><a
|
||||
href="components/gisPolylines/PolylineContextMenu.md">PolylineContextMenu</a></li>
|
||||
<li><a
|
||||
href="components/gisPolylines/icons/StartIcon.md">StartIcon</a></li>
|
||||
<li><a href="components/gisPolylines/icons/EndIcon.md">EndIcon</a></li>
|
||||
<li><a
|
||||
href="components/gisPolylines/icons/CircleIcon.md">CircleIcon</a></li>
|
||||
<li><a
|
||||
href="components/gisPolylines/icons/SupportPointIcons.md">SupportPointIcons</a></li>
|
||||
</ul>
|
||||
<h3 id="ui-komponenten">💡 UI-Komponenten</h3>
|
||||
<ul>
|
||||
<li><a
|
||||
href="components/uiWidgets/CoordinateInput.md">CoordinateInput</a></li>
|
||||
<li><a
|
||||
href="components/uiWidgets/VersionInfoModal.md">VersionInfoModal</a></li>
|
||||
<li><a
|
||||
href="components/uiWidgets/mapLayersControlPanel/EditModeToggle.md">EditModeToggle</a></li>
|
||||
<li><a
|
||||
href="components/uiWidgets/mapLayersControlPanel/MapLayersControlPanel.md">MapLayersControlPanel</a></li>
|
||||
</ul>
|
||||
<h3 id="weitere-tools">🧪 Weitere Tools</h3>
|
||||
<ul>
|
||||
<li><a href="components/TestScript.md">TestScript (Debug)</a></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="projektüberblick">Projektüberblick</h2>
|
||||
<p>NodeMap wird von <strong>TALAS.web</strong> über einen iFrame
|
||||
geladen. Die Anwendung basiert auf folgenden Technologien:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Technologie</th>
|
||||
<th>Zweck</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Next.js</td>
|
||||
<td>React-Framework (Frontend/SSR)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Leaflet</td>
|
||||
<td>Kartendarstellung</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Redux Toolkit</td>
|
||||
<td>Zustandverwaltung</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tailwind CSS</td>
|
||||
<td>Styling</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MySQL</td>
|
||||
<td>Datenbank</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Node.js / IIS</td>
|
||||
<td>Server und Auslieferung</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>👉 Mehr zur Systemarchitektur: <a
|
||||
href="architecture.md">architecture.md</a></p>
|
||||
<hr />
|
||||
<h2 id="projektstruktur-setup">Projektstruktur & Setup</h2>
|
||||
<h3 id="zielsystem">Zielsystem</h3>
|
||||
<ul>
|
||||
<li>Offline-Umgebung</li>
|
||||
<li>Windows-Server mit IIS</li>
|
||||
<li>Datenzugriff über TALAS-Webservice oder lokale API</li>
|
||||
</ul>
|
||||
<h3 id="lokale-entwicklung">Lokale Entwicklung</h3>
|
||||
<p>➡ <a href="guide/setup-dev.md">Entwicklungs-Setup</a><br />
|
||||
➡ <a href="guide/project-structure.md">Projektstruktur erklärt</a><br />
|
||||
➡ <a href="guide/dependencies.md">Abhängigkeiten & Tools</a><br />
|
||||
➡ <a href="guide/env.md">Umgebungsvariablen (env-Dateien)</a></p>
|
||||
<hr />
|
||||
<h2 id="webservices-api-fluss">Webservices & API-Fluss</h2>
|
||||
<p>NodeMap verwendet zwei Quellen für Daten:</p>
|
||||
<ol type="1">
|
||||
<li><strong>TALAS-WebServices</strong> (Port 80) – POIs, Geräte, Rechte,
|
||||
Linien usw.</li>
|
||||
<li><strong>Lokale Next.js API</strong> (Port 3000) – direkte
|
||||
Datenbankzugriffe via MySQL</li>
|
||||
</ol>
|
||||
<p>➡ <a href="guide/webservices.md">Webservices-Dokumentation</a></p>
|
||||
<hr />
|
||||
<h2 id="zustandverwaltung-redux">Zustandverwaltung Redux</h2>
|
||||
<p>Die komplette Anwendung verwendet Redux zur globalen
|
||||
Zustandverwaltung.</p>
|
||||
<ul>
|
||||
<li>Architektur: <code>Service → Thunk → Slice → Komponente</code></li>
|
||||
<li>Beispiel: POIs, Marker, Linien, Rechte, Layer-Status</li>
|
||||
<li>Redux DevTools werden unterstützt</li>
|
||||
</ul>
|
||||
<p>➡ <a href="guide/redux-zustand.md">Zustandverwaltung mit
|
||||
Redux</a></p>
|
||||
<hr />
|
||||
<h2 id="entwicklung-testdaten">Entwicklung & Testdaten</h2>
|
||||
<p>Zur Entwicklung ohne echte API stehen lokale Mockdaten zur
|
||||
Verfügung:</p>
|
||||
<ul>
|
||||
<li>Aktivierung über
|
||||
<code>.env.development → NEXT_PUBLIC_USE_MOCKS=true</code></li>
|
||||
<li>In <code>.env.production</code> sollte
|
||||
<code>NEXT_PUBLIC_USE_MOCKS=false</code> gesetzt sein</li>
|
||||
<li>Nutzung z. B. in <code>pages/api/mocks/...</code></li>
|
||||
<li>Hinweise im UI zeigen aktivierten Mockmodus</li>
|
||||
</ul>
|
||||
<p>➡ <a href="guide/mock-data.md">Mockdaten & Entwicklung</a></p>
|
||||
<hr />
|
||||
<h2 id="fehlerbehandlung-glossar">Fehlerbehandlung & Glossar</h2>
|
||||
<p>Typische Probleme (z. B. Webservice nicht erreichbar, Layer nicht
|
||||
sichtbar) werden in der FAQ gesammelt.<br />
|
||||
Zudem gibt es eine Begriffsliste zur Orientierung:</p>
|
||||
<p>➡ <a href="guide/faq.md">FAQ & häufige Fehler</a><br />
|
||||
➡ <a href="guide/glossar.md">Glossar</a></p>
|
||||
<hr />
|
||||
<h2 id="hinweis-zum-deployment">Hinweis zum Deployment</h2>
|
||||
<p>📦 Die Anleitung für Server-Installation und ZIP-Deployment findest
|
||||
du in:<br />
|
||||
➡ <a href="../README.md">Root-README.md</a></p>
|
||||
<hr />
|
||||
<h2 id="tipp">Tipp</h2>
|
||||
<p>Wenn du neu im Projekt bist, beginne mit dem Kapitel
|
||||
<strong>Projektstruktur & Setup</strong> und folge dann über die
|
||||
Webservices bis zu den Komponenten.</p>
|
||||
@@ -0,0 +1,122 @@
|
||||
<h1 id="dynamische-marker-verwaltung-in-mapcomponent.js-nodemap">🗺️
|
||||
Dynamische Marker-Verwaltung in MapComponent.js (NodeMap)</h1>
|
||||
<p>Dieses Dokument erklärt, wie Marker dynamisch erstellt, verwaltet und
|
||||
in <code>MapComponent.js</code> verwendet werden – inklusive Datenfluss
|
||||
und OverlappingMarkerSpiderfier-Integration.</p>
|
||||
<hr />
|
||||
<h2 id="dynamische-marker-erzeugung-übersicht">🔄 Dynamische
|
||||
Marker-Erzeugung – Übersicht</h2>
|
||||
<p>Früher (statisch):</p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">useLayerVisibility</span>(map<span class="op">,</span> talasMarkers<span class="op">,</span> mapLayersVisibility<span class="op">,</span> <span class="st">"TALAS"</span><span class="op">,</span> oms)<span class="op">;</span></span></code></pre></div>
|
||||
<p>→ Jeder Marker-Typ war hart codiert.</p>
|
||||
<p>Jetzt (dynamisch):</p>
|
||||
<div class="sourceCode" id="cb2"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> { markerStates<span class="op">,</span> layerRefs } <span class="op">=</span> <span class="fu">useDynamicDeviceLayers</span>(</span>
|
||||
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a> map<span class="op">,</span></span>
|
||||
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> GisSystemStatic<span class="op">,</span></span>
|
||||
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> mapLayersVisibility<span class="op">,</span></span>
|
||||
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a> priorityConfig<span class="op">,</span></span>
|
||||
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a> oms</span>
|
||||
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>)<span class="op">;</span></span></code></pre></div>
|
||||
<hr />
|
||||
<h2 id="datenfluss-schritt-für-schritt">🔁 Datenfluss Schritt für
|
||||
Schritt</h2>
|
||||
<ol type="1">
|
||||
<li><strong>MapComponent.js</strong> ruft den Hook
|
||||
<code>useDynamicDeviceLayers(...)</code> auf.</li>
|
||||
<li>Der Hook iteriert über <code>GisSystemStatic</code>
|
||||
(Webservice-Liste aller Systeme).</li>
|
||||
<li>Für jedes System wird <code>createAndSetDevices(...)</code>
|
||||
aufgerufen.</li>
|
||||
<li>Diese Funktion:
|
||||
<ul>
|
||||
<li>Holt <code>Stations</code> aus Redux (filtered by System-ID)</li>
|
||||
<li>Erstellt Marker (Leaflet)</li>
|
||||
<li>Rückgabe über Callback <code>setMarkersFunction(markers)</code></li>
|
||||
</ul></li>
|
||||
<li>Die Marker werden per <code>setMarkerStates()</code>
|
||||
gespeichert.</li>
|
||||
<li>In MapComponent.js können sie aus
|
||||
<code>markerStates[SystemName]</code> gelesen werden.</li>
|
||||
<li>Sichtbarkeit wird über Redux (<code>mapLayersVisibility</code>)
|
||||
gesteuert.</li>
|
||||
<li>Überlappende Marker werden über
|
||||
<code>checkOverlappingMarkers()</code> + <code>plusRoundIcon</code> +
|
||||
OMS angezeigt.</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="marker-aufbau">📦 Marker-Aufbau</h2>
|
||||
<h3 id="createandsetdevices.js"><code>createAndSetDevices.js</code></h3>
|
||||
<ul>
|
||||
<li><p>Filtert Stations (<code>Points</code>) aus
|
||||
<code>selectGisStationsStaticDistrict</code></p></li>
|
||||
<li><p>Erstellt für jede gültige Station einen Marker:</p>
|
||||
<div class="sourceCode" id="cb3"><pre
|
||||
class="sourceCode js"><code class="sourceCode javascript"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> marker <span class="op">=</span> L<span class="op">.</span><span class="fu">marker</span>([station<span class="op">.</span><span class="at">X</span><span class="op">,</span> station<span class="op">.</span><span class="at">Y</span>]<span class="op">,</span> { <span class="op">...</span> })<span class="op">;</span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>oms<span class="op">.</span><span class="fu">addMarker</span>(marker)<span class="op">;</span> <span class="co">// Spiderfier-fähig</span></span></code></pre></div></li>
|
||||
<li><p>Fügt Marker zur richtigen <code>LayerGroup</code> hinzu</p></li>
|
||||
<li><p>Gibt alle Marker über Callback zurück</p></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="overlappingmarkerspiderfier-oms">🕷️ OverlappingMarkerSpiderfier
|
||||
(OMS)</h2>
|
||||
<ul>
|
||||
<li><p>Initialisiert in <code>useInitializeMap(...)</code> in
|
||||
<code>MapComponent.js</code></p></li>
|
||||
<li><p>Wird an <code>useDynamicDeviceLayers</code> übergeben</p></li>
|
||||
<li><p>Marker werden dort registriert:
|
||||
<code>oms.addMarker(marker)</code></p></li>
|
||||
<li><p>Bei Klick auf das PlusIcon:</p>
|
||||
<div class="sourceCode" id="cb4"><pre
|
||||
class="sourceCode js"><code class="sourceCode javascript"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>plusMarker<span class="op">.</span><span class="fu">on</span>(<span class="st">"click"</span><span class="op">,</span> () <span class="kw">=></span> oms<span class="op">.</span><span class="fu">spiderfy</span>(nearbyMarkers))<span class="op">;</span></span></code></pre></div></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="mermaid-diagramm">📘 Mermaid-Diagramm</h2>
|
||||
<pre class="mermaid"><code>flowchart TD
|
||||
A1[MapComponent] --> B1[useDynamicDeviceLayers]
|
||||
B1 --> C1[loop über GisSystemStatic]
|
||||
C1 --> D1[createAndSetDevices]
|
||||
D1 --> E1[Filter stations aus Redux]
|
||||
E1 --> F1[erstelle Marker /Leaflet]
|
||||
F1 --> G1[Marker in LayerGroup einfügen]
|
||||
G1 --> H1[setMarkerStates im Hook]
|
||||
H1 --> A2[markerStates zurück nach MapComponent]
|
||||
|
||||
A2 --> I1[Map aktualisiert Marker]
|
||||
A2 --> I2[checkOverlappingMarkers mit OMS]</code></pre>
|
||||
<hr />
|
||||
<h2 id="vorteile-der-neuen-lösung">✅ Vorteile der neuen Lösung</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 19%" />
|
||||
<col style="width: 80%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Vorteil</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>🔄 Flexibel</td>
|
||||
<td>Neue Geräte-Typen automatisch erkannt</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>📦 Kompakt</td>
|
||||
<td>Kein <code>useState</code> oder <code>useLayerVisibility</code> mehr
|
||||
nötig</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🧠 Wartbar</td>
|
||||
<td>Eine zentrale Logik statt doppelter Komponentenlogik</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>🕷️ Integriert</td>
|
||||
<td>OMS funktioniert automatisch bei überlappenden Markern</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<p>Letztes Update: automatisch generiert mit ChatGPT (OpenAI)</p>
|
||||
<hr />
|
||||
<p><a href="README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,5 @@
|
||||
<h1 id="übersicht-docsarchitecture">📄 Übersicht: docs/architecture</h1>
|
||||
<ul>
|
||||
<li><a
|
||||
href="device-layer-connection.md">device-layer-connection</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,393 @@
|
||||
<!-- /docs/architecture.md -->
|
||||
<h1 id="architekturübersicht-nodemap">🧠 Architekturübersicht –
|
||||
NodeMap</h1>
|
||||
<p>Dieses Dokument beschreibt die technische Gesamtarchitektur des
|
||||
Projekts <strong>NodeMap</strong>, einer kartenbasierten Webanwendung
|
||||
zur Anzeige, Bearbeitung und Verwaltung von GIS-Daten, POIs und
|
||||
Gerätestatus.</p>
|
||||
<hr />
|
||||
<h2 id="technologie-stack">⚙️ Technologie-Stack</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 23%" />
|
||||
<col style="width: 76%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Komponente</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>Frontend</strong></td>
|
||||
<td>React 18 + Next.js (App Router)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>State-Management</strong></td>
|
||||
<td>Redux Toolkit mit zentralem Store, Thunks & Slices</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>UI</strong></td>
|
||||
<td>Tailwind CSS + Leaflet + React-Icons</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Backend-Anbindung</strong></td>
|
||||
<td>Webservices via <code>WebServiceMap.asmx</code> (IIS) + lokale
|
||||
Next.js API für DB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Datenbank</strong></td>
|
||||
<td>MySQL (Produktiv & Entwicklung, z. T. via Docker)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Deployment</strong></td>
|
||||
<td>Windows Server (IIS), optional per <code>nssm</code> als Dienst</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="systemübersicht-ablauf">🔄 Systemübersicht (Ablauf)</h2>
|
||||
<pre class="mermaid"><code>sequenceDiagram
|
||||
participant Browser
|
||||
participant TALASweb
|
||||
participant NodeMap
|
||||
participant MySQL
|
||||
|
||||
Browser->>TALASweb: mapTypC.aspx?m=12&u=484
|
||||
TALASweb-->>Browser: iFrame lädt NodeMap
|
||||
Browser->>NodeMap: Liest m & u aus URL
|
||||
NodeMap->>TALASweb: WebService-Requests (5 APIs)
|
||||
NodeMap->>MySQL: API-Anfragen zu POIs, Geräten, Linien
|
||||
NodeMap-->>Browser: Interaktive Karte anzeigen
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h2 id="architekturüberblick">🗺️ Architekturüberblick</h2>
|
||||
<pre><code>+------------------+ +------------------+ +------------------+
|
||||
| Leaflet Map | <---> | Redux Store | <---> | Webservices |
|
||||
| (Interaktivität) | | (Status & Data) | | (IIS, .asmx) |
|
||||
+------------------+ +------------------+ +------------------+
|
||||
^
|
||||
|
|
||||
v
|
||||
+------------------+ +------------------+ +-------------------+
|
||||
| POI-Komponenten | <---> | Redux Slices | <---> | Next.js API-Routen|
|
||||
| (Add/Edit) | | (z. B. poiSlice) | | (Datenbank) |
|
||||
+------------------+ +------------------+ +-------------------+</code></pre>
|
||||
<hr />
|
||||
<h2 id="datenfluss-beispiel-poi-anzeigen">🔁 Datenfluss (Beispiel: POI
|
||||
anzeigen)</h2>
|
||||
<ol type="1">
|
||||
<li>Leaflet-Karte lädt bei <code>MapComponent</code> Mounting</li>
|
||||
<li>Redux-Thunk <code>fetchPoiMarkersThunk</code> wird ausgelöst</li>
|
||||
<li>Thunk ruft <code>fetchPoiDataService.js</code> (DB) oder Webservice
|
||||
(IIS) auf</li>
|
||||
<li>Ergebnisse werden im Slice <code>readPoiMarkersStoreSlice</code>
|
||||
gespeichert</li>
|
||||
<li>Komponenten lesen POI-Daten über <code>useSelector(...)</code> aus
|
||||
dem Store</li>
|
||||
<li>POIs werden als Marker in Leaflet gesetzt</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="schlüsselfunktionen-module">📁 Schlüsselfunktionen &
|
||||
Module</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 11%" />
|
||||
<col style="width: 54%" />
|
||||
<col style="width: 34%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Bereich</th>
|
||||
<th>Datei/Modul</th>
|
||||
<th>Aufgabe</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Kartenlogik</td>
|
||||
<td><code>MapComponent.js</code></td>
|
||||
<td>Zentrale Initialisierung und Layer-Logik</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Webservices</td>
|
||||
<td><code>services/webservice/</code></td>
|
||||
<td>Kommunikation mit TALAS V5 Webservice</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Datenbank</td>
|
||||
<td><code>services/database/</code></td>
|
||||
<td>Zugriff auf lokale Next.js-API & DB</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>POIs</td>
|
||||
<td><code>AddPOIModal.js</code>, <code>PoiUpdateModal.js</code></td>
|
||||
<td>UI für POI-Erstellung & -Bearbeitung</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Redux</td>
|
||||
<td><code>redux/slices/</code>, <code>redux/thunks/</code>,
|
||||
<code>redux/store</code></td>
|
||||
<td>Globaler State, API-Steuerung</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Konfiguration</td>
|
||||
<td><code>.env.development</code>,<code>.env.production</code>,
|
||||
<code>config.js</code>, dynamic URLs</td>
|
||||
<td>IP, basePath, Ports</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="besonderheiten">🧩 Besonderheiten</h2>
|
||||
<ul>
|
||||
<li><p><strong>Konfigurierbarer basePath:</strong></p></li>
|
||||
<li><p><strong>Konfigurierbarer basePath:</strong><br />
|
||||
Pfad wie <code>/talas5</code> ist optional und wird jetzt in
|
||||
<code>public/config.json</code> als <code>basePath</code> gepflegt
|
||||
werden.<br />
|
||||
Die Konfiguration erfolgt je nach Umgebung über:</p>
|
||||
<ul>
|
||||
<li><code>.env.development</code> für lokale Entwicklung</li>
|
||||
<li><code>.env.production</code> für produktiven Einsatz</li>
|
||||
</ul></li>
|
||||
<li><p><strong>Rechteabhängige UI:</strong><br />
|
||||
Funktionen (z. B. POI bearbeiten) basieren auf Benutzerrechten
|
||||
(<code>IdRight</code>) vom Server.</p></li>
|
||||
<li><p><strong>Zentrale Komponentensteuerung:</strong><br />
|
||||
Komponenten wie <code>MapLayersControlPanel</code> oder
|
||||
<code>CoordinatePopup</code> kontrollieren Layer &
|
||||
Interaktion.</p></li>
|
||||
<li><p><strong>Kontextmenü-Logik:</strong><br />
|
||||
Marker & Polylinien besitzen eigene Kontextmenüs – dynamisch
|
||||
zusammengesetzt und verwaltet.</p></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="versionierung-builds">📦 Versionierung & Builds</h2>
|
||||
<ul>
|
||||
<li>Version wird mit Husky Bibliothek automatisch erhöhert in
|
||||
<code>scripts/bumpVersion.js</code></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="weiterführende-dokumentation">📚 Weiterführende
|
||||
Dokumentation</h2>
|
||||
<ul>
|
||||
<li><a
|
||||
href="./build-and-deploy.md"><code>build-and-deploy.md</code></a></li>
|
||||
<li><a
|
||||
href="./env.local.schema.md"><code>env.local.schema.md</code></a></li>
|
||||
<li><a href="./redux/slices/"><code>redux/slices/</code></a></li>
|
||||
<li><a
|
||||
href="./services/webservice/"><code>services/webservice/</code></a></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="dynamische-layer-verwaltung-mit-redux">Dynamische
|
||||
Layer-Verwaltung mit Redux</h2>
|
||||
<pre class="mermaid"><code>flowchart TD
|
||||
%% Webservice
|
||||
subgraph Webservice
|
||||
A1[GisSystemStatic API]
|
||||
A2[GisStationsStaticDistrict API]
|
||||
end
|
||||
|
||||
%% Redux
|
||||
subgraph Redux
|
||||
B1[fetchGisSystemStaticThunk]
|
||||
B2[fetchGisStationsStaticDistrictThunk]
|
||||
C1["gisSystemStaticSlice → selectGisSystemStatic"]
|
||||
C2["gisStationsStaticDistrictSlice → selectGisStationsStaticDistrict"]
|
||||
C3["mapLayersSlice → mapLayersVisibility"]
|
||||
end
|
||||
|
||||
%% React
|
||||
subgraph React-Komponente
|
||||
D1[MapComponent.js]
|
||||
D2["useEffect: dynamische Layer"]
|
||||
D3["createAndSetDevices"]
|
||||
D4["layerRefs (useRef)"]
|
||||
D5["markerStates (useState)"]
|
||||
D6["useEffect: Sichtbarkeit prüfen"]
|
||||
D7["Map aktualisieren / add/remove"]
|
||||
D8["checkOverlappingMarkers"]
|
||||
end
|
||||
|
||||
%% Datenfluss
|
||||
A1 --> B1 --> C1 --> D2
|
||||
A2 --> B2 --> C2 --> D3
|
||||
C3 --> D6
|
||||
D2 --> D3
|
||||
D3 --> D4
|
||||
D3 --> D5
|
||||
D5 --> D6
|
||||
D6 --> D7
|
||||
D6 --> D8
|
||||
D7 --> D1
|
||||
|
||||
|
||||
|
||||
</code></pre>
|
||||
<hr />
|
||||
<p>Jetzt (dynamisch & Redux-basiert): MapComponent.js ruft folgenden
|
||||
Hook auf:</p>
|
||||
<p>js Copy Edit const { markerStates, layerRefs } =
|
||||
useDynamicDeviceLayers(map, GisSystemStatic, mapLayersVisibility,
|
||||
priorityConfig, oms); useDynamicDeviceLayers.js verarbeitet die
|
||||
GisSystemStatic-Liste:</p>
|
||||
<p>Jedes System (z. B. “TALAS”, “ECI”, “Cisco”) bekommt einen eigenen
|
||||
Marker-Layer.</p>
|
||||
<p>Die Marker werden erstellt durch:</p>
|
||||
<p>js Copy Edit createAndSetDevices(…) // Systemweise Marker erzeugen
|
||||
createAndSetDevices.js:</p>
|
||||
<p>Filtert alle Stations aus staticDistrictData, deren System ===
|
||||
IdSystem.</p>
|
||||
<p>Erstellt Marker für jedes Gerät.</p>
|
||||
<p>Bindet Popup, Kontextmenü, Styling, Bounce usw.</p>
|
||||
<p>Ruft setMarkersFunction(markers) auf → Übergibt die Marker zurück an
|
||||
den Hook.</p>
|
||||
<p>Der Hook speichert:</p>
|
||||
<p>js Copy Edit setMarkerStates((prev) => ({ …prev, [Name]:
|
||||
newMarkers })); MapComponent.js hat dann:</p>
|
||||
<p>Zugriff auf alle Marker dynamisch über markerStates (ein Objekt mit
|
||||
Schlüssel = Systemname)</p>
|
||||
<p>Sichtbarkeit und OverlappingMarkerSpiderfier werden damit
|
||||
verarbeitet.</p>
|
||||
<hr />
|
||||
<p>🔁 Die Geräte-Marker sind nicht mehr fest codiert, sondern werden
|
||||
dynamisch erzeugt anhand der Webservice-Daten GisSystemStatic.</p>
|
||||
<p>🔄 Sichtbarkeit (Checkbox im Control Panel) löst ein Event
|
||||
visibilityChanged aus → MapComponent reagiert und rendert Marker
|
||||
neu.</p>
|
||||
<p>🕷️ Überlappende Marker werden mit checkOverlappingMarkers +
|
||||
PlusRoundIcon verarbeitet.</p>
|
||||
<pre class="mermaid"><code>flowchart TD
|
||||
A1[MapComponent] --> B1[useDynamicDeviceLayers]
|
||||
B1 --> C1[loop über GisSystemStatic]
|
||||
C1 --> D1[createAndSetDevices]
|
||||
D1 --> E1[Filter stations aus Redux]
|
||||
E1 --> F1[erstelle Marker /Leaflet]
|
||||
F1 --> G1[Marker in LayerGroup einfügen]
|
||||
G1 --> H1[setMarkerStates im Hook]
|
||||
H1 --> A2[markerStates zurück nach MapComponent]
|
||||
|
||||
A2 --> I1[Map aktualisiert Marker]
|
||||
A2 --> I2[checkOverlappingMarkers mit OMS]</code></pre>
|
||||
<hr />
|
||||
<p>10.06.2025</p>
|
||||
<h1 id="datenfluss-konzept-websocket-redux-ui">Datenfluss-Konzept:
|
||||
WebSocket ↔︎ Redux ↔︎ UI</h1>
|
||||
<p>Dieses Dokument beschreibt den technischen Ablauf des
|
||||
Live-Datenflusses im NodeMap-Projekt, um neue Entwickler:innen beim
|
||||
Onboarding zu unterstützen.</p>
|
||||
<h2 id="ᵀᵃᵗᵉᵖᵏᴼᵏᴼᵉ-architekturübersicht">ᵀᵃᵗᵉᵖᵏᴼᵏᴼᵉ:
|
||||
Architekturübersicht</h2>
|
||||
<pre class="mermaid"><code>sequenceDiagram
|
||||
autonumber
|
||||
participant WS_Server as WebSocket Server
|
||||
participant WebService as TALAS WebService
|
||||
participant Browser
|
||||
participant ReduxStore as Redux Store
|
||||
participant UI as React Leaflet UI
|
||||
|
||||
loop Alle 5 Sekunden
|
||||
WS_Server->>WebService: fetch endpointX
|
||||
alt Daten haben sich geändert
|
||||
WS_Server-->>Browser: emit 'endpointXUpdated'
|
||||
Browser->>ReduxStore: dispatch(fetchEndpointXThunk())
|
||||
ReduxStore->>WebService: fetch endpointX
|
||||
WebService-->>ReduxStore: JSON response
|
||||
ReduxStore-->>UI: update Slice
|
||||
UI-->>User: re-render Markers
|
||||
else Keine Änderung
|
||||
WS_Server-->>WS_Server: keine Aktion
|
||||
end
|
||||
end</code></pre>
|
||||
<h2 id="beteiligte-komponenten">Beteiligte Komponenten</h2>
|
||||
<h3 id="websocket-server-server.js">WebSocket Server
|
||||
(<code>server.js</code>)</h3>
|
||||
<ul>
|
||||
<li>Ruft regelmäßig (<code>setInterval</code>) die Webservice-Endpunkte
|
||||
auf.</li>
|
||||
<li>Erkennt Änderungen durch JSON-Vergleich
|
||||
(<code>JSON.stringify</code>).</li>
|
||||
<li>Sendet WebSocket-Events nur bei echten Änderungen.</li>
|
||||
</ul>
|
||||
<h3 id="client-mapcomponent">Client: MapComponent</h3>
|
||||
<ul>
|
||||
<li>Hört auf <code>socket.on("endpointXUpdated")</code>.</li>
|
||||
<li>Ruft dann gezielt den passenden Redux-Thunk auf (z. B.
|
||||
<code>fetchGisLinesStatusThunk</code>).</li>
|
||||
</ul>
|
||||
<h3 id="redux-store-thunks">Redux Store & Thunks</h3>
|
||||
<ul>
|
||||
<li><p>Jeder Endpunkt besitzt:</p>
|
||||
<ul>
|
||||
<li>einen <code>Service</code> (API-Fetch)</li>
|
||||
<li>einen <code>Thunk</code> (Redux-Logik)</li>
|
||||
<li>einen <code>Slice</code> (State-Verwaltung)</li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
<h3 id="react-ui-leaflet-map">React UI (Leaflet Map)</h3>
|
||||
<ul>
|
||||
<li>Beobachtet relevante Redux-Slices via
|
||||
<code>useSelector()</code>.</li>
|
||||
<li>Aktualisiert Marker, Tooltip und Popup über
|
||||
<code>createAndSetDevices()</code> und
|
||||
<code>useDynamicDeviceLayers()</code>.</li>
|
||||
</ul>
|
||||
<h2 id="beispiel-endpunkte">Beispiel-Endpunkte</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 27%" />
|
||||
<col style="width: 34%" />
|
||||
<col style="width: 39%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Endpunktname</th>
|
||||
<th>WebSocket Event</th>
|
||||
<th>Redux Thunk</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>GisLinesStatus</code></td>
|
||||
<td><code>GisLinesStatusUpdated</code></td>
|
||||
<td><code>fetchGisLinesStatusThunk()</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GisStationsMeasurements</code></td>
|
||||
<td><code>GisStationsMeasurementsUpdated</code></td>
|
||||
<td><code>fetchGisStationsMeasurementsThunk()</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GisStationsStaticDistrict</code></td>
|
||||
<td><code>GisStationsStaticDistrictUpdated</code></td>
|
||||
<td><code>fetchGisStationsStaticDistrictThunk()</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GisStationsStatusDistrict</code></td>
|
||||
<td><code>GisStationsStatusDistrictUpdated</code></td>
|
||||
<td><code>fetchGisStationsStatusDistrictThunk()</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="vorteile">Vorteile</h2>
|
||||
<ul>
|
||||
<li>UI aktualisiert sich nur bei echten Datenänderungen → weniger
|
||||
Re-Renders.</li>
|
||||
<li>Live-Synchronisation zwischen Datenquelle und Anzeige.</li>
|
||||
<li>Skalierbar für beliebige Endpunkte.</li>
|
||||
</ul>
|
||||
<h2 id="todoerweiterungen">ToDo/Erweiterungen</h2>
|
||||
<ul>
|
||||
<li>Automatische Reconnect-Logik für WebSocket.</li>
|
||||
<li>Anzeige des letzten Update-Zeitpunkts in UI.</li>
|
||||
<li>Logging-UI für WebSocket-Messages zur Diagnose.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<blockquote>
|
||||
<p>Letzte Änderung: <code>{{heutiges Datum}}</code> von Ismail Ali</p>
|
||||
</blockquote>
|
||||
<hr />
|
||||
<p><a href="README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,19 @@
|
||||
<h1 id="architektur-verbindung-gis-system-gis-station">📡 Architektur:
|
||||
Verbindung GIS-System & GIS-Station</h1>
|
||||
<p>Dieses Diagramm zeigt den Ablauf, wie Geräte (Marker) auf der Karte
|
||||
über die ID (System gegen IdSystem) korrekt geladen und sichtbar gemacht
|
||||
werden.</p>
|
||||
<pre class="mermaid"><code>flowchart TD
|
||||
A[Stationen aus GIS Stations District mit System ID zum Beispiel 111] --> B[useDynamicDeviceLayers.js]
|
||||
B --> C[Filter und Gruppierung nach System ID]
|
||||
C --> D[createAndSetDevices.js erzeugt Marker]
|
||||
D --> E[MapComponent.js zeigt Marker auf Karte]
|
||||
subgraph Redux
|
||||
F[fetchGisSystemStaticService.js liefert Systeme mit IdSystem]
|
||||
F --> G[fetchGisSystemStaticThunk.js]
|
||||
G --> H[setInitialLayers mit system-IdSystem]
|
||||
H --> I[mapLayersSlice.js speichert Sichtbarkeit]
|
||||
end
|
||||
I -->|Sichtbarkeit steuert Anzeige| E</code></pre>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,100 @@
|
||||
<!-- /docs/build-amddeploy.md -->
|
||||
<h1 id="deployment-build-verhalten-next.js">🛠 Deployment &
|
||||
Build-Verhalten (Next.js)</h1>
|
||||
<p>Diese Datei beschreibt, welche Projektdateien in den Build
|
||||
(<code>.next/</code>) aufgenommen werden und welche nicht.<br />
|
||||
Ziel: Klarheit für Onboarding, Deployment-ZIP-Erstellung oder CI/CD.</p>
|
||||
<hr />
|
||||
<h2 id="wird-beim-npm-run-build-in-.next-gespeichert">📦 Wird beim
|
||||
<code>npm run build</code> in <code>.next/</code> gespeichert</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 34%" />
|
||||
<col style="width: 65%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Inhalt</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Kompilierte Seiten</td>
|
||||
<td>Alle unter <code>/pages/</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>API-Routen</td>
|
||||
<td>Alles aus <code>pages/api/</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Assets aus <code>public/</code></td>
|
||||
<td>Werden im Build nicht verändert, aber ausgeliefert</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CSS-Dateien (Tailwind)</td>
|
||||
<td>Werden gebundelt und minimiert</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.env.production</code> / <code>.env.development</code></td>
|
||||
<td>Umgebungsabhängige Konfiguration. Wird eingelesen, aber nicht
|
||||
exportiert</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="line-block">JS/TS-Quellcode | Wird zu Client- und
|
||||
Server-Bundles kompiliert |</div>
|
||||
<hr />
|
||||
<h2 id="wird-nicht-in-.next-aufgenommen">🧹 Wird <strong>nicht</strong>
|
||||
in <code>.next/</code> aufgenommen</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 38%" />
|
||||
<col style="width: 61%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Ordner/Datei</th>
|
||||
<th>Zweck / Grund</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>__tests__</code>, <code>__mocks__</code></td>
|
||||
<td>Nur lokal für Tests, nicht im Build</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>cypress/</code></td>
|
||||
<td>End-to-End-Tests, nur für lokale Entwicklung</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>scripts/</code></td>
|
||||
<td>Hilfsskripte, nicht für Runtime relevant</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>docs/</code></td>
|
||||
<td>Dokumentation, nur für Entwickler</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>README.md</code>, <code>CHANGELOG.md</code></td>
|
||||
<td>Doku – nicht erforderlich zur Laufzeit</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Jenkinsfile</code>, <code>.github/</code></td>
|
||||
<td>CI/CD – wird vom Buildsystem verwendet</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2
|
||||
id="empfohlene-struktur-für-deployment-z.-b.-zip-upload-auf-server">📂
|
||||
Empfohlene Struktur für Deployment (z. B. ZIP-Upload auf Server)</h2>
|
||||
<p>Nur folgende Dateien/Ordner übertragen:</p>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">.next/</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ex">public/</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ex">package.json</span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="ex">package-lock.json</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a><span class="ex">.env.production</span></span></code></pre></div>
|
||||
<hr />
|
||||
<p><a href="README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,51 @@
|
||||
<!-- /docs/checklist.md -->
|
||||
<h1 id="projektpflege-checkliste">🧾 Projektpflege-Checkliste</h1>
|
||||
<p>Diese Datei dient als persönliche Gedächtnisstütze bei der
|
||||
Entwicklung und Pflege des Projekts.</p>
|
||||
<p>Bevor du einen Feature-, Refactor- oder Bugfix-Commit abschließt, geh
|
||||
diese Liste durch:</p>
|
||||
<hr />
|
||||
<h2 id="dokumentation">📝 Dokumentation</h2>
|
||||
<ul class="task-list">
|
||||
<li><label><input type="checkbox" />Ist <code>README.md</code> noch
|
||||
aktuell (Projektziel, Setup, Nutzung)?</label></li>
|
||||
<li><label><input type="checkbox" />Wurde <code>CHANGELOG.md</code>
|
||||
ergänzt (mit Datum, Version, Änderung)?</label></li>
|
||||
<li><label><input type="checkbox" />Wurde ggf. ein neuer Punkt in
|
||||
<code>/docs/</code> ergänzt oder aktualisiert?</label></li>
|
||||
<li><label><input type="checkbox" />Sind Beispiel-URLs oder sensible
|
||||
Daten <strong>nicht im Code</strong>, sondern dokumentiert?</label></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="konfiguration">📦 Konfiguration</h2>
|
||||
<ul class="task-list">
|
||||
<li><label><input type="checkbox" />Sind <code>.env.production</code>
|
||||
und <code>.env.development</code> aktuell und vollständig?</label></li>
|
||||
<li><label><input type="checkbox" />Wird jede Konfiguration
|
||||
<strong>ausschließlich über <code>.env.*</code> Dateien</strong>
|
||||
gesteuert?</label></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="codequalität-git">✅ Codequalität & Git</h2>
|
||||
<ul class="task-list">
|
||||
<li><label><input type="checkbox" />Ist die Git-Commit-Message
|
||||
beschreibend und lesbar (z. B. <code>feat:</code>, <code>fix:</code>,
|
||||
<code>docs:</code>)?</label></li>
|
||||
<li><label><input type="checkbox" />Wurden unnötige Debug-Logs entfernt
|
||||
oder per <code>NODE_ENV</code> abgesichert?</label></li>
|
||||
<li><label><input type="checkbox" />Wurden Änderungen getestet (lokal,
|
||||
ggf. auf Testsystem)?</label></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="onboarding-freundlich">🧭 Onboarding-freundlich?</h2>
|
||||
<ul class="task-list">
|
||||
<li><label><input type="checkbox" />Könnte ein neuer Entwickler mit den
|
||||
aktuellen Dokumenten verstehen, was wie funktioniert?</label></li>
|
||||
<li><label><input type="checkbox" />Gibt es Hinweise zur Architektur,
|
||||
API-Flows oder Besonderheiten im Code?</label></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p>Du kannst diese Checkliste in jedem Projekt beibehalten und auf deine
|
||||
Arbeitsweise anpassen.</p>
|
||||
<hr />
|
||||
<p><a href="README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,67 @@
|
||||
<!-- /docs/components/README.md -->
|
||||
<h1 id="components-übersicht-über-alle-ui-komponenten">🧩
|
||||
<code>components/</code> – Übersicht über alle UI-Komponenten</h1>
|
||||
<p>Dieses Verzeichnis enthält die gesamten React-Komponenten der
|
||||
TALAS-Kartenanwendung.<br />
|
||||
Sie sind thematisch gegliedert in Teilbereiche für Kontextmenüs, POIs,
|
||||
Polylinien, Modale und die zentrale <code>MapComponent</code>.</p>
|
||||
<hr />
|
||||
<h2 id="strukturübersicht">📁 Strukturübersicht</h2>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">components/</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> contextmenu/ <span class="co"># Komponenten für rechte Maustaste & Kontextaktionen</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> ├── CoordinatePopup.js</span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> └── useMapContextMenu.js</span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> gisPolylines/ <span class="co"># Polylinien (Kabelstrecken)</span></span>
|
||||
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> ├── PolylineContextMenu.js</span>
|
||||
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> └── icons/</span>
|
||||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> ├── CircleIcon.js</span>
|
||||
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> ├── EndIcon.js</span>
|
||||
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> ├── StartIcon.js</span>
|
||||
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> └── SupportPointIcons.js</span>
|
||||
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> icons/devices/overlapping/ <span class="co"># Zusätzliche Overlap-Icons für Geräte</span></span>
|
||||
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> └── PlusRoundIcon.js</span>
|
||||
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> mainComponent/ <span class="co"># Hauptkomponenten für Karteninitialisierung</span></span>
|
||||
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> ├── MapComponent.js</span>
|
||||
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> └── hooks/</span>
|
||||
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> └── useInitializeMap.js</span>
|
||||
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> pois/ <span class="co"># POI-spezifische Modale</span></span>
|
||||
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> ├── AddPOIModal.js</span>
|
||||
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> └── PoiUpdateModal.js</span>
|
||||
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a><span class="ex">├──</span> uiWidgets/ <span class="co"># UI-Widgets</span></span>
|
||||
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> ├── CoordinateInput.js</span>
|
||||
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> ├── VersionInfoModal.js</span>
|
||||
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> ├── TestScript.js</span>
|
||||
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> └── mapLayersControlPanel/</span>
|
||||
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> ├── EditModeToggle.js</span>
|
||||
<span id="cb1-32"><a href="#cb1-32" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> └── MapLayersControlPanel.js</span></code></pre></div>
|
||||
<hr />
|
||||
<h2 id="beschreibung-der-hauptbereiche">🔎 Beschreibung der
|
||||
Hauptbereiche</h2>
|
||||
<h3 id="contextmenu"><code>contextmenu/</code></h3>
|
||||
<p>Rechtsklick-Menüs für Marker, POIs, Polylinien. Steuert Anzeige &
|
||||
Verhalten.</p>
|
||||
<h3 id="gispolylines"><code>gisPolylines/</code></h3>
|
||||
<p>Komponenten für das Zeichnen, Bearbeiten und Interagieren mit
|
||||
Linien/Strecken.</p>
|
||||
<h3 id="maincomponent"><code>mainComponent/</code></h3>
|
||||
<p>Zentrale Leaflet-Map-Logik & Initialisierung via
|
||||
<code>MapComponent</code> und <code>useInitializeMap</code>.</p>
|
||||
<h3 id="pois"><code>pois/</code></h3>
|
||||
<p>Modale für das Hinzufügen und Bearbeiten von POIs (Points of
|
||||
Interest).</p>
|
||||
<h3 id="uiwidgets"><code>uiWidgets/</code></h3>
|
||||
<p>Komponenten wie Eingabefelder für Koordinaten-Suche, Infoboxen und
|
||||
Control Panel für Geräte Layers .</p>
|
||||
<hr />
|
||||
<h2 id="besonderheiten">✅ Besonderheiten</h2>
|
||||
<ul>
|
||||
<li>Verwendet <strong>Tailwind CSS</strong> für Styling</li>
|
||||
<li>Integration mit Redux, Leaflet, OverlappingMarkerSpiderfier</li>
|
||||
<li>Vollständig modular & testbar aufgebaut</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,59 @@
|
||||
<!-- /docs/components/TestScript.md -->
|
||||
<h1 id="testscript.js">🧪 TestScript.js</h1>
|
||||
<p>Ein einfaches React-Testskript zur Laufzeitüberprüfung von
|
||||
Codefragmenten in <code>setupPolylines.js</code>.</p>
|
||||
<h2 id="zweck">Zweck</h2>
|
||||
<p>Dieses Skript durchsucht die geladene
|
||||
<code>setupPolylines.js</code>-Datei (per <code>raw-loader</code>) nach
|
||||
bestimmten Kontextmenüeinträgen:</p>
|
||||
<ul>
|
||||
<li>„Stützpunkt entfernen“</li>
|
||||
<li>„Stützpunkt hinzufügen“</li>
|
||||
</ul>
|
||||
<h2 id="vorgehen">Vorgehen</h2>
|
||||
<ul>
|
||||
<li>Lädt <code>setupPolylines.js</code> als Text via
|
||||
<code>!!raw-loader!</code></li>
|
||||
<li>Nutzt reguläre Ausdrücke zur Prüfung</li>
|
||||
<li>Gibt Ergebnisse farblich formatiert in der Konsole aus</li>
|
||||
</ul>
|
||||
<h2 id="ausgaben">Ausgaben</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Zustand</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>✅ Test bestanden</td>
|
||||
<td>Der gesuchte Text wurde gefunden</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>❌ Test fehlgeschlagen</td>
|
||||
<td>Der gesuchte Text fehlt in der Datei</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ℹ️ Info</td>
|
||||
<td>Neutrale Zusatzinformationen in der Konsole</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="besonderheiten">Besonderheiten</h2>
|
||||
<ul>
|
||||
<li>Kein visuelles UI – Rückmeldung nur über
|
||||
<code>console.log</code></li>
|
||||
<li>Eignet sich als Dev-Hilfe für Refactoring oder PR-Checks</li>
|
||||
</ul>
|
||||
<h2 id="beispielausgabe">Beispielausgabe</h2>
|
||||
<pre class="plaintext"><code>✔ Test bestanden: Der Text für 'Stützpunkt entfernen' wurde gefunden.
|
||||
ℹ️ Info: Überprüfung abgeschlossen.</code></pre>
|
||||
<h2 id="hinweise">Hinweise</h2>
|
||||
<ul>
|
||||
<li>Wird automatisch beim Mount (via <code>useEffect</code>)
|
||||
ausgeführt</li>
|
||||
<li><code>return null</code> → keine sichtbare Ausgabe</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,61 @@
|
||||
<!-- /docs/components/contextmenu/CoordinatePopup.md -->
|
||||
<h1 id="coordinatepopup.js">📌 CoordinatePopup.js</h1>
|
||||
<p>Zeigt ein modales Fenster mit Koordinateninformationen an, z. B. aus
|
||||
einem Kontextmenü heraus.</p>
|
||||
<figure>
|
||||
<img src="../../screenshots/CoordinatePopup.png"
|
||||
alt="CoordinatePopup" />
|
||||
<figcaption aria-hidden="true">CoordinatePopup</figcaption>
|
||||
</figure>
|
||||
<h2 id="features">Features</h2>
|
||||
<ul>
|
||||
<li>Darstellung eines Koordinatenwerts (<code>lat,lng</code>)</li>
|
||||
<li>Kopieren in die Zwischenablage (Clipboard API + Fallback)</li>
|
||||
<li>Modal zentriert mit Tailwind CSS</li>
|
||||
<li>Zwei Buttons: „Kopieren“ und „Schließen“</li>
|
||||
</ul>
|
||||
<h2 id="props">Props</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 19%" />
|
||||
<col style="width: 14%" />
|
||||
<col style="width: 65%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Typ</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>isOpen</code></td>
|
||||
<td><code>boolean</code></td>
|
||||
<td>Steuert Sichtbarkeit des Modals</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>coordinates</code></td>
|
||||
<td><code>string</code></td>
|
||||
<td>Zu zeigende Koordinaten (z. B. <code>"53.2,8.1"</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>onClose</code></td>
|
||||
<td><code>function</code></td>
|
||||
<td>Wird bei Klick auf „Schließen“ ausgelöst</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="design">Design</h2>
|
||||
<ul>
|
||||
<li>Tailwind-Klassen für zentriertes Layout (<code>fixed</code>,
|
||||
<code>inset-0</code>, <code>z-50</code>)</li>
|
||||
<li>Leicht animierter Button-Hover</li>
|
||||
</ul>
|
||||
<h2 id="interne-logik">Interne Logik</h2>
|
||||
<ul>
|
||||
<li>Nutzt <code>navigator.clipboard.writeText</code> oder Fallback mit
|
||||
<code>document.execCommand("copy")</code></li>
|
||||
<li>Stoppt Event-Bubbling, um Klick außerhalb zu erkennen</li>
|
||||
</ul>
|
||||
<p>🔙 <a href="./README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,62 @@
|
||||
<!-- /docs/components/contextmenu/README.md temp branch damit develop zurücksetzt-->
|
||||
<h1 id="contextmenu-kontextmenü-komponenten">🖱️
|
||||
<code>contextmenu/</code> – Kontextmenü-Komponenten</h1>
|
||||
<p>Dieses Verzeichnis enthält Komponenten und Hooks zur Anzeige und
|
||||
Steuerung von Kontextmenüs in der Leaflet-Kartenanwendung. Sie dienen
|
||||
der Interaktion mit POIs, Koordinaten und Layer-Objekten per
|
||||
Rechtsklick.</p>
|
||||
<h2 id="usemapcontextmenu"><img
|
||||
src="../../screenshots/useMapContextMenu.png"
|
||||
alt="useMapContextMenu" /></h2>
|
||||
<h2 id="enthaltene-dateien">📂 Enthaltene Dateien</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 40%" />
|
||||
<col style="width: 59%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Datei</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a
|
||||
href="./CoordinatePopup.md"><code>CoordinatePopup.js</code></a></td>
|
||||
<td>Zeigt ein kleines Kontextfenster mit Koordinaten und
|
||||
Copy-Funktion</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a
|
||||
href="./useMapContextMenu.md"><code>useMapContextMenu.js</code></a></td>
|
||||
<td>Hook zur Initialisierung und Verwaltung des Kontextmenüs auf der
|
||||
Karte</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="verwendung">🔄 Verwendung</h2>
|
||||
<p>Diese Komponenten sind typischerweise eingebunden in:</p>
|
||||
<ul>
|
||||
<li><a
|
||||
href="../mainComponent/MapComponent.md"><code>MapComponent.js</code></a></li>
|
||||
<li><a
|
||||
href="../gisPolylines/PolylineContextMenu.md"><code>PolylineContextMenu.js</code></a></li>
|
||||
<li>Marker- und Linienfunktionen aus <code>setupDevices</code>,
|
||||
<code>setupPolylines</code></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="ziel">🎯 Ziel</h2>
|
||||
<p>Ermöglicht einfache Benutzerinteraktion mit:</p>
|
||||
<ul>
|
||||
<li>Geräten</li>
|
||||
<li>Koordinaten</li>
|
||||
<li>POIs</li>
|
||||
<li>Streckenabschnitten</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="weitere-dokumentation">📚 Weitere Dokumentation</h2>
|
||||
<p>Alle Markdown-Dateien für Komponenten befinden sich im
|
||||
<code>/docs/components/contextmenu/</code> Verzeichnis.</p>
|
||||
<p>🔙 <a href="../README.md">Zurück zu <code>components</code></a></p>
|
||||
@@ -0,0 +1,67 @@
|
||||
<!-- /docs/components/contextmenu/useMapContextMenu.md -->
|
||||
<h1 id="usemapcontextmenu.js">🖱️ useMapContextMenu.js</h1>
|
||||
<p>Initialisiert Kontextmenüeinträge für die Leaflet-Karte.<br />
|
||||
Wird typischerweise in <code>initializeMap()</code> oder
|
||||
<code>MapComponent</code> verwendet.</p>
|
||||
<figure>
|
||||
<img src="../../screenshots/useMapContextMenu.png"
|
||||
alt="useMapContextMenu" />
|
||||
<figcaption aria-hidden="true">useMapContextMenu</figcaption>
|
||||
</figure>
|
||||
<h2 id="kontextmenüeinträge">Kontextmenüeinträge</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 29%" />
|
||||
<col style="width: 70%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Eintrag</th>
|
||||
<th>Funktion</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Koordinaten anzeigen</td>
|
||||
<td>Öffnet <code>CoordinatePopup</code> mit aktueller Position</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Reinzoomen</td>
|
||||
<td>Zoomt 3 Stufen näher an das Zentrum heran</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rauszoomen</td>
|
||||
<td>Zoomt 3 Stufen heraus</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Hier zentrieren</td>
|
||||
<td>Verschiebt Kartenzentrum auf Klickposition</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>POI hinzufügen</td>
|
||||
<td>(nur bei <code>editMode=true</code>) öffnet POI-Dialog</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="parameter">Parameter</h2>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">addItemsToMapContextMenu</span>(</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> map<span class="op">,</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> menuItemAdded<span class="op">,</span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> setMenuItemAdded<span class="op">,</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> setShowCoordinatesModal<span class="op">,</span></span>
|
||||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a> setShowPoiModal<span class="op">,</span></span>
|
||||
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a> setPopupCoordinates<span class="op">,</span></span>
|
||||
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> openPopupWithCoordinates</span>
|
||||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>)<span class="op">;</span></span></code></pre></div>
|
||||
<h2 id="besonderheiten">Besonderheiten</h2>
|
||||
<ul>
|
||||
<li><p>Prüft auf <code>localStorage.editMode</code> für
|
||||
POI-Eintrag</p></li>
|
||||
<li><p>FlyTo-Animationen für Zoom-Vorgänge mit dynamischer
|
||||
Dauer</p></li>
|
||||
<li><p>Modularer Aufbau: <code>openPopupWithCoordinates</code> wird
|
||||
extern übergeben</p>
|
||||
<p>🔙 <a href="./README.md">Zurück zu contextmenu</a></p></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,67 @@
|
||||
<!-- /docs/components/gisPolylines/PolylineContextMenu.md -->
|
||||
<h1 id="polylinecontextmenu.js">📐 PolylineContextMenu.js</h1>
|
||||
<p>Ein einfaches benutzerdefiniertes Kontextmenü zur Interaktion mit
|
||||
Linien (Polylinien) auf der Karte.</p>
|
||||
<figure>
|
||||
<img src="../../screenshots/PolylineContextMenu.png"
|
||||
alt="GIS Ployline contextmenu" />
|
||||
<figcaption aria-hidden="true">GIS Ployline contextmenu</figcaption>
|
||||
</figure>
|
||||
<h2 id="zweck">Zweck</h2>
|
||||
<p>Das Menü erlaubt folgende Interaktionen:</p>
|
||||
<ul>
|
||||
<li>➕ „Stützpunkt hinzufügen“</li>
|
||||
<li>➖ „Stützpunkt entfernen“</li>
|
||||
<li>❌ „Schließen“</li>
|
||||
</ul>
|
||||
<p>Wird dynamisch positioniert anhand der Klickkoordinaten
|
||||
(<code>position.x</code>, <code>position.y</code>).</p>
|
||||
<h2 id="props">Props</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 19%" />
|
||||
<col style="width: 12%" />
|
||||
<col style="width: 67%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Prop</th>
|
||||
<th>Typ</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>position</code></td>
|
||||
<td><code>{x, y}</code></td>
|
||||
<td>Position in Pixelkoordinaten (z. B. von Mausereignis)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>onAddPoint</code></td>
|
||||
<td><code>function</code></td>
|
||||
<td>Handler für „Stützpunkt hinzufügen“</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>onRemovePoint</code></td>
|
||||
<td><code>function</code></td>
|
||||
<td>Handler für „Stützpunkt entfernen“</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>onClose</code></td>
|
||||
<td><code>function</code></td>
|
||||
<td>Handler zum Schließen des Menüs</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="styling">Styling</h2>
|
||||
<ul>
|
||||
<li>Absolut positioniertes <code>div</code></li>
|
||||
<li>Weißer Hintergrund, schwarzer Rahmen</li>
|
||||
<li>Kein Tailwind – purer Inline-Style</li>
|
||||
</ul>
|
||||
<h2 id="verwendung">Verwendung</h2>
|
||||
<p>Eingebettet z. B. in <code>setupPolylines.js</code> oder
|
||||
<code>PolylineLayerManager</code>, um rechte Mausklicks auf Linien zu
|
||||
behandeln.</p>
|
||||
<hr />
|
||||
<p><a href="../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,164 @@
|
||||
<!-- /docs/components/gisPolylines/README.md -->
|
||||
<h1 id="übersicht-docscomponentsgispolylines">📄 Übersicht:
|
||||
docs/components/gisPolylines</h1>
|
||||
<p>Diese Komponente verwaltet die Darstellung und Interaktion von
|
||||
GIS-Polylinien in der Leaflet-Karte.<br />
|
||||
Sie kombiniert Statusdaten, statische Linien und Stationsdaten zu
|
||||
Tooltips und Farben.</p>
|
||||
<hr />
|
||||
<h2 id="data-flow-diagram">🧬 Data Flow Diagram</h2>
|
||||
<p>Dieses Diagramm zeigt den <strong>Datenfluss</strong> zwischen den
|
||||
Redux-Slices, Thunks, Service-Funktionen und den
|
||||
React-Komponenten,<br />
|
||||
die für die Anzeige der <strong>GIS-Polylinien</strong> zuständig
|
||||
sind.</p>
|
||||
<h3 id="ablauf-erklärt">📖 Ablauf erklärt</h3>
|
||||
<ol type="1">
|
||||
<li><strong>Beim Laden der Seite</strong> ruft die Hook
|
||||
<code>useLineData</code> mehrere Thunks auf:
|
||||
<ul>
|
||||
<li>Diese laden Linien, Statusdaten und Stationsdaten über entsprechende
|
||||
Service-Funktionen.</li>
|
||||
</ul></li>
|
||||
<li>Die Thunks speichern die geladenen Daten in Redux-Slices.</li>
|
||||
<li><code>useLineData</code> liest diese Redux-Daten aus und kombiniert
|
||||
sie:
|
||||
<ul>
|
||||
<li>Zuordnung nach <code>idLD</code> und <code>Modul</code></li>
|
||||
</ul></li>
|
||||
<li>Daraus entsteht:
|
||||
<ul>
|
||||
<li>Eine Prioritätsfarbe für die Linie</li>
|
||||
<li>Ein Tooltip-HTML mit Modulname, Slot, Station (LD_Name) und
|
||||
Statusmeldungen.</li>
|
||||
</ul></li>
|
||||
<li>Diese Daten werden weitergegeben an:
|
||||
<ul>
|
||||
<li><code>generateLineTooltipContent</code> → für Tooltips bei
|
||||
Hover</li>
|
||||
<li><code>PolylineContextMenu</code> → für Kontextmenü bei
|
||||
Rechtsklick</li>
|
||||
<li>Leaflet Polyline-Komponente → für farbige Darstellung</li>
|
||||
</ul></li>
|
||||
</ol>
|
||||
<pre class="mermaid"><code>graph TD
|
||||
|
||||
subgraph Redux Store
|
||||
A1[gisLinesFromDatabase Slice]
|
||||
A2[gisLinesStatusFromWebservice Slice]
|
||||
A3[gisStationsStaticDistrict Slice]
|
||||
end
|
||||
|
||||
subgraph Thunks
|
||||
T1[fetchGisLinesThunk]
|
||||
T2[fetchGisLinesStatusThunk]
|
||||
T3[fetchGisStationsStaticDistrictThunk]
|
||||
end
|
||||
|
||||
subgraph Services
|
||||
S1[fetchGisLinesService]
|
||||
S2[fetchGisLinesStatusService]
|
||||
S3[fetchGisStationsStaticDistrictService]
|
||||
end
|
||||
|
||||
subgraph Komponenten
|
||||
C1[useLineData Hook]
|
||||
C2[generateLineTooltipContent]
|
||||
C3[PolylineContextMenu.js]
|
||||
C4[Leaflet Polyline Rendering]
|
||||
end
|
||||
|
||||
T1 --> S1
|
||||
T2 --> S2
|
||||
T3 --> S3
|
||||
|
||||
T1 --> A1
|
||||
T2 --> A2
|
||||
T3 --> A3
|
||||
|
||||
A1 --> C1
|
||||
A2 --> C1
|
||||
A3 --> C1
|
||||
|
||||
C1 --> C2
|
||||
C2 --> C4
|
||||
C1 --> C3</code></pre>
|
||||
<hr />
|
||||
<h2 id="wichtige-dateien">📦 Wichtige Dateien</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 51%" />
|
||||
<col style="width: 48%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Datei</th>
|
||||
<th>Zweck</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><a
|
||||
href="tooltip/useLineData.js"><code>useLineData.js</code></a></td>
|
||||
<td>Holt Linien-, Status- und Stationsdaten aus Redux und kombiniert
|
||||
sie</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a
|
||||
href="tooltip/generateLineTooltipContent.js"><code>generateLineTooltipContent.js</code></a></td>
|
||||
<td>Baut HTML für die Tooltips</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a
|
||||
href="PolylineContextMenu.md"><code>PolylineContextMenu.js</code></a></td>
|
||||
<td>Kontextmenü zur Interaktion mit Linien</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<figure>
|
||||
<img src="../../screenshots/gisPolylines.png" alt="GIS Polylines" />
|
||||
<figcaption aria-hidden="true">GIS Polylines</figcaption>
|
||||
</figure>
|
||||
<hr />
|
||||
<p><a href="../../README.md">Zurück zur Übersicht</a></p>
|
||||
<hr />
|
||||
<h2 id="technischer-hintergrund-für-einsteiger">📘 Technischer
|
||||
Hintergrund für Einsteiger</h2>
|
||||
<p>Diese Komponente verbindet Daten aus <strong>zwei unterschiedlichen
|
||||
Systemen</strong>:</p>
|
||||
<ol type="1">
|
||||
<li><strong>NodeMap App (Next.js API)</strong><br />
|
||||
→ liefert die <strong>Geometrie der Linien</strong> direkt aus der
|
||||
Datenbank (ohne Webservice).</li>
|
||||
<li><strong>TALAS.web WebService</strong><br />
|
||||
→ liefert <strong>Statusinformationen und Stationsnamen</strong>
|
||||
(LD_Name).</li>
|
||||
</ol>
|
||||
<h3 id="ablauf-im-detail">🔄 Ablauf im Detail</h3>
|
||||
<ul>
|
||||
<li><strong>Liniengeometrie</strong> (<code>idLD</code>,
|
||||
<code>idModul</code>, <code>points</code>) kommt über
|
||||
<code>fetchGisLinesThunk</code> aus der Datenbank.</li>
|
||||
<li><strong>Statusinformationen</strong> (Meldungen, Farben, Modulname,
|
||||
Slot) kommen über <code>fetchGisLinesStatusThunk</code>.</li>
|
||||
<li><strong>Stationsnamen</strong> (LD_Name) kommen über
|
||||
<code>fetchGisStationsStaticDistrictThunk</code>.</li>
|
||||
<li>Die Hook <code>useLineData.js</code> verbindet alle Infos → erzeugt
|
||||
Tooltip-HTML & Farblogik.</li>
|
||||
<li><code>generateLineTooltipContent.js</code> erstellt den konkreten
|
||||
Tooltip-HTML-String.</li>
|
||||
</ul>
|
||||
<h3 id="wichtig-für-debugging">🧠 Wichtig für Debugging</h3>
|
||||
<ul>
|
||||
<li><strong>Zuordnung</strong> erfolgt immer über <code>idLD</code> und
|
||||
<code>Modul</code>.</li>
|
||||
<li>Stationen findest du im Slice
|
||||
<code>gisStationsStaticDistrict.Points[] → LD_Name</code></li>
|
||||
<li>Linien findest du im Slice <code>gisLinesFromDatabase</code></li>
|
||||
<li>Statusinfos findest du im Slice
|
||||
<code>gisLinesStatusFromWebservice</code></li>
|
||||
</ul>
|
||||
<p>🛠 <strong>Fehler wie “Station: N/A”</strong> entstehen, wenn
|
||||
<code>idLD</code> im Status vorhanden ist, aber keine passende Station
|
||||
in <code>gisStationsStaticDistrict</code> gefunden wurde.</p>
|
||||
@@ -0,0 +1,19 @@
|
||||
<!-- /docs/components/gisPolylines/icons/CircleIcon.md -->
|
||||
<h1 id="circleicon.js">🔘 CircleIcon.js</h1>
|
||||
<p>Ein einfacher, grauer runder Marker als Stützpunkt in einer
|
||||
Polyline.</p>
|
||||
<figure>
|
||||
<img src="../../../screenshots/CircleIcon.png" alt="CircleIcon" />
|
||||
<figcaption aria-hidden="true">CircleIcon</figcaption>
|
||||
</figure>
|
||||
<h2 id="eigenschaften">Eigenschaften</h2>
|
||||
<ul>
|
||||
<li>Stil: grauer Kreis mit schwarzem Rand</li>
|
||||
<li>Größe: 10×10 px, IconSize 25×25 px (wegen Klickfläche)</li>
|
||||
<li>Klasse: <code>custom-circle-icon</code></li>
|
||||
</ul>
|
||||
<h2 id="verwendung">Verwendung</h2>
|
||||
<p>Wird in Polylinien als Zwischenpunkt gesetzt. Inaktiv, aber
|
||||
sichtbar.</p>
|
||||
<hr />
|
||||
<p><a href="../../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,18 @@
|
||||
<!-- /docs/components/gisPolylines/icons/EndIcon.md -->
|
||||
<h1 id="endicon.js">🔲 EndIcon.js</h1>
|
||||
<p>Ein Viereck zur Markierung des Endpunkts einer Polyline.</p>
|
||||
<figure>
|
||||
<img src="../../../screenshots/EndIcon.png" alt="EndIcon" />
|
||||
<figcaption aria-hidden="true">EndIcon</figcaption>
|
||||
</figure>
|
||||
<h2 id="eigenschaften">Eigenschaften</h2>
|
||||
<ul>
|
||||
<li>Stil: graues Quadrat mit schwarzem Rand</li>
|
||||
<li>Größe: 14×14 px</li>
|
||||
<li>Klasse: <code>custom-end-icon</code></li>
|
||||
</ul>
|
||||
<h2 id="verwendung">Verwendung</h2>
|
||||
<p>Wird am letzten Punkt einer Linie gesetzt, z. B.
|
||||
<code>lineData.coordinates[line.length - 1]</code></p>
|
||||
<hr />
|
||||
<p><a href="../../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,13 @@
|
||||
<h1 id="übersicht-docscomponentsgispolylinesicons">📄 Übersicht:
|
||||
docs/components/gisPolylines/icons</h1>
|
||||
<ul>
|
||||
<li><a href="CircleIcon.md">CircleIcon</a></li>
|
||||
<li><a href="EndIcon.md">EndIcon</a></li>
|
||||
<li><a href="StartIcon.md">StartIcon</a></li>
|
||||
<li><a href="SupportPointIcons.md">SupportPointIcons</a></li>
|
||||
</ul>
|
||||
<figure>
|
||||
<img src="../../../screenshots/gisPolylinesIcons.png"
|
||||
alt="gisPolylinesIcons" />
|
||||
<figcaption aria-hidden="true">gisPolylinesIcons</figcaption>
|
||||
</figure>
|
||||
@@ -0,0 +1,17 @@
|
||||
<!-- /docs/components/gisPolylines/icons/StartIcon.md -->
|
||||
<h1 id="starticon.js">🔺 StartIcon.js</h1>
|
||||
<p>Ein SVG-Dreieck zur Markierung des Startpunkts einer Polyline.</p>
|
||||
<figure>
|
||||
<img src="../../../screenshots/StartIcon.png" alt="StartIcon" />
|
||||
<figcaption aria-hidden="true">StartIcon</figcaption>
|
||||
</figure>
|
||||
<h2 id="eigenschaften">Eigenschaften</h2>
|
||||
<ul>
|
||||
<li>Schwarzes Dreieck mit grauem Overlay (Polygon SVG)</li>
|
||||
<li>Größe: 18×18 px</li>
|
||||
<li>Klasse: <code>custom-start-icon</code></li>
|
||||
</ul>
|
||||
<h2 id="verwendung">Verwendung</h2>
|
||||
<p>Wird am ersten Punkt einer Polyline platziert.</p>
|
||||
<hr />
|
||||
<p><a href="../../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,26 @@
|
||||
<!-- /docs/components/gisPolylines/icons/SupportPointIcons.md -->
|
||||
<h1 id="supportpointicons.js">➕➖ SupportPointIcons.js</h1>
|
||||
<p>Definiert zwei Icons für interaktive Stützpunkte in einer
|
||||
Polyline:</p>
|
||||
<figure>
|
||||
<img src="../../../screenshots/CircleIcon.png" alt="CircleIcon" />
|
||||
<figcaption aria-hidden="true">CircleIcon</figcaption>
|
||||
</figure>
|
||||
<h2 id="addsupportpointicon">AddSupportPointIcon</h2>
|
||||
<ul>
|
||||
<li>Grüner Kreis mit weißem Rand und Pluszeichen</li>
|
||||
<li><code>iconSize</code>: 24×24 px</li>
|
||||
</ul>
|
||||
<h2 id="removesupportpointicon">RemoveSupportPointIcon</h2>
|
||||
<ul>
|
||||
<li>Roter Kreis mit weißem Rand und Minuszeichen</li>
|
||||
<li><code>iconSize</code>: 24×24 px</li>
|
||||
</ul>
|
||||
<h2 id="verwendung">Verwendung</h2>
|
||||
<ul>
|
||||
<li>Hinzufügen/Entfernen von Zwischenpunkten in der Bearbeitungsansicht
|
||||
(editMode)</li>
|
||||
<li>Marker erscheinen z. B. bei Maus-Hover oder per Kontextmenü</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,55 @@
|
||||
<!-- /docs/components/icons/devices/overlapping/PlusRoundIcon.md -->
|
||||
<h1 id="plusroundicon.js">➕ PlusRoundIcon.js</h1>
|
||||
<p>Ein einfaches Leaflet-Icon, das ein rundes Pluszeichen
|
||||
darstellt.<br />
|
||||
Wird für zusätzliche UI-Markierungen auf Geräten oder überlappenden
|
||||
Icons verwendet.</p>
|
||||
<figure>
|
||||
<img src="../../../../screenshots/PlusRoundIcon.png"
|
||||
alt="PlusRoundIcon" />
|
||||
<figcaption aria-hidden="true">PlusRoundIcon</figcaption>
|
||||
</figure>
|
||||
<h2 id="eigenschaften">Eigenschaften</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Attribut</th>
|
||||
<th>Wert</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>iconUrl</code></td>
|
||||
<td><code>/img/plus_round.png</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>iconSize</code></td>
|
||||
<td><code>[22, 22]</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>iconAnchor</code></td>
|
||||
<td><code>[25, 55]</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>className</code></td>
|
||||
<td><code>absolute top-0 left-0 z-10</code> (Tailwind)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="verwendung">Verwendung</h2>
|
||||
<ul>
|
||||
<li>Dient als Overlay-Symbol, z. B. für „Gerät hinzufügen“ oder zur
|
||||
Darstellung über bestehenden Icons</li>
|
||||
<li>Durch die <code>z-10</code>-Klasse immer im Vordergrund
|
||||
sichtbar</li>
|
||||
<li>Kombinierbar mit OverlappingMarkerSpiderfier oder
|
||||
Marker-Gruppen</li>
|
||||
</ul>
|
||||
<h2 id="hinweis">Hinweis</h2>
|
||||
<ul>
|
||||
<li>Die Bilddatei <code>/img/plus_round.png</code> muss vorhanden
|
||||
sein</li>
|
||||
<li>Kann bei Bedarf dynamisch durch ein anderes Icon ersetzt werden</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../../../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,10 @@
|
||||
<h1 id="übersicht-docscomponentsiconsdevicesoverlapping">📄 Übersicht:
|
||||
docs/components/icons/devices/overlapping</h1>
|
||||
<ul>
|
||||
<li><a href="PlusRoundIcon.md">PlusRoundIcon</a></li>
|
||||
</ul>
|
||||
<figure>
|
||||
<img src="../../../../screenshots/PlusRoundIcon.png"
|
||||
alt="PlusRoundIcon" />
|
||||
<figcaption aria-hidden="true">PlusRoundIcon</figcaption>
|
||||
</figure>
|
||||
@@ -0,0 +1,85 @@
|
||||
<!-- /docs/components/mainComponent/MapComponent.md -->
|
||||
<h1 id="mapcomponent.js">🗺️ MapComponent.js</h1>
|
||||
<p>Die zentrale React-Komponente zur Darstellung und Steuerung der
|
||||
Leaflet-Karte.<br />
|
||||
Bindet alle Marker, Layer, POIs, Linien und das Kontextmenü dynamisch
|
||||
ein.</p>
|
||||
<figure>
|
||||
<img src="../../screenshots/overview1.png" alt="Overview" />
|
||||
<figcaption aria-hidden="true">Overview</figcaption>
|
||||
</figure>
|
||||
<h2 id="zweck">🎯 Zweck</h2>
|
||||
<ul>
|
||||
<li>Initialisiert die Leaflet-Karte (<code>useInitializeMap</code>)</li>
|
||||
<li>Bindet Marker & Polylinien über Redux und eigene Hooks</li>
|
||||
<li>Steuerung über Redux-Slices wie <code>selectedArea</code>,
|
||||
<code>zoomTrigger</code>, <code>polylineVisible</code></li>
|
||||
<li>Kontextmenüs für Karte, POIs, Polylinien</li>
|
||||
<li>Unterstützung für Editierfunktionen über <code>editMode</code>
|
||||
(localStorage)</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="hauptbestandteile">🧱 Hauptbestandteile</h2>
|
||||
<ul>
|
||||
<li><code>useEffect</code>-Hooks zum Laden und Aktualisieren von:
|
||||
<ul>
|
||||
<li>Kartenlayern, POIs, Linien, Rechte, Systeme, Positionen</li>
|
||||
</ul></li>
|
||||
<li>Marker-Logik für 15+ Layergruppen (TALAS, ECI, GMA, etc.)</li>
|
||||
<li>Marker-Overlapping mit <code>OverlappingMarkerSpiderfier</code></li>
|
||||
<li>Kontextmenüs (Karte & Polylinie)</li>
|
||||
<li>UI-Komponenten:
|
||||
<ul>
|
||||
<li><code>MapLayersControlPanel</code></li>
|
||||
<li><code>CoordinateInput</code></li>
|
||||
<li><code>CoordinatePopup</code></li>
|
||||
<li><code>AddPOIModal</code>, <code>PoiUpdateModal</code>,
|
||||
<code>VersionInfoModal</code></li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="zustand-redux">🧠 Zustand & Redux</h2>
|
||||
<p>Verwendet umfangreiche Redux-Slices zur Steuerung von:</p>
|
||||
<ul>
|
||||
<li><p>Linienstatus, POI-Typen, POI-Icons</p></li>
|
||||
<li><p>Gerätesysteme & Rechte</p></li>
|
||||
<li><p>Sichtbarkeit einzelner Layergruppen</p></li>
|
||||
<li><p>Aktuelle Selektion (Area, Gerät, POI)</p>
|
||||
<figure>
|
||||
<img src="../../screenshots/ReaduxSlices.png" alt="ReduxSlices" />
|
||||
<figcaption aria-hidden="true">ReduxSlices</figcaption>
|
||||
</figure></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="lokale-steuerung">🔧 Lokale Steuerung</h2>
|
||||
<ul>
|
||||
<li><p>EditMode wird aus <code>localStorage</code> gelesen</p></li>
|
||||
<li><p>Karte speichert Zoom & Center dauerhaft im Browser</p></li>
|
||||
<li><p>Kontextmenü-Einträge ändern sich je nach Rechten & Modus</p>
|
||||
<figure>
|
||||
<img src="../../screenshots/LocalStorage.png" alt="LocalStorage" />
|
||||
<figcaption aria-hidden="true">LocalStorage</figcaption>
|
||||
</figure></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="besonderheiten">🧪 Besonderheiten</h2>
|
||||
<ul>
|
||||
<li>Fehlerbehandlung für <code>contextmenu</code>-Fehler eingebaut →
|
||||
Auto-Neuladen</li>
|
||||
<li>Alle Marker-Updates mit Overlapping-Check &
|
||||
Z-Index-Steuerung</li>
|
||||
<li>Linien enthalten dynamische Tooltips mit
|
||||
<code>tooltipContents</code></li>
|
||||
<li>Initiale Datenabfrage über Redux-Thunk-Kaskade</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="abhängigkeiten">🔗 Abhängigkeiten</h2>
|
||||
<ul>
|
||||
<li>Leaflet, OverlappingMarkerSpiderfier, React-Toastify</li>
|
||||
<li>Redux Toolkit (Thunks + Selectors)</li>
|
||||
<li>Tailwind CSS für visuelles Layout</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p>📄 Pfad: <code>/components/mainComponent/MapComponent.js</code></p>
|
||||
<hr />
|
||||
<p><a href="../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,13 @@
|
||||
<h1 id="übersicht-docscomponentsmaincomponent">📄 Übersicht:
|
||||
docs/components/mainComponent</h1>
|
||||
<p>Die zentrale React-Komponente zur Darstellung und Steuerung der
|
||||
Leaflet-Karte.<br />
|
||||
Bindet alle Marker, Layer, POIs, Linien und das Kontextmenü dynamisch
|
||||
ein.</p>
|
||||
<ul>
|
||||
<li><a href="MapComponent.md">MapComponent</a></li>
|
||||
</ul>
|
||||
<figure>
|
||||
<img src="../../screenshots/overview1.png" alt="Overview" />
|
||||
<figcaption aria-hidden="true">Overview</figcaption>
|
||||
</figure>
|
||||
@@ -0,0 +1,5 @@
|
||||
<h1 id="übersicht-docscomponentsmaincomponenthooks">📄 Übersicht:
|
||||
docs/components/mainComponent/hooks</h1>
|
||||
<ul>
|
||||
<li><a href="useInitializeMap.md">useInitializeMap</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,90 @@
|
||||
<!-- /docs/components/mainComponent/hooks/useInitializeMap.md -->
|
||||
<h1 id="useinitializemap.js">🪄 useInitializeMap.js</h1>
|
||||
<p>Custom React-Hook zur Initialisierung der Leaflet-Karte.<br />
|
||||
Ermöglicht die einfache Übergabe aller nötigen Parameter und abstrahiert
|
||||
die <code>initializeMap(...)</code>-Logik.</p>
|
||||
<hr />
|
||||
<h2 id="zweck">📦 Zweck</h2>
|
||||
<ul>
|
||||
<li>Führt <code>initializeMap(...)</code> nur <strong>einmal</strong>
|
||||
aus, wenn <code>mapRef</code> existiert und
|
||||
<code>map === null</code></li>
|
||||
<li>Kapselt die Initialisierung in ein <code>useEffect</code></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="parameter">🔧 Parameter</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 26%" />
|
||||
<col style="width: 21%" />
|
||||
<col style="width: 51%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Typ</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>map</code></td>
|
||||
<td><code>LeafletMap</code> (Zustand)</td>
|
||||
<td>Wird initialisiert, wenn <code>null</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>mapRef</code></td>
|
||||
<td><code>ref</code></td>
|
||||
<td>Referenz auf <code><div id="map"></code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>setMap</code></td>
|
||||
<td><code>function</code></td>
|
||||
<td>Callback zum Setzen der Karteninstanz</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>setOms</code></td>
|
||||
<td><code>function</code></td>
|
||||
<td>Callback für OverlappingMarkerSpiderfier</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>setMenuItemAdded</code></td>
|
||||
<td><code>function</code></td>
|
||||
<td>Wird genutzt, um mehrfaches Menü-Setup zu verhindern</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>addItemsToMapContextMenu</code></td>
|
||||
<td><code>function</code></td>
|
||||
<td>Logik zum Hinzufügen von Kontextmenüeinträgen</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>hasRights</code></td>
|
||||
<td><code>boolean</code></td>
|
||||
<td>Steuerung, ob POI-Menüs angezeigt werden dürfen</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>setPolylineEventsDisabled</code></td>
|
||||
<td><code>function</code></td>
|
||||
<td>Aktiviert/Deaktiviert Polyline-Events global</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="verwendung">🌐 Verwendung</h2>
|
||||
<p>In <code>MapComponent.js</code>:</p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">useInitializeMap</span>(</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> map<span class="op">,</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> mapRef<span class="op">,</span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> setMap<span class="op">,</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> setOms<span class="op">,</span></span>
|
||||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a> setMenuItemAdded<span class="op">,</span></span>
|
||||
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a> addItemsToMapContextMenu<span class="op">,</span></span>
|
||||
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> hasRights<span class="op">,</span></span>
|
||||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a> value <span class="kw">=></span> <span class="fu">dispatch</span>(<span class="fu">setDisabled</span>(value))</span>
|
||||
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a>)<span class="op">;</span></span></code></pre></div>
|
||||
<hr />
|
||||
<h2 id="quelle">📁 Quelle</h2>
|
||||
<p>Wrappt <code>initializeMap()</code> aus
|
||||
<code>/utils/initializeMap.js</code></p>
|
||||
<hr />
|
||||
<p><a href="../../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,59 @@
|
||||
<!-- /docs/components/pois/AddPOIModal.md -->
|
||||
<h1 id="addpoimodal.js">➕ AddPOIModal.js</h1>
|
||||
<p>Zeigt ein modales Formular an, um einen neuen POI auf der Karte zu
|
||||
erstellen.<br />
|
||||
Die Koordinaten (<code>latlng</code>) werden automatisch übernommen.</p>
|
||||
<figure>
|
||||
<img src="../../screenshots/AddPOIModal.png"
|
||||
alt="POI hinzufügen Modal" />
|
||||
<figcaption aria-hidden="true">POI hinzufügen Modal</figcaption>
|
||||
</figure>
|
||||
<h2 id="funktionen">Funktionen</h2>
|
||||
<ul>
|
||||
<li>POI-Name, Typ und zugehöriges Gerät auswählbar</li>
|
||||
<li>Koordinatenanzeige (<code>lat</code>, <code>lng</code>)</li>
|
||||
<li>Dynamisches Laden der Gerätedaten und POI-Typen</li>
|
||||
<li>Fehleranzeige bei fehlgeschlagenem Speichern</li>
|
||||
<li>Löst <code>addPoiThunk</code> + Refresh-Trigger
|
||||
(<code>incrementTrigger</code>) aus</li>
|
||||
</ul>
|
||||
<h2 id="props">Props</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 14%" />
|
||||
<col style="width: 15%" />
|
||||
<col style="width: 70%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Prop</th>
|
||||
<th>Typ</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>onClose</code></td>
|
||||
<td><code>function</code></td>
|
||||
<td>Schließt das Modal</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>map</code></td>
|
||||
<td><code>Leaflet</code></td>
|
||||
<td>(optional) zum Schließen evtl. offener Popups</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>latlng</code></td>
|
||||
<td><code>object</code></td>
|
||||
<td>Koordinaten für den neuen POI</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="redux">Redux</h2>
|
||||
<ul>
|
||||
<li><code>fetchPoiTypThunk</code>,
|
||||
<code>fetchPoiIconsDataThunk</code></li>
|
||||
<li><code>addPoiThunk</code>, <code>resetAddPoiStatus</code></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,51 @@
|
||||
<!-- /docs/components/pois/PoiUpdateModal.md -->
|
||||
<h1 id="poiupdatemodal.js">✏️ PoiUpdateModal.js</h1>
|
||||
<p>Ein Dialog zur Aktualisierung oder Löschung bestehender POIs.</p>
|
||||
<figure>
|
||||
<img src="../../screenshots/PoiUpdateModal.png"
|
||||
alt="POI Update Modal" />
|
||||
<figcaption aria-hidden="true">POI Update Modal</figcaption>
|
||||
</figure>
|
||||
<h2 id="features">Features</h2>
|
||||
<ul>
|
||||
<li>Zeigt aktuellen Namen, Beschreibung, Gerät und Typ</li>
|
||||
<li>Gerät und Typ auswählbar via <code>react-select</code></li>
|
||||
<li>Unterstützt Löschen und Speichern von POIs</li>
|
||||
<li>Eingebundene Sicherheitsabfrage bei Löschen</li>
|
||||
</ul>
|
||||
<h2 id="props">Props</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Prop</th>
|
||||
<th>Typ</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>onClose</code></td>
|
||||
<td><code>function</code></td>
|
||||
<td>Schließt das Modal</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>poiData</code></td>
|
||||
<td><code>object</code></td>
|
||||
<td>Bestehende POI-Daten zur Bearbeitung</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="redux">Redux</h2>
|
||||
<ul>
|
||||
<li><code>updatePoiThunk</code>, <code>deletePoiThunk</code></li>
|
||||
<li><code>fetchLocationDevicesThunk</code>,
|
||||
<code>fetchPoiTypThunk</code></li>
|
||||
</ul>
|
||||
<h2 id="technisches">Technisches</h2>
|
||||
<ul>
|
||||
<li>Dynamische Gerätegruppenfilterung basierend auf
|
||||
<code>mapLayersVisibility</code></li>
|
||||
<li>Formfelder mit <code>react-select</code> für bessere UX</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,10 @@
|
||||
<h1 id="übersicht-docscomponentspois">📄 Übersicht:
|
||||
docs/components/pois</h1>
|
||||
<ul>
|
||||
<li><a href="AddPOIModal.md">AddPOIModal</a></li>
|
||||
<li><a href="PoiUpdateModal.md">PoiUpdateModal</a></li>
|
||||
</ul>
|
||||
<figure>
|
||||
<img src="../../screenshots/POIs.png" alt="POIs" />
|
||||
<figcaption aria-hidden="true">POIs</figcaption>
|
||||
</figure>
|
||||
@@ -0,0 +1,154 @@
|
||||
<!-- /docs/components/uiWidgets/CoordinateInput.md -->
|
||||
<h1 id="coordinateinput.js">CoordinateInput.js</h1>
|
||||
<p>Die Komponente <code>CoordinateInput</code> stellt ein einfaches
|
||||
Eingabefeld für geografische Koordinaten (Latitude, Longitude)
|
||||
bereit.<br />
|
||||
Sie dient typischerweise dazu, einen bestimmten Punkt auf der Karte zu
|
||||
fokussieren bzw. zu markieren.</p>
|
||||
<hr />
|
||||
<figure>
|
||||
<img src="../../screenshots/CoordinateInput.png"
|
||||
alt="CoordinateInput" />
|
||||
<figcaption aria-hidden="true">CoordinateInput</figcaption>
|
||||
</figure>
|
||||
<hr />
|
||||
<h2 id="pfad">🔧 Pfad</h2>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">/components/uiWidgets/CoordinateInput.js</span></span></code></pre></div>
|
||||
<hr />
|
||||
<h2 id="zweck">🎯 Zweck</h2>
|
||||
<ul>
|
||||
<li>Eingabe von Koordinaten (z. B. <code>53.2,8.1</code>)</li>
|
||||
<li>Übergabe dieser Koordinaten an eine Callback-Funktion zur weiteren
|
||||
Verarbeitung</li>
|
||||
<li>Positioniert sich dauerhaft in der linken oberen Ecke der Seite
|
||||
(z. B. zur schnellen Navigation)</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="props">⚙️ Props</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 18%" />
|
||||
<col style="width: 8%" />
|
||||
<col style="width: 73%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Prop</th>
|
||||
<th>Typ</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>onCoordinatesSubmit</code></td>
|
||||
<td><code>function</code></td>
|
||||
<td>Wird beim Abschicken des Formulars mit dem eingegebenen
|
||||
Koordinaten-String aufgerufen</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="interne-logik">🧩 Interne Logik</h2>
|
||||
<div class="sourceCode" id="cb2"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> [coordinates<span class="op">,</span> setCoordinates] <span class="op">=</span> <span class="fu">useState</span>(<span class="st">""</span>)<span class="op">;</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>Der Eingabewert wird im lokalen State gespeichert</li>
|
||||
<li>Beim Submit (<code>onSubmit</code>) wird
|
||||
<code>onCoordinatesSubmit(coordinates)</code> aufgerufen, wenn
|
||||
gesetzt</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="ui-aufbau">🧰 UI-Aufbau</h2>
|
||||
<ul>
|
||||
<li>Eingabefeld für Text: Erwartet <code>lat,lng</code></li>
|
||||
<li>Button: „Zu Marker zoomen“</li>
|
||||
<li>Position: <code>fixed top-5 left-5</code> → dauerhaft sichtbar</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="gestaltung-tailwind-css">🎨 Gestaltung (Tailwind CSS)</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 12%" />
|
||||
<col style="width: 87%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Element</th>
|
||||
<th>Klassen</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Container</td>
|
||||
<td><code>fixed top-5 left-5 z-50 bg-white shadow-lg rounded-lg p-4 w-72</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Input</td>
|
||||
<td><code>border p-2 rounded w-full mb-2</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Button</td>
|
||||
<td><code>bg-blue-500 text-white p-2 rounded w-full hover:bg-blue-600</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="testfälle">🧪 Testfälle</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 31%" />
|
||||
<col style="width: 68%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Eingabe</th>
|
||||
<th>Erwartung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>53.2,8.1</code></td>
|
||||
<td>Callback <code>onCoordinatesSubmit("53.2,8.1")</code> wird
|
||||
ausgelöst</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Leer</td>
|
||||
<td>Callback wird ausgelöst mit leerem String</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Buttonklick</td>
|
||||
<td>Löst <code>handleSubmit()</code> aus</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Enter-Taste im Eingabefeld</td>
|
||||
<td>Löst ebenfalls Submit aus</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="erweiterungsideen">💡 Erweiterungsideen</h2>
|
||||
<ul>
|
||||
<li>Validierung des Formats (<code>lat,lng</code>) vor dem Absenden</li>
|
||||
<li>Automatisches Zentrieren der Leaflet-Karte in der
|
||||
Callback-Funktion</li>
|
||||
<li>Optionale Markierung des Punkts auf der Karte</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="verwendung">📄 Verwendung</h2>
|
||||
<p>Beispiel in einer Map-Komponente:</p>
|
||||
<div class="sourceCode" id="cb3"><pre
|
||||
class="sourceCode jsx"><code class="sourceCode javascriptreact"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu"><CoordinateInput</span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a> <span class="ot">onCoordinatesSubmit</span><span class="op">=</span><span class="va">{</span>coords <span class="kw">=></span> {</span>
|
||||
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> <span class="kw">const</span> [lat<span class="op">,</span> lng] <span class="op">=</span> coords<span class="op">.</span><span class="fu">split</span>(<span class="st">","</span>)<span class="op">.</span><span class="fu">map</span>(<span class="bu">Number</span>)<span class="op">;</span></span>
|
||||
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> map<span class="op">.</span><span class="fu">setView</span>([lat<span class="op">,</span> lng]<span class="op">,</span> <span class="dv">16</span>)<span class="op">;</span> <span class="co">// Leaflet</span></span>
|
||||
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a> }<span class="va">}</span></span>
|
||||
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="fu">/></span></span></code></pre></div>
|
||||
<hr />
|
||||
<h2 id="verwandte-komponenten">📦 Verwandte Komponenten</h2>
|
||||
<ul>
|
||||
<li><code>MapComponent.js</code> – kann die übergebenen Koordinaten zur
|
||||
Zentrierung oder Marker-Erstellung nutzen</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<hr />
|
||||
<p><a href="../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,11 @@
|
||||
<h1 id="ui-widgets">📄 UI-Widgets</h1>
|
||||
<ul>
|
||||
<li><p><a
|
||||
href="mapLayersControlPanel/mapLayersControlPanel.md">mapLayersControlPanel</a></p></li>
|
||||
<li><p><a href="CoordinateInput.md">CoordinateInput</a></p></li>
|
||||
<li><p><a href="VersionInfoModal.md">VersionInfoModal</a></p>
|
||||
<figure>
|
||||
<img src="../../screenshots/uiWidgets.png" alt="uiWidgets.png" />
|
||||
<figcaption aria-hidden="true">uiWidgets.png</figcaption>
|
||||
</figure></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,131 @@
|
||||
<!-- /docs/components/uiWidgets/VersionInfoModal.md -->
|
||||
<h1 id="versioninfomodal.js">🪪 VersionInfoModal.js</h1>
|
||||
<p>Das <code>VersionInfoModal</code> ist ein modales Fenster zur Anzeige
|
||||
von Unternehmensinformationen und der aktuellen App-Version.<br />
|
||||
Es wird meist im Footer oder als Info-Schaltfläche in der
|
||||
Benutzeroberfläche eingeblendet.</p>
|
||||
<hr />
|
||||
<figure>
|
||||
<img src="../../screenshots/VersionInfoModal.png"
|
||||
alt="VersionInfoModal" />
|
||||
<figcaption aria-hidden="true">VersionInfoModal</figcaption>
|
||||
</figure>
|
||||
<hr />
|
||||
<h2 id="pfad">🔧 Pfad</h2>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">/components/uiWidgets/VersionInfoModal.js</span></span></code></pre></div>
|
||||
<hr />
|
||||
<h2 id="zweck">🎯 Zweck</h2>
|
||||
<p>Die Komponente informiert Nutzer über:</p>
|
||||
<ul>
|
||||
<li>Die <strong>aktuelle TALAS.Map Version</strong></li>
|
||||
<li>Die <strong>Firmenadresse und Kontaktdaten</strong> der Littwin
|
||||
Systemtechnik GmbH & Co. KG</li>
|
||||
<li>Eine zentral platzierte Grafik mit dem TALAS-Logo</li>
|
||||
<li>Eine Schaltfläche zum Schließen des Modals<br />
|
||||
<img src="../../screenshots/VersionInfoModal2.png"
|
||||
alt="VersionInfoModal" /></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="props">⚙️ Props</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 18%" />
|
||||
<col style="width: 8%" />
|
||||
<col style="width: 73%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Prop</th>
|
||||
<th>Typ</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>showVersionInfoModal</code></td>
|
||||
<td><code>boolean</code></td>
|
||||
<td>Steuert, ob das Modal angezeigt wird</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>closeVersionInfoModal</code></td>
|
||||
<td><code>function</code></td>
|
||||
<td>Callback zum Schließen des Modals</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>APP_VERSION</code></td>
|
||||
<td><code>string</code></td>
|
||||
<td>Versionstext (z. B. <code>1.1.188</code>), meist aus
|
||||
<code>.env.production</code> oder <code>.env.development</code>
|
||||
geladen</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="verhalten">💡 Verhalten</h2>
|
||||
<ul>
|
||||
<li>Wird <code>showVersionInfoModal</code> auf <code>true</code>
|
||||
gesetzt, erscheint das Modal zentriert über einem halbtransparenten
|
||||
Overlay</li>
|
||||
<li>Klick auf den Hintergrund (schwarzes Overlay) oder auf „Schließen“
|
||||
führt <code>closeVersionInfoModal()</code> aus</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="gestaltung">🎨 Gestaltung</h2>
|
||||
<ul>
|
||||
<li>Modal-Layout mit Tailwind CSS (<code>fixed</code>,
|
||||
<code>z-50</code>, <code>bg-white</code>, <code>rounded</code>,
|
||||
<code>shadow</code>)</li>
|
||||
<li>Schaltfläche <code>Schließen</code> reagiert auf Hover mit
|
||||
Farbwechsel (<code>hover:bg-blue-700</code>)</li>
|
||||
<li>Design folgt der UI-Ästhetik von TALAS.web</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="testfälle">🧪 Testfälle</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 43%" />
|
||||
<col style="width: 56%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Bedingung</th>
|
||||
<th>Erwartung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>showVersionInfoModal = true</code></td>
|
||||
<td>Modal wird angezeigt</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Klick auf Hintergrund</td>
|
||||
<td>Modal wird geschlossen</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Klick auf „Schließen“-Button</td>
|
||||
<td>Modal wird geschlossen</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Version <code>APP_VERSION = 1.1.290</code></td>
|
||||
<td>Text „TALAS.Map Version 1.1.290“ sichtbar</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="verknüpfte-dateien">📦 Verknüpfte Dateien</h2>
|
||||
<ul>
|
||||
<li><code>.env.production</code> oder <code>.env.development</code>
|
||||
enthält z. B. <code>NEXT_PUBLIC_APP_VERSION=1.1.188</code></li>
|
||||
<li>Aufruf in <code>Footer</code> oder <code>Layout</code> zur Anzeige
|
||||
bei Klick auf „Version“</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="verbesserungsideen">🛠 Verbesserungsideen</h2>
|
||||
<ul>
|
||||
<li>ESC-Taste als Schließen-Funktion ergänzen</li>
|
||||
<li>Automatischer Import von Version via
|
||||
<code>process.env.NEXT_PUBLIC_APP_VERSION</code></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,109 @@
|
||||
<!-- /docs/components/uiWidgets/mapLayersControlPanel/EditModeToggle.md -->
|
||||
<h1 id="editmodetoggle.js">✏️ EditModeToggle.js</h1>
|
||||
<p>Die Komponente <code>EditModeToggle</code> stellt einen interaktiven
|
||||
Umschalter für den Bearbeitungsmodus bereit.<br />
|
||||
Sie ermöglicht das Ein- und Ausschalten des Modus, in dem POIs,
|
||||
Polylines (Strecken) und Bereiche bearbeitet werden können.</p>
|
||||
<hr />
|
||||
<h2 id="pfad">📦 Pfad</h2>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">/components/uiWidgets/mapLayersControlPanel/EditModeToggle.js</span></span></code></pre></div>
|
||||
<hr />
|
||||
<h2 id="zweck">🧩 Zweck</h2>
|
||||
<p>Der Bearbeitungsmodus wirkt sich auf die Interaktivität der Map
|
||||
aus:</p>
|
||||
<ul>
|
||||
<li>Wenn <strong>aktiv</strong>:
|
||||
<ul>
|
||||
<li>Checkboxen für Layer sind deaktiviert</li>
|
||||
<li>POI-Funktionen (Hinzufügen, Verschieben, Löschen) werden
|
||||
ermöglicht</li>
|
||||
</ul></li>
|
||||
<li>Wenn <strong>inaktiv</strong>:
|
||||
<ul>
|
||||
<li>Keine Bearbeitung möglich</li>
|
||||
<li>UI ist auf Betrachtung beschränkt</li>
|
||||
</ul></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="verhalten">🖱 Verhalten</h2>
|
||||
<p>Beim Klick auf das Icon:</p>
|
||||
<ol type="1">
|
||||
<li>Wird der lokale Zustand <code>editMode</code> umgeschaltet</li>
|
||||
<li><code>localStorage</code> speichert den neuen Status
|
||||
(<code>true</code> oder <code>false</code>)</li>
|
||||
<li>Die Seite wird neu geladen (<code>window.location.reload()</code>),
|
||||
um globale Effekte zu aktivieren</li>
|
||||
</ol>
|
||||
<hr />
|
||||
<h2 id="interner-zustand">🧠 Interner Zustand</h2>
|
||||
<div class="sourceCode" id="cb2"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> [editMode<span class="op">,</span> setEditMode] <span class="op">=</span> <span class="fu">useState</span>(() <span class="kw">=></span> localStorage<span class="op">.</span><span class="fu">getItem</span>(<span class="st">"editMode"</span>) <span class="op">===</span> <span class="st">"true"</span>)<span class="op">;</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li>Initialisiert aus <code>localStorage</code></li>
|
||||
<li>Persistente Speicherung des Zustands browserseitig</li>
|
||||
<li>Aufruf in anderen Komponenten (z. B.
|
||||
<code>MapLayersControlPanel.js</code>) basiert ebenfalls auf diesem
|
||||
Wert</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="ui-darstellung">🧰 UI-Darstellung</h2>
|
||||
<ul>
|
||||
<li>Verwendet <strong>Material-UI-Icons</strong>:
|
||||
<ul>
|
||||
<li>🟢 <code>ModeEditIcon</code>: Bearbeitungsmodus <strong>aus</strong>
|
||||
→ wird angeboten zum <strong>Aktivieren</strong></li>
|
||||
<li>🔴 <code>EditOffIcon</code>: Bearbeitungsmodus <strong>ein</strong>
|
||||
→ wird angeboten zum <strong>Deaktivieren</strong></li>
|
||||
</ul></li>
|
||||
<li>Tooltip informiert den Nutzer über die jeweilige Aktion</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="testfälle">🧪 Testfälle</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 25%" />
|
||||
<col style="width: 75%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Zustand</th>
|
||||
<th>Erwartetes Verhalten</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>editMode = false</code></td>
|
||||
<td>Icon: ✏️ → Tooltip: „Bearbeitungsmodus aktivieren“</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>editMode = true</code></td>
|
||||
<td>Icon: 🚫✏️ → Tooltip: „Bearbeitungsmodus deaktivieren“</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Klick auf Icon</td>
|
||||
<td>Status umschalten, Seite neu laden</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="erweiterungsideen">💡 Erweiterungsideen</h2>
|
||||
<ul>
|
||||
<li>🔄 Statt <code>window.location.reload()</code> → globalen Zustand
|
||||
über Redux-Dispatch steuern</li>
|
||||
<li>📢 Feedback-Toast nach Umschalten anzeigen (z. B. „Bearbeitungsmodus
|
||||
aktiviert“)</li>
|
||||
<li>🧩 Integration in Redux-Store zur globalen Synchronisierung ohne
|
||||
Reload</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="verwandte-komponenten">📄 Verwandte Komponenten</h2>
|
||||
<ul>
|
||||
<li><code>MapLayersControlPanel.js</code>: liest
|
||||
<code>localStorage.editMode</code> und deaktiviert Layer-Checkboxen im
|
||||
aktiven Modus</li>
|
||||
<li><code>PoiUpdateModal</code>, <code>AddPOIModal</code>: nutzen den
|
||||
Bearbeitungsmodus für UI-Freigabe</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<hr />
|
||||
<p><a href="../../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,213 @@
|
||||
<!-- /docs/components/uiWidgets/mapLayersControlPanel/MapLayersControlPanel.md -->
|
||||
<h1 id="maplayerscontrolpanel.js">🧭 MapLayersControlPanel.js</h1>
|
||||
<p>Dieses UI-Widget zeigt eine interaktive Steuereinheit für Layer, POIs
|
||||
und Stationsbereiche auf der rechten Seite der Karte.<br />
|
||||
Es ist vollständig an den Redux-Store angebunden und reagiert auf
|
||||
Änderungen der Layer-Sichtbarkeit, Bearbeitungsmodus und
|
||||
Stationsauswahl.</p>
|
||||
<hr />
|
||||
<h2 id="ui-struktur">🧩 UI-Struktur</h2>
|
||||
<figure>
|
||||
<img src="../../../screenshots/MapLayersControlPanel.png"
|
||||
alt="Map layers controll panel" />
|
||||
<figcaption aria-hidden="true">Map layers controll panel</figcaption>
|
||||
</figure>
|
||||
<hr />
|
||||
<h2 id="pfad">🔧 Pfad</h2>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">/components/uiWidgets/mapLayersControlPanel/MapLayersControlPanel.js</span></span></code></pre></div>
|
||||
<hr />
|
||||
<h2 id="zweck">📌 Zweck</h2>
|
||||
<p>Das <code>MapLayersControlPanel</code> ermöglicht Nutzern:</p>
|
||||
<ul>
|
||||
<li>Die Auswahl eines Stationsbereichs (Dropdown)</li>
|
||||
<li>Das Aktivieren/Deaktivieren einzelner GIS-Systeme (Checkboxen)</li>
|
||||
<li>Das Anzeigen von POIs oder Kabelstrecken (TALAS-spezifisch)</li>
|
||||
<li>Das Ein-/Ausschalten des Bearbeitungsmodus</li>
|
||||
<li>Die Steuerung der Karten-Zentrierung über ein Icon</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="verwendete-redux-slices">🧠 Verwendete Redux-Slices</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 35%" />
|
||||
<col style="width: 64%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Slice</th>
|
||||
<th>Zweck</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>gisStationsStaticDistrictSlice</code></td>
|
||||
<td>Enthält die Gerätebereiche (mit <code>.Points</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>gisSystemStaticSlice</code></td>
|
||||
<td>Enthält die konfigurierten GIS-Systeme mit Anzeigeerlaubnis</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>mapLayersSlice</code></td>
|
||||
<td>Speichert die Sichtbarkeit aller Layer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>poiLayerVisibleSlice</code></td>
|
||||
<td>Steuert Sichtbarkeit der POIs</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>polylineLayerVisibleSlice</code></td>
|
||||
<td>Steuert Sichtbarkeit der Kabelstrecken (TALAS)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>zoomTriggerSlice</code></td>
|
||||
<td>Löst Neuzentrierung der Karte aus</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>selectedAreaSlice</code></td>
|
||||
<td>Speichert den gewählten Bereich/Station</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="logikübersicht">🔄 Logikübersicht</h2>
|
||||
<ul>
|
||||
<li><p><strong>Dropdown Stationsauswahl:</strong><br />
|
||||
Wird dynamisch aus <code>GisStationsStaticDistrict.Points</code>
|
||||
befüllt<br />
|
||||
Nur eindeutige <code>Area_Name</code>, wenn <code>System</code> erlaubt
|
||||
ist</p></li>
|
||||
<li><p><strong>Checkboxen für Layer:</strong><br />
|
||||
Zeigen alle Systeme aus <code>GisSystemStatic</code>, bei denen
|
||||
<code>Allow === 1</code><br />
|
||||
Sonderfall: <code>TALAS</code> erhält ein Untermenü für
|
||||
„Kabelstrecken“</p></li>
|
||||
<li><p><strong>Lokale Speicherung:</strong><br />
|
||||
Sichtbarkeiten, Bearbeitungsmodus und POI-Zustand werden in
|
||||
<code>localStorage</code> geschrieben und bei Initialisierung
|
||||
geladen</p></li>
|
||||
<li><p><strong>Bearbeitungsmodus:</strong><br />
|
||||
Wenn aktiv (<code>editMode === true</code>), sind Layer-Checkboxen
|
||||
deaktiviert</p></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="wichtige-funktionen">📥 Wichtige Funktionen</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 44%" />
|
||||
<col style="width: 55%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Funktion</th>
|
||||
<th>Zweck</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>handleAreaChange()</code></td>
|
||||
<td>Setzt <code>selectedArea</code> im Redux Store</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>handleCheckboxChange()</code></td>
|
||||
<td>Schaltet Sichtbarkeit einzelner Layer</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>handlePolylineCheckboxChange()</code></td>
|
||||
<td>Aktiviert Sichtbarkeit von Kabelstrecken</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>handlePoiCheckboxChange()</code></td>
|
||||
<td>Aktiviert Sichtbarkeit von POIs</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>handleIconClick()</code></td>
|
||||
<td>Setzt Station zurück und triggert Zoom</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="debug-hinweise">🐞 Debug-Hinweise</h2>
|
||||
<ul>
|
||||
<li><p>Debug-Logs:<br />
|
||||
<code>__debug.gisStations</code><br />
|
||||
werden ausgegeben, um sicherzustellen, dass Daten korrekt geladen
|
||||
wurden</p></li>
|
||||
<li><p>Warnungen:<br />
|
||||
Falls <code>.Points</code> nicht vorhanden ist, wird dies in der Konsole
|
||||
gewarnt</p></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="todos-erweiterungsideen">🛠 ToDos / Erweiterungsideen</h2>
|
||||
<ul>
|
||||
<li>Checkboxen für Bereiche („Bereiche“, „Standorte“) sind bereits
|
||||
vorbereitet, aber auskommentiert</li>
|
||||
<li>Möglichkeit, Tooltips zu aktivieren/deaktivieren?</li>
|
||||
<li>Gruppierung von Layern nach Typ (z. B. Linien, Geräte, POIs)</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="verwendete-komponenten">📄 Verwendete Komponenten</h2>
|
||||
<ul>
|
||||
<li><code>MapLayersControlPanel</code></li>
|
||||
<li><code>EditModeToggle</code> – Schaltfläche für Umschalten des
|
||||
Bearbeitungsmodus</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="zustand-lokal-global">✅ Zustand: Lokal & Global</h2>
|
||||
<ul>
|
||||
<li><strong>Global:</strong> <code>useSelector(...)</code> aus
|
||||
Redux</li>
|
||||
<li><strong>Lokal:</strong> <code>useState(...)</code> für editMode,
|
||||
stationListing, systemListing</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="lokalestorage-keys">📦 LokaleStorage-Keys</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>poiVisible</code></td>
|
||||
<td>Sichtbarkeit der POI-Marker</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>polylineVisible</code></td>
|
||||
<td>Sichtbarkeit der Kabelstrecken</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>mapLayersVisibility</code></td>
|
||||
<td>Sichtbarkeiten der einzelnen Systeme</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>editMode</code></td>
|
||||
<td>Zustand des Bearbeitungsmodus (true/false)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="testempfehlung">🧪 Testempfehlung</h2>
|
||||
<ul>
|
||||
<li>Dropdown zeigt erwartete <code>Area_Name</code>-Werte?</li>
|
||||
<li>Layer-Checkboxen werden korrekt gespeichert?</li>
|
||||
<li>Bei <code>TALAS</code> erscheint zusätzlich: „Kabelstrecken“?</li>
|
||||
<li>Bei Wechsel der Station wird <code>setSelectedArea</code>
|
||||
ausgelöst?</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="verknüpfte-dateien">🧩 Verknüpfte Dateien</h2>
|
||||
<ul>
|
||||
<li><code>redux/slices/webservice/gisStationsStaticDistrictSlice.js</code></li>
|
||||
<li><code>redux/slices/webservice/gisSystemStaticSlice.js</code></li>
|
||||
<li><code>redux/slices/mapLayersSlice.js</code></li>
|
||||
<li><code>redux/slices/selectedAreaSlice.js</code></li>
|
||||
<li><code>redux/slices/database/polylines/polylineLayerVisibleSlice.js</code></li>
|
||||
<li><code>redux/slices/database/pois/poiLayerVisibleSlice.js</code></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<hr />
|
||||
<p><a href="../../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,6 @@
|
||||
<h1 id="übersicht-docscomponentsuiwidgetsmaplayerscontrolpanel">📄
|
||||
Übersicht: docs/components/uiWidgets/mapLayersControlPanel</h1>
|
||||
<ul>
|
||||
<li><a href="EditModeToggle.md">EditModeToggle</a></li>
|
||||
<li><a href="MapLayersControlPanel.md">MapLayersControlPanel</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,107 @@
|
||||
<!-- /docs/config/README.md -->
|
||||
<h1 id="konfigurationsübersicht-config">⚙️ Konfigurationsübersicht
|
||||
(/config)</h1>
|
||||
<p>Dieses Verzeichnis enthält die zentrale Pfad-Konfigurationsdatei, die
|
||||
für konsistente URL-Generierung in NodeMap zuständig ist.</p>
|
||||
<hr />
|
||||
<h2 id="paths.js">📁 <a href="./paths.md"><code>paths.js</code></a></h2>
|
||||
<ul>
|
||||
<li>Berechnet den Basis-Pfad aus <code>.env.production</code> oder
|
||||
<code>.env.development</code></li>
|
||||
<li>Liefert <code>BASE_URL</code>, z. B. <code>/talas5</code></li>
|
||||
<li>Wird in der gesamten App zur dynamischen URL-Erzeugung
|
||||
verwendet</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p>Diese Konfiguration stellt sicher, dass NodeMap unabhängig von
|
||||
Hostname, Port oder Verzeichnisstruktur funktioniert.</p>
|
||||
<p>📄 Pfad: <code>/config/paths.js</code></p>
|
||||
<hr />
|
||||
<h2 id="osmbasierte-open-quellen">OSM‑basierte, „open“ Quellen</h2>
|
||||
<p>Diese sind datenrechtlich offen (ODbL bzw. Community-Lizenzen), aber
|
||||
das „kostenlos“ gilt nicht im Sinne unbegrenzter Tile‑Nutzung. Die
|
||||
Tile‑Server werden als Community‑Ressource bereitgestellt – bitte
|
||||
Policies respektieren.</p>
|
||||
<ul>
|
||||
<li>osm-standard (OpenStreetMap)</li>
|
||||
<li><ul>
|
||||
<li>Key: Nein</li>
|
||||
</ul></li>
|
||||
<li><ul>
|
||||
<li>Nutzung: Fair‑Use; für produktive/hohe Last eigenen
|
||||
Tile‑Server/Provider verwenden.</li>
|
||||
</ul></li>
|
||||
<li><ul>
|
||||
<li>Attribution: „© OpenStreetMap contributors“</li>
|
||||
</ul></li>
|
||||
<li>osm-humanitarian (HOT)</li>
|
||||
<li><ul>
|
||||
<li>Key: Nein</li>
|
||||
</ul></li>
|
||||
<li><ul>
|
||||
<li>Nutzung: Fair‑Use; für größere Last die Betreiber kontaktieren bzw.
|
||||
andere Infrastruktur nutzen.</li>
|
||||
</ul></li>
|
||||
<li><ul>
|
||||
<li>Attribution: „© OpenStreetMap contributors <br></li>
|
||||
</ul></li>
|
||||
<li></li>
|
||||
<li>Humanitarian OpenStreetMap Team“ cyclosm</li>
|
||||
<li><ul>
|
||||
<li>Key: Nein</li>
|
||||
</ul></li>
|
||||
<li><ul>
|
||||
<li>Nutzung: Fair‑Use (bereitgestellt u. a. über OSM France). Für höhere
|
||||
Last Unterstützung/Hostingoptionen prüfen.</li>
|
||||
</ul></li>
|
||||
<li><ul>
|
||||
<li>Attribution: „CyclOSM“ + „OpenStreetMap contributors“</li>
|
||||
</ul></li>
|
||||
<li>Praxis‑Tipps Kleine bis mittlere Nutzung: Die oben genannten
|
||||
„keyless“ Quellen sind oft ausreichend, solange du Attribution setzt und
|
||||
Limits respektierst. Produktion/hohe Last: Nutze einen Anbieter mit
|
||||
Vertrag/Key (z. B. Thunderforest, Tracestrack, MapTiler, Mapbox) oder
|
||||
hoste Tiles selbst. Schlüssel im Client: Für Thunderforest/Tracestrack
|
||||
stehen die Keys im Frontend. Das ist üblich, aber der Key ist sichtbar.
|
||||
Wenn du ihn verbergen willst, richte einen kleinen Tile‑Proxy auf deinem
|
||||
Server ein, der den Key serverseitig anhängt und optional cached.
|
||||
Attribution: Dein BaseMapPanel setzt bereits Attributionsstrings aus
|
||||
config.json. Achte darauf, dass sie je Quelle korrekt sind.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p>Kurzantwort: Für kommerzielle Nutzung sind OSM‑Community‑Tile‑Server
|
||||
nicht geeignet. Nutze einen bezahlten Anbieter (z. B. Thunderforest,
|
||||
Tracestrack) oder hoste selbst. Attribution ist immer Pflicht.</p>
|
||||
<p>Links und Hinweise je Layer/Provider:</p>
|
||||
<p>OpenStreetMap Standard (osm-standard)</p>
|
||||
<p>Lizenz/Daten: ODbL, Attribution Pflicht Tile-Server-Policy (keine
|
||||
Produktion/hohe Last):
|
||||
https://operations.osmfoundation.org/policies/tiles/
|
||||
Urheberrecht/Attribution: https://www.openstreetmap.org/copyright HOT
|
||||
Humanitarian (osm-humanitarian)</p>
|
||||
<p>Community-Server (OSM France); keine Produktion/hohe Last Info/Policy
|
||||
OSM France Tiles: https://tile.openstreetmap.fr/ HOT:
|
||||
https://www.hotosm.org/ CyclOSM (cyclosm)</p>
|
||||
<p>Community-Server (OSM France); keine Produktion/hohe Last
|
||||
Projektseite: https://www.cyclosm.org/ Hinweise/Policy (OSM France):
|
||||
https://tile.openstreetmap.fr/ Wiki:
|
||||
https://wiki.openstreetmap.org/wiki/CyclOSM Carto Light (carto-light /
|
||||
Positron)</p>
|
||||
<p>Keylos nutzbar mit Attribution; Fair‑Use, für hohe Last über
|
||||
CARTO‑Pläne Basemaps: https://carto.com/basemaps/ Attribution:
|
||||
https://carto.com/attributions Pricing (Plattform):
|
||||
https://carto.com/pricing/ (bei großem Volumen Sales kontaktieren)
|
||||
Thunderforest (Cycle/Transport u. a.)</p>
|
||||
<p>Kommerziell mit API‑Key; Pläne von Free bis Pro Pricing:
|
||||
https://www.thunderforest.com/pricing/ Terms/Attribution:
|
||||
https://www.thunderforest.com/terms/ Tracestrack Topo</p>
|
||||
<p>API‑Key erforderlich; kostenlose und bezahlte Pläne
|
||||
Übersicht/Pricing: https://www.tracestrack.com/en/maps/
|
||||
Nutzungsbedingungen: https://www.tracestrack.com/en/terms/
|
||||
Empfehlung:</p>
|
||||
<p>Produktion: Nimm Thunderforest oder Tracestrack (oder MapTiler:
|
||||
https://www.maptiler.com/pricing/) oder hoste Tiles selbst. Attribution
|
||||
in der Karte anzeigen (OSM + jeweiliger Anbieter). Soll ich diese Links
|
||||
samt klarer Hinweise kompakt in eure README.md einpflegen?</p>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,17 @@
|
||||
<!-- /docs/config/paths.md -->
|
||||
<h1 id="paths.js">📁 paths.js</h1>
|
||||
<p>Berechnet den sauberen <code>BASE_URL</code>-Pfad basierend auf
|
||||
<code>.env.production</code> oder
|
||||
<code>public/config.json → basePath</code>.<br />
|
||||
Entfernt führende und abschließende Slashes.</p>
|
||||
<h2 id="beispiel">Beispiel</h2>
|
||||
<p>Wenn <code>basePath = "/talas5/"</code> in config.json gesetzt ist,
|
||||
wird <code>BASE_URL = "/talas5"</code> verwendet.</p>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> BASE_PATH <span class="op">=</span> basePathRaw<span class="op">.</span><span class="fu">replace</span>(<span class="ss">/</span><span class="sc">^\/|\/$</span><span class="ss">/g</span><span class="op">,</span> <span class="st">""</span>)<span class="op">;</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="im">export</span> <span class="kw">const</span> BASE_URL <span class="op">=</span> BASE_PATH <span class="op">?</span> <span class="vs">`/</span><span class="sc">${</span>BASE_PATH<span class="sc">}</span><span class="vs">`</span> <span class="op">:</span> <span class="st">""</span><span class="op">;</span></span></code></pre></div>
|
||||
<h2 id="nutzung">Nutzung</h2>
|
||||
<ul>
|
||||
<li>Für konsistente Pfadangaben im gesamten Projekt</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,10 @@
|
||||
<!-- /docs/env.local -->
|
||||
<h3 id="docsenv.local.schema.md">/docs/env.local.schema.md</h3>
|
||||
<ul>
|
||||
<li><code>NEXT_PUBLIC_API_HOST</code> → Webservice-DNS oder IP</li>
|
||||
<li><code>NEXT_PUBLIC_API_BASE_PATH</code> → z. B. <code>talas5</code>,
|
||||
per Deployment steuerbar</li>
|
||||
<li><code>DB_NAME</code> → hängt vom Kundenprojekt ab</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,14 @@
|
||||
<h1 id="übersicht-docsguide">📄 Übersicht: docs/guide</h1>
|
||||
<ul>
|
||||
<li><a href="dependencies.md">dependencies</a></li>
|
||||
<li><a href="env.md">env</a></li>
|
||||
<li><a href="faq.md">faq</a></li>
|
||||
<li><a href="glossar.md">glossar</a></li>
|
||||
<li><a href="mock-data.md">mock-data</a></li>
|
||||
<li><a href="onboarding-checklist.md">onboarding-checklist</a></li>
|
||||
<li><a href="project-structure.md">project-structure</a></li>
|
||||
<li><a href="redux-zustand.md">redux-zustand</a></li>
|
||||
<li><a href="setup-dev.md">setup-dev</a></li>
|
||||
<li><a href="user-guide.md">user-guide</a></li>
|
||||
<li><a href="webservices.md">webservices</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,272 @@
|
||||
<!-- /docs/guide/dependencies.md-->
|
||||
<h1 id="abhängigkeiten-in-nodemap-stand-2025">📂 Abhängigkeiten in
|
||||
NodeMap (Stand: 2025)</h1>
|
||||
<p>Diese Datei listet alle Drittanbieter-Abhängigkeiten aus der Datei
|
||||
<code>package.json</code> mit einer kurzen Erklärung, wofür sie im
|
||||
Projekt verwendet werden.</p>
|
||||
<hr />
|
||||
<h2 id="frameworks-tooling">✨ Frameworks & Tooling</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 32%" />
|
||||
<col style="width: 67%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Paket</th>
|
||||
<th>Zweck & Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>next</strong></td>
|
||||
<td>Hauptframework (Next.js) zur Erstellung von React-basierten
|
||||
SSR/SSG-Apps.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>react</strong> / <strong>react-dom</strong></td>
|
||||
<td>Grundlage für UI-Komponenten im Projekt.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>tailwindcss</strong> / <strong>postcss</strong> /
|
||||
<strong>autoprefixer</strong></td>
|
||||
<td>Styling mit Tailwind. PostCSS verarbeitet CSS, Autoprefixer fügt
|
||||
vendor-spezifische Präfixe hinzu.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>dotenv</strong></td>
|
||||
<td>Ermöglicht das Einlesen von <code>.env</code>-Dateien zur Laufzeit
|
||||
auf dem Server.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="leaflet-karten">🌐 Leaflet & Karten</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 40%" />
|
||||
<col style="width: 59%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Paket</th>
|
||||
<th>Zweck & Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>leaflet</strong></td>
|
||||
<td>Basiskartenbibliothek zur Darstellung interaktiver Karten.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>leaflet-contextmenu</strong></td>
|
||||
<td>Kontextmenüs per Rechtsklick in Leaflet.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>leaflet-control-geocoder</strong></td>
|
||||
<td>Steuerelement für Suche/Geokodierung in Karten.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>leaflet.smooth_marker_bouncing</strong></td>
|
||||
<td>Animation für Marker-Bounces (visuelles Feedback).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>overlapping-marker-spiderfier-leaflet</strong></td>
|
||||
<td>Marker-Overlapping-Management mit Spiderfy-Effekt bei Klick.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="zustand-redux">🪄 Zustand & Redux</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 33%" />
|
||||
<col style="width: 66%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Paket</th>
|
||||
<th>Zweck & Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong><span class="citation"
|
||||
data-cites="reduxjs/toolkit">@reduxjs/toolkit</span></strong></td>
|
||||
<td>Vereinfachte Redux-Nutzung mit Slices & Thunks.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>redux</strong> / <strong>react-redux</strong></td>
|
||||
<td>Core-State-Management in React-Komponenten.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>redux-thunk</strong></td>
|
||||
<td>Middleware zur Verarbeitung von asynchronen Aktionen.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="ui-styling">🦜 UI & Styling</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 43%" />
|
||||
<col style="width: 56%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Paket</th>
|
||||
<th>Zweck & Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong><span class="citation"
|
||||
data-cites="mui/icons-material">@mui/icons-material</span></strong></td>
|
||||
<td>UI-Icons aus der Material UI Sammlung.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong><span class="citation"
|
||||
data-cites="emotion/react">@emotion/react</span></strong>, <strong><span
|
||||
class="citation"
|
||||
data-cites="emotion/styled">@emotion/styled</span></strong></td>
|
||||
<td>Styled Components-Engine, benötigt für MUI Styling.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong><span class="citation"
|
||||
data-cites="heroicons/react">@heroicons/react</span></strong></td>
|
||||
<td>React-Icons im Hero-Stil für UI.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>react-select</strong></td>
|
||||
<td>Erweiterte Dropdown-Komponente mit Suchfunktion.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>react-toastify</strong></td>
|
||||
<td>Benachrichtigungs-Tool für Toast-Meldungen.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="daten-kommunikation">📁 Daten & Kommunikation</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 35%" />
|
||||
<col style="width: 64%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Paket</th>
|
||||
<th>Zweck & Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>axios</strong></td>
|
||||
<td>HTTP-Client zur API-Kommunikation (z. B. zu Webservices).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>cookies</strong></td>
|
||||
<td>Zugriff & Verwaltung von Cookies auf Server/Client.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>ws</strong></td>
|
||||
<td>WebSocket-Kommunikation mit z. B. GMA-Live-Daten.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>xml2js</strong> / <strong>fast-xml-parser</strong></td>
|
||||
<td>Parsen von XML-Antworten aus Webservices.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>mysql</strong> / <strong>mysql2</strong></td>
|
||||
<td>Zugriff auf MySQL-Datenbanken.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="sicherheit-netzwerk">🚫 Sicherheit & Netzwerk</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 30%" />
|
||||
<col style="width: 69%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Paket</th>
|
||||
<th>Zweck & Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>http-proxy-middleware</strong></td>
|
||||
<td>API-Routing & Proxy-Zugriff z. B. für lokale Entwicklung.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>nextjs-cors</strong></td>
|
||||
<td>CORS-Konfiguration für Next.js API-Routen.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="entwicklung-test-nur-devdependencies">🎓 Entwicklung & Test
|
||||
(nur devDependencies)</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 60%" />
|
||||
<col style="width: 39%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Paket</th>
|
||||
<th>Zweck & Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>cypress</strong></td>
|
||||
<td>End-to-End-Testing.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>jest-environment-jsdom</strong> /
|
||||
<strong>jest-fetch-mock</strong> / <strong>jest-junit</strong></td>
|
||||
<td>Unit- & Integrationstests.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>identity-obj-proxy</strong></td>
|
||||
<td>Mocking für CSS-Module im Jest-Testkontext.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>node-fetch</strong>, <strong>node-mocks-http</strong></td>
|
||||
<td>HTTP-Mocks für Tests.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>husky</strong></td>
|
||||
<td>Git-Hook-Management (Pre-Commit etc.).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>raw-loader</strong></td>
|
||||
<td>Import von Rohdaten (z. B. SVG) in Webpack.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="weitere-tools-hilfen">📄 Weitere Tools & Hilfen</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Paket</th>
|
||||
<th>Zweck & Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>prepare</strong></td>
|
||||
<td>Wird durch Husky benötigt zum Setup von Hooks.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>bump-version</strong></td>
|
||||
<td>Interner Versionsbump-Script für <code>appVersion.js</code>.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,108 @@
|
||||
<!-- /docs/guide/env.md-->
|
||||
<h1 id="umgebungsvariablen-.env.production-.env.development">🌐
|
||||
Umgebungsvariablen (<code>.env.production</code> /
|
||||
<code>.env.development</code>)</h1>
|
||||
<p>NodeMap verwendet Umgebungsvariablen zur Steuerung von API-Verhalten,
|
||||
Serverpfaden und Moduswahl (Mock oder Produktion).</p>
|
||||
<h2 id="speicherort">📂 Speicherort</h2>
|
||||
<ul>
|
||||
<li><strong>Entwicklung</strong>: <code>.env.development</code></li>
|
||||
<li><strong>Produktion</strong>: <code>.env.production</code> (für
|
||||
<code>npm run build</code> & <code>npm start</code>)</li>
|
||||
</ul>
|
||||
<h2 id="wichtige-variablen">🔧 Wichtige Variablen</h2>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 18%" />
|
||||
<col style="width: 12%" />
|
||||
<col style="width: 69%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Variable</th>
|
||||
<th>Beispielwert</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>DB_HOST</code></td>
|
||||
<td><code>localhost</code></td>
|
||||
<td>Adresse des Datenbankservers (MySQL)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>DB_PORT</code></td>
|
||||
<td><code>3306</code></td>
|
||||
<td>Port für die Datenbankverbindung</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>DB_NAME</code></td>
|
||||
<td><code>talas</code></td>
|
||||
<td>Datenbankname</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>DB_USER</code></td>
|
||||
<td><code>root</code></td>
|
||||
<td>Benutzername für MySQL</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>DB_PASSWORD</code></td>
|
||||
<td><code>geheim</code></td>
|
||||
<td>Passwort für MySQL</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>NEXT_PUBLIC_API_PORT_MODE</code></td>
|
||||
<td><code>prod</code> oder <code>dev</code></td>
|
||||
<td>Steuert API-Routing bei Services (z. B. Portwechsel für lokal)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>NEXT_PUBLIC_USE_MOCKS</code></td>
|
||||
<td><code>true</code> oder <code>false</code></td>
|
||||
<td>Aktiviert den Mockdaten-Modus über <code>/api/mocks/...</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>basePath</code> (in config.json)</td>
|
||||
<td><code>/talas5</code> oder leer</td>
|
||||
<td>Optionaler Pfad, falls App unter Subpfad läuft (z. B. IIS). Wird
|
||||
jetzt in <code>public/config.json</code> gepflegt.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>NEXT_PUBLIC_DEBUG</code></td>
|
||||
<td><code>true</code> oder <code>false</code></td>
|
||||
<td>Aktiviert zusätzliche <code>console.log</code> Ausgaben für
|
||||
Debugging im Browser</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="beispiel-.env.production">📦 Beispiel
|
||||
<code>.env.production</code></h2>
|
||||
<pre class="env"><code>DB_HOST=localhost
|
||||
DB_PORT=3306
|
||||
DB_NAME=talas
|
||||
DB_USER=root
|
||||
DB_PASSWORD=geheim
|
||||
NEXT_PUBLIC_API_PORT_MODE=prod
|
||||
NEXT_PUBLIC_USE_MOCKS=false
|
||||
// public/config.json
|
||||
{
|
||||
...
|
||||
"basePath": "/talas5"
|
||||
}
|
||||
NEXT_PUBLIC_DEBUG=false</code></pre>
|
||||
<h2 id="beispiel-.env.development">📦 Beispiel
|
||||
<code>.env.development</code></h2>
|
||||
<pre class="env"><code>DB_HOST=localhost
|
||||
DB_PORT=3306
|
||||
DB_NAME=talas
|
||||
DB_USER=root
|
||||
DB_PASSWORD=geheim
|
||||
NEXT_PUBLIC_API_PORT_MODE=dev
|
||||
NEXT_PUBLIC_USE_MOCKS=true
|
||||
// public/config.json
|
||||
{
|
||||
...
|
||||
"basePath": "/talas5"
|
||||
}
|
||||
NEXT_PUBLIC_DEBUG=true</code></pre>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,85 @@
|
||||
<!-- /docs/guide/faq.md -->
|
||||
<h1 id="faq-häufige-fragen">❓ FAQ – Häufige Fragen</h1>
|
||||
<hr />
|
||||
<h3 id="warum-sehe-ich-nur-eine-weiße-seite">🔹 Warum sehe ich nur eine
|
||||
weiße Seite?</h3>
|
||||
<ul>
|
||||
<li>Stelle sicher, dass <code>.env.production</code> korrekt
|
||||
konfiguriert ist.</li>
|
||||
<li>Prüfe, ob <code>NEXT_PUBLIC_USE_MOCKS=false</code> gesetzt ist (nur
|
||||
in Produktion).</li>
|
||||
<li>Starte den Dienst neu (<strong>NodeMapService</strong>) oder führe
|
||||
<code>npm start</code> im Terminal aus.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h3 id="was-bedeutet-die-url-m12u484">🔹 Was bedeutet die URL
|
||||
<code>?m=12&u=484</code>?</h3>
|
||||
<ul>
|
||||
<li><code>m=12</code> ist die <strong>Map-ID</strong> (z. B.
|
||||
Leverkusen).</li>
|
||||
<li><code>u=484</code> ist die <strong>User-ID</strong>.</li>
|
||||
<li>Diese IDs werden vom übergeordneten System
|
||||
(<strong>TALAS.web</strong>) übergeben und steuern, was angezeigt
|
||||
wird.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h3 id="wie-kann-ich-pois-hinzufügen-oder-bearbeiten">🔹 Wie kann ich
|
||||
POIs hinzufügen oder bearbeiten?</h3>
|
||||
<ul>
|
||||
<li>Rechtsklick auf die Karte → <strong>„POI hinzufügen“</strong> oder
|
||||
<strong>„bearbeiten“</strong>.</li>
|
||||
<li>Daten werden automatisch gespeichert, wenn du das Formular
|
||||
bestätigst.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h3 id="wie-kann-ich-die-karte-lokal-testen-ohne-backend">🔹 Wie kann
|
||||
ich die Karte lokal testen, ohne Backend?</h3>
|
||||
<ul>
|
||||
<li>Setze in <code>.env.development</code> die Variable
|
||||
<code>NEXT_PUBLIC_USE_MOCKS=true</code>.</li>
|
||||
<li>Starte mit <code>npm run dev</code>.</li>
|
||||
<li>Die App lädt jetzt Mockdaten aus <code>/mockData/</code>.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h3 id="was-mache-ich-wenn-keine-marker-angezeigt-werden">🔹 Was mache
|
||||
ich, wenn keine Marker angezeigt werden?</h3>
|
||||
<ul>
|
||||
<li>Prüfe die Verbindung zum Webservice:<br />
|
||||
<code>http://<ip>/talas5/ClientData/WebServiceMap.asmx</code></li>
|
||||
<li>Stelle sicher, dass die <strong>Map-ID</strong> und
|
||||
<strong>User-ID</strong> in der URL gültig sind.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h3
|
||||
id="wie-erkenne-ich-ob-mein-layer-z.-b.-talas-wago-gma-geladen-ist">🔹
|
||||
Wie erkenne ich, ob mein Layer (z. B. TALAS, WAGO, GMA) geladen
|
||||
ist?</h3>
|
||||
<ul>
|
||||
<li>Im rechten Panel (<strong>LayerControl</strong>) sollten Checkboxen
|
||||
für jeden Layer erscheinen.</li>
|
||||
<li>Wenn keine Layer sichtbar sind, prüfe
|
||||
<code>redux/mapLayersSlice</code> und den Webservice
|
||||
<code>GisSystemStatic</code>.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h3 id="was-tun-bei-der-meldung-fehler-beim-laden-der-kartenkacheln">🔹
|
||||
Was tun bei der Meldung „Fehler beim Laden der Kartenkacheln“?</h3>
|
||||
<ul>
|
||||
<li>Verzeichnis <code>C:\inetpub\wwwroot\talas5\TileMap</code>
|
||||
prüfen.</li>
|
||||
<li>Kartenkacheln müssen im <code>public/</code>-Pfad korrekt verlinkt
|
||||
sein (z. B. <code>mapTiles/...</code>).</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h3 id="wie-kann-ich-die-anwendung-aktualisieren">🔹 Wie kann ich die
|
||||
Anwendung aktualisieren?</h3>
|
||||
<ul>
|
||||
<li><strong>Kleines Update:</strong> Nur <code>.next/</code>
|
||||
kopieren.</li>
|
||||
<li><strong>Größeres Update:</strong> Gesamte App inkl.
|
||||
<code>node_modules</code>, <code>.env.production</code> und
|
||||
<code>public/</code> ersetzen.</li>
|
||||
<li>Dienst neu starten.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,128 @@
|
||||
<h1 id="glossar">📘 Glossar</h1>
|
||||
<p>Eine Übersicht wichtiger Begriffe rund um NodeMap und die verwendeten
|
||||
Technologien.</p>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 18%" />
|
||||
<col style="width: 81%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Begriff</th>
|
||||
<th>Erklärung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><strong>NodeMap</strong></td>
|
||||
<td>Die Kartenanwendung zur Darstellung von GIS-Daten (z. B. POIs,
|
||||
Geräte) in TALAS.web.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Next.js</strong></td>
|
||||
<td>Ein Webframework für React, das Server-Rendering und Routing
|
||||
vereinfacht.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>React</strong></td>
|
||||
<td>Eine JavaScript-Bibliothek zur Erstellung von Benutzeroberflächen
|
||||
(UI).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Redux Toolkit</strong></td>
|
||||
<td>Ein Tool zur einfacheren Zustandverwaltung (State Management) für
|
||||
React.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Tailwind CSS</strong></td>
|
||||
<td>Ein CSS-Framework mit vordefinierten Klassen für schnelles
|
||||
UI-Design.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Leaflet</strong></td>
|
||||
<td>Eine JavaScript-Bibliothek für interaktive Karten auf
|
||||
Webseiten.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>POI</strong></td>
|
||||
<td>„Point of Interest“ – Ein Marker auf der Karte (z. B. ein Gerät,
|
||||
Schacht oder Messpunkt).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>MapComponent</strong></td>
|
||||
<td>Die Hauptkomponente, die die Karte lädt und alle Inhalte darauf
|
||||
anzeigt.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>WebService</strong></td>
|
||||
<td>Ein Serverdienst, der Daten wie POIs, Linien, Geräte liefert (z. B.
|
||||
aus TALAS).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>.env.production</strong></td>
|
||||
<td>Eine Konfigurationsdatei mit Zugangsdaten und Einstellungen für den
|
||||
Live-Betrieb.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Mockdaten</strong></td>
|
||||
<td>Testdaten, die lokal geladen werden, wenn kein Server verfügbar ist
|
||||
(<code>USE_MOCKS=true</code>).</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>iFrame</strong></td>
|
||||
<td>Ein HTML-Element, mit dem eine andere Webseite innerhalb einer Seite
|
||||
eingebettet wird.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>nssm.exe</strong></td>
|
||||
<td>Ein Tool, um Node.js-Anwendungen als Windows-Dienst laufen zu
|
||||
lassen.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Port 3000</strong></td>
|
||||
<td>Der lokale Entwicklungs-Port, unter dem NodeMap im Browser
|
||||
erreichbar ist.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Redux Slice</strong></td>
|
||||
<td>Ein Teil des globalen Redux-Zustands, der z. B. POIs oder Linien
|
||||
speichert.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Thunk</strong></td>
|
||||
<td>Eine asynchrone Funktion in Redux, z. B. um Daten vom Server zu
|
||||
laden.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Contextmenü</strong></td>
|
||||
<td>Ein Rechtsklick-Menü mit Funktionen wie „POI hinzufügen“, „Station
|
||||
öffnen“.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>Layer</strong></td>
|
||||
<td>Ein Karten-Overlay (z. B. Geräte, Linien), das ein- oder
|
||||
ausgeblendet werden kann.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>IdSystem / IdMap</strong></td>
|
||||
<td>Interne IDs zur Zuordnung von Layern und Karten in TALAS.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>GisSystemStatic</strong></td>
|
||||
<td>Eine Webservice-Antwort mit Systeminformationen für die
|
||||
Kartendarstellung.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>mapTiles</strong></td>
|
||||
<td>Bildkacheln (z. B. <code>.png</code>), die die Grundkarte darstellen
|
||||
– wie bei Google Maps.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>TALAS.web</strong></td>
|
||||
<td>Die bestehende (ältere) Verwaltungssoftware, in die NodeMap
|
||||
eingebettet wird.</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,65 @@
|
||||
<h1 id="mockdaten-modus-next_public_use_mockstrue">🧪 Mockdaten-Modus
|
||||
(<code>NEXT_PUBLIC_USE_MOCKS=true</code>)</h1>
|
||||
<p>Dieses Projekt unterstützt einen optionalen
|
||||
<strong>Mockdaten-Modus</strong>, um Entwicklung und Tests ohne
|
||||
Backend/Webservice durchzuführen.</p>
|
||||
<hr />
|
||||
<h2 id="zweck-nutzen">🔍 Zweck & Nutzen</h2>
|
||||
<ul>
|
||||
<li>Schneller Entwicklungsstart ohne aktive Serververbindung</li>
|
||||
<li>Stabilere Testszenarien mit festen JSON-Daten</li>
|
||||
<li>Vollständige Isolation von Backend-Fehlern während der
|
||||
UI-Entwicklung</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="aktivierung">⚙️ Aktivierung</h2>
|
||||
<p>Mockdaten werden aktiviert durch folgende Umgebungsvariable:</p>
|
||||
<pre class="env"><code>NEXT_PUBLIC_USE_MOCKS=true</code></pre>
|
||||
<p>Diese Variable wird in <code>.env.development</code> gesetzt und
|
||||
<strong>nicht</strong> für die Produktionsumgebung verwendet.<br />
|
||||
Im Produktivbetrieb steht:</p>
|
||||
<pre class="env"><code>NEXT_PUBLIC_USE_MOCKS=false</code></pre>
|
||||
<hr />
|
||||
<h2 id="funktionsweise">🧩 Funktionsweise</h2>
|
||||
<p>Wenn <code>NEXT_PUBLIC_USE_MOCKS=true</code> gesetzt ist:</p>
|
||||
<ul>
|
||||
<li>Statt realer Webservices werden Endpunkte unter
|
||||
<code>/pages/api/mocks/webservice/*.js</code> aufgerufen</li>
|
||||
<li>Diese geben vorbereitete JSON-Dateien unter
|
||||
<code>/mockData/*.json</code> zurück</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="beispiel-aufruf-im-mockmodus">📂 Beispiel-Aufruf im
|
||||
Mockmodus</h2>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode ts"><code class="sourceCode typescript"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co">// Beispiel aus fetchGisSystemStaticService.js</span></span>
|
||||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> url <span class="op">=</span> useMocks</span>
|
||||
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a> <span class="op">?</span> <span class="st">"/api/mocks/webservice/GisSystemStatic"</span></span>
|
||||
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> <span class="op">:</span> <span class="vs">`</span><span class="sc">${</span>apiUrl<span class="sc">}</span><span class="vs">/WebServiceMap.asmx/GisSystemStatic`</span><span class="op">;</span></span></code></pre></div>
|
||||
<hr />
|
||||
<h2 id="sicherheit-versionskontrolle">🛡️ Sicherheit &
|
||||
Versionskontrolle</h2>
|
||||
<ul>
|
||||
<li>Alle <code>.json</code>-Dateien im Ordner <code>/mockData/</code>
|
||||
sind über <code>.gitignore</code> vom Repository ausgeschlossen</li>
|
||||
<li>So wird verhindert, dass versehentlich sensible Testdaten
|
||||
veröffentlicht werden</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="hinweise">💡 Hinweise</h2>
|
||||
<ul>
|
||||
<li>Mockdaten sollen nur die wichtigsten API-Schnittstellen
|
||||
simulieren</li>
|
||||
<li>Bei Änderungen am Datenmodell sollten auch die Mockdaten
|
||||
aktualisiert werden</li>
|
||||
<li>Eine zentrale Thunk- & Service-Logik entscheidet automatisch, ob
|
||||
<code>mock</code> oder <code>real</code></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="weitere-informationen">🔗 Weitere Informationen</h2>
|
||||
<ul>
|
||||
<li><a href="env.md">📄 Umgebungsvariablen</a></li>
|
||||
<li><a href="webservices.md">📄 Webservices im Detail</a></li>
|
||||
<li><a href="redux-zustand.md">📄 Zustandverwaltung (Redux)</a></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,59 @@
|
||||
<h2 id="onboarding-checkliste-für-neue-entwickler-bei-nodemap">✅
|
||||
Onboarding-Checkliste für neue Entwickler bei NodeMap</h2>
|
||||
<p>Willkommen im NodeMap-Team! Diese Checkliste begleitet dich Schritt
|
||||
für Schritt beim Einstieg ins Projekt.</p>
|
||||
<hr />
|
||||
<h3 id="schritte-zum-start">🚦 Schritte zum Start</h3>
|
||||
<ol type="1">
|
||||
<li><p><strong>README.md lesen</strong><br />
|
||||
<em>Verschaffe dir einen Überblick über das Projekt.</em><br />
|
||||
☐ Erledigt</p></li>
|
||||
<li><p><strong>Repository clonen & installieren</strong></p>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">git</span> clone http://10.10.0.12:3000/ISA/nodeMap</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="bu">cd</span> nodeMap</span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ex">npm</span> install</span></code></pre></div>
|
||||
<p>☐ Erledigt</p></li>
|
||||
<li><p><strong><code>.env.development</code> anlegen</strong><br />
|
||||
<em>Siehe <a href="docs/guide/env.md">env.md</a> für Details.</em><br />
|
||||
☐ Erledigt</p></li>
|
||||
<li><p><strong>Mock-Modus aktivieren</strong></p>
|
||||
<pre class="env"><code>NEXT_PUBLIC_USE_MOCKS=true</code></pre>
|
||||
<p>☐ Erledigt</p></li>
|
||||
<li><p><strong>Projekt starten</strong></p>
|
||||
<div class="sourceCode" id="cb3"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">npm</span> run dev</span></code></pre></div>
|
||||
<p>☐ Erledigt</p></li>
|
||||
<li><p><strong>App im Browser öffnen</strong><br />
|
||||
<em>Gehe zu:</em> <a
|
||||
href="http://localhost:3000">http://localhost:3000</a><br />
|
||||
☐ Erledigt</p></li>
|
||||
<li><p><strong>POIs testen</strong><br />
|
||||
<em>Hinzufügen, Verschieben, Löschen – siehe <a
|
||||
href="docs/guide/user-guide.md">user-guide.md</a>.</em><br />
|
||||
☐ Erledigt</p></li>
|
||||
<li><p><strong>Redux DevTools installieren & testen</strong><br />
|
||||
<em>Empfohlen für Debugging.</em><br />
|
||||
☐ Erledigt</p></li>
|
||||
<li><p><strong>Projektstruktur ansehen</strong><br />
|
||||
<em>Wichtige Ordner: <code>components/</code>, <code>redux/</code>,
|
||||
<code>services/</code> – siehe <a
|
||||
href="docs/guide/project-structure.md">project-structure.md</a>.</em><br />
|
||||
☐ Erledigt</p></li>
|
||||
<li><p><strong>Webservices überfliegen</strong><br />
|
||||
<em>Siehe <a
|
||||
href="docs/guide/webservices.md">webservices.md</a>.</em><br />
|
||||
☐ Erledigt</p></li>
|
||||
<li><p><strong>Fehlerbehandlung beachten</strong><br />
|
||||
<em>Hinweise dazu findest du im README.</em><br />
|
||||
☐ Erledigt</p></li>
|
||||
<li><p><strong>Fragen notieren & klären</strong><br />
|
||||
<em>Sammle offene Punkte und sprich sie im Team an.</em><br />
|
||||
☐ Erledigt</p></li>
|
||||
</ol>
|
||||
<hr />
|
||||
<p><strong>Tipp:</strong> Hake jeden Schritt ab, sobald du ihn erledigt
|
||||
hast.<br />
|
||||
Viel Erfolg beim Einstieg! 🎉</p>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,135 @@
|
||||
<h2 id="projektstruktur">🧱 Projektstruktur</h2>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">components/</span> → UI-Komponenten inkl. Karte und Layer-Control-Panel <span class="er">(</span><span class="kw">`</span><span class="ex">MapLayersControlPanel</span><span class="kw">`)</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="ex">📦components</span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="ex">┣</span> 📂contextmenu</span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜CoordinatePopup.js</span>
|
||||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┗ 📜useMapContextMenu.js</span>
|
||||
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a> <span class="ex">┣</span> 📂gisPolylines</span>
|
||||
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📂icons</span>
|
||||
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜CircleIcon.js</span>
|
||||
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜EndIcon.js</span>
|
||||
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜StartIcon.js</span>
|
||||
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┗ 📜SupportPointIcons.js</span>
|
||||
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┗ 📜PolylineContextMenu.js</span>
|
||||
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a> <span class="ex">┣</span> 📂icons</span>
|
||||
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┗ 📂devices</span>
|
||||
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┗ 📂overlapping</span>
|
||||
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┗ 📜PlusRoundIcon.js</span>
|
||||
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a> <span class="ex">┣</span> 📂mainComponent</span>
|
||||
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📂hooks</span>
|
||||
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┗ 📜useInitializeMap.js</span>
|
||||
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┗ 📜MapComponent.js</span>
|
||||
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a> <span class="ex">┣</span> 📂pois</span>
|
||||
<span id="cb1-23"><a href="#cb1-23" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜AddPOIModal.js</span>
|
||||
<span id="cb1-24"><a href="#cb1-24" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┗ 📜PoiUpdateModal.js</span>
|
||||
<span id="cb1-25"><a href="#cb1-25" aria-hidden="true" tabindex="-1"></a> <span class="ex">┣</span> 📂uiWidgets</span>
|
||||
<span id="cb1-26"><a href="#cb1-26" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📂mapLayersControlPanel</span>
|
||||
<span id="cb1-27"><a href="#cb1-27" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜EditModeToggle.js</span>
|
||||
<span id="cb1-28"><a href="#cb1-28" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┗ 📜MapLayersControlPanel.js</span>
|
||||
<span id="cb1-29"><a href="#cb1-29" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜CoordinateInput.js</span>
|
||||
<span id="cb1-30"><a href="#cb1-30" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┗ 📜VersionInfoModal.js</span>
|
||||
<span id="cb1-31"><a href="#cb1-31" aria-hidden="true" tabindex="-1"></a> <span class="ex">┗</span> 📜TestScript.js</span>
|
||||
<span id="cb1-32"><a href="#cb1-32" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-33"><a href="#cb1-33" aria-hidden="true" tabindex="-1"></a><span class="ex">config/</span> → zentrale Variablen <span class="er">(</span><span class="ex">.env.development,</span> .env.production<span class="kw">)</span></span>
|
||||
<span id="cb1-34"><a href="#cb1-34" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-35"><a href="#cb1-35" aria-hidden="true" tabindex="-1"></a><span class="ex">hooks/</span> → eigene React-Hooks</span>
|
||||
<span id="cb1-36"><a href="#cb1-36" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-37"><a href="#cb1-37" aria-hidden="true" tabindex="-1"></a><span class="ex">utils/</span> → POI- und Linienverarbeitung</span>
|
||||
<span id="cb1-38"><a href="#cb1-38" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-39"><a href="#cb1-39" aria-hidden="true" tabindex="-1"></a><span class="ex">lib/</span> → Formatierungen, Umrechnungen</span>
|
||||
<span id="cb1-40"><a href="#cb1-40" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-41"><a href="#cb1-41" aria-hidden="true" tabindex="-1"></a><span class="ex">public/</span> → Bilder, Icons, mapTiles sind nicht im nodeMap Projekt Verzeichnis sondern in TALAS Verzeichnis</span>
|
||||
<span id="cb1-42"><a href="#cb1-42" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-43"><a href="#cb1-43" aria-hidden="true" tabindex="-1"></a><span class="ex">pages/</span> → Next.js Seiten <span class="kw">&</span> <span class="ex">Routen</span></span>
|
||||
<span id="cb1-44"><a href="#cb1-44" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-45"><a href="#cb1-45" aria-hidden="true" tabindex="-1"></a><span class="ex">scripts/</span> → lokale Tools <span class="er">(</span><span class="ex">nur</span> Dev<span class="kw">)</span></span>
|
||||
<span id="cb1-46"><a href="#cb1-46" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-47"><a href="#cb1-47" aria-hidden="true" tabindex="-1"></a><span class="ex">redux/</span> → globale Zustände <span class="er">(</span><span class="ex">Slices</span><span class="kw">)</span></span>
|
||||
<span id="cb1-48"><a href="#cb1-48" aria-hidden="true" tabindex="-1"></a><span class="ex">📦redux</span></span>
|
||||
<span id="cb1-49"><a href="#cb1-49" aria-hidden="true" tabindex="-1"></a> <span class="ex">┣</span> 📂slices</span>
|
||||
<span id="cb1-50"><a href="#cb1-50" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📂database</span>
|
||||
<span id="cb1-51"><a href="#cb1-51" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📂pois</span>
|
||||
<span id="cb1-52"><a href="#cb1-52" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜addPoiOnPolylineSlice.js</span>
|
||||
<span id="cb1-53"><a href="#cb1-53" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜addPoiSlice.js</span>
|
||||
<span id="cb1-54"><a href="#cb1-54" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜currentPoiSlice.js</span>
|
||||
<span id="cb1-55"><a href="#cb1-55" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜poiIconsDataSlice.js</span>
|
||||
<span id="cb1-56"><a href="#cb1-56" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜poiLayerVisibleSlice.js</span>
|
||||
<span id="cb1-57"><a href="#cb1-57" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜poiReadFromDbTriggerSlice.js</span>
|
||||
<span id="cb1-58"><a href="#cb1-58" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜poiTypesSlice.js</span>
|
||||
<span id="cb1-59"><a href="#cb1-59" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜poiTypSlice.js</span>
|
||||
<span id="cb1-60"><a href="#cb1-60" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜readPoiMarkersStoreSlice.js</span>
|
||||
<span id="cb1-61"><a href="#cb1-61" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┗ 📜selectedPoiSlice.js</span>
|
||||
<span id="cb1-62"><a href="#cb1-62" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📂polylines</span>
|
||||
<span id="cb1-63"><a href="#cb1-63" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜gisLinesSlice.js</span>
|
||||
<span id="cb1-64"><a href="#cb1-64" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜polylineContextMenuSlice.js</span>
|
||||
<span id="cb1-65"><a href="#cb1-65" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜polylineEventsDisabledSlice.js</span>
|
||||
<span id="cb1-66"><a href="#cb1-66" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┗ 📜polylineLayerVisibleSlice.js</span>
|
||||
<span id="cb1-67"><a href="#cb1-67" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜locationDevicesFromDBSlice.js</span>
|
||||
<span id="cb1-68"><a href="#cb1-68" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜locationDevicesSlice.js</span>
|
||||
<span id="cb1-69"><a href="#cb1-69" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┗ 📜priorityConfigSlice.js</span>
|
||||
<span id="cb1-70"><a href="#cb1-70" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📂webservice</span>
|
||||
<span id="cb1-71"><a href="#cb1-71" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜gisLinesStatusSlice.js</span>
|
||||
<span id="cb1-72"><a href="#cb1-72" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜gisStationsMeasurementsSlice.js</span>
|
||||
<span id="cb1-73"><a href="#cb1-73" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜gisStationsStaticDistrictSlice.js</span>
|
||||
<span id="cb1-74"><a href="#cb1-74" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜gisStationsStatusDistrictSlice.js</span>
|
||||
<span id="cb1-75"><a href="#cb1-75" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜gisSystemStaticSlice.js</span>
|
||||
<span id="cb1-76"><a href="#cb1-76" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┗ 📜userRightsSlice.js</span>
|
||||
<span id="cb1-77"><a href="#cb1-77" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜lineVisibilitySlice.js</span>
|
||||
<span id="cb1-78"><a href="#cb1-78" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜mapLayersSlice.js</span>
|
||||
<span id="cb1-79"><a href="#cb1-79" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜selectedAreaSlice.js</span>
|
||||
<span id="cb1-80"><a href="#cb1-80" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜selectedDeviceSlice.js</span>
|
||||
<span id="cb1-81"><a href="#cb1-81" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜urlParameterSlice.js</span>
|
||||
<span id="cb1-82"><a href="#cb1-82" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┗ 📜zoomTriggerSlice.js</span>
|
||||
<span id="cb1-83"><a href="#cb1-83" aria-hidden="true" tabindex="-1"></a> <span class="ex">┣</span> 📂thunks</span>
|
||||
<span id="cb1-84"><a href="#cb1-84" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📂database</span>
|
||||
<span id="cb1-85"><a href="#cb1-85" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📂pois</span>
|
||||
<span id="cb1-86"><a href="#cb1-86" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜addPoiThunk.js</span>
|
||||
<span id="cb1-87"><a href="#cb1-87" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜deletePoiThunk.js</span>
|
||||
<span id="cb1-88"><a href="#cb1-88" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜fetchPoiIconsDataThunk.js</span>
|
||||
<span id="cb1-89"><a href="#cb1-89" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┣ 📜fetchPoiTypThunk.js</span>
|
||||
<span id="cb1-90"><a href="#cb1-90" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┗ 📜updatePoiThunk.js</span>
|
||||
<span id="cb1-91"><a href="#cb1-91" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📂polylines</span>
|
||||
<span id="cb1-92"><a href="#cb1-92" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┃ ┗ 📜fetchGisLinesThunk.js</span>
|
||||
<span id="cb1-93"><a href="#cb1-93" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜fetchLocationDevicesThunk.js</span>
|
||||
<span id="cb1-94"><a href="#cb1-94" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜fetchPriorityConfigThunk.js</span>
|
||||
<span id="cb1-95"><a href="#cb1-95" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┗ 📜getDeviceIdByNameThunk.js</span>
|
||||
<span id="cb1-96"><a href="#cb1-96" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┗ 📂webservice</span>
|
||||
<span id="cb1-97"><a href="#cb1-97" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜fetchGisLinesStatusThunk.js</span>
|
||||
<span id="cb1-98"><a href="#cb1-98" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜fetchGisStationsMeasurementsThunk.js</span>
|
||||
<span id="cb1-99"><a href="#cb1-99" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜fetchGisStationsStaticDistrictThunk.js</span>
|
||||
<span id="cb1-100"><a href="#cb1-100" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜fetchGisStationsStatusDistrictThunk.js</span>
|
||||
<span id="cb1-101"><a href="#cb1-101" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜fetchGisSystemStaticThunk.js</span>
|
||||
<span id="cb1-102"><a href="#cb1-102" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┗ 📜fetchUserRightsThunk.js</span>
|
||||
<span id="cb1-103"><a href="#cb1-103" aria-hidden="true" tabindex="-1"></a> <span class="ex">┗</span> 📜store.js</span>
|
||||
<span id="cb1-104"><a href="#cb1-104" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-105"><a href="#cb1-105" aria-hidden="true" tabindex="-1"></a><span class="ex">services/</span> → API-Kommunikation, Mock-Logik</span>
|
||||
<span id="cb1-106"><a href="#cb1-106" aria-hidden="true" tabindex="-1"></a><span class="ex">📦services</span></span>
|
||||
<span id="cb1-107"><a href="#cb1-107" aria-hidden="true" tabindex="-1"></a> <span class="ex">┣</span> 📂database</span>
|
||||
<span id="cb1-108"><a href="#cb1-108" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📂pois</span>
|
||||
<span id="cb1-109"><a href="#cb1-109" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜addPoiService.js</span>
|
||||
<span id="cb1-110"><a href="#cb1-110" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜deletePoiService.js</span>
|
||||
<span id="cb1-111"><a href="#cb1-111" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜fetchPoiDataByIdService.js</span>
|
||||
<span id="cb1-112"><a href="#cb1-112" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜fetchPoiDataService.js</span>
|
||||
<span id="cb1-113"><a href="#cb1-113" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜fetchPoiIconsDataService.js</span>
|
||||
<span id="cb1-114"><a href="#cb1-114" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┣ 📜fetchPoiTypService.js</span>
|
||||
<span id="cb1-115"><a href="#cb1-115" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┗ 📜updatePoiService.js</span>
|
||||
<span id="cb1-116"><a href="#cb1-116" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📂polylines</span>
|
||||
<span id="cb1-117"><a href="#cb1-117" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┃ ┗ 📜fetchGisLinesService.js</span>
|
||||
<span id="cb1-118"><a href="#cb1-118" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜fetchDeviceNameByIdService.js</span>
|
||||
<span id="cb1-119"><a href="#cb1-119" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜fetchLocationDevicesService.js</span>
|
||||
<span id="cb1-120"><a href="#cb1-120" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜fetchPriorityConfigService.js</span>
|
||||
<span id="cb1-121"><a href="#cb1-121" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜getDeviceIdByNameService.js</span>
|
||||
<span id="cb1-122"><a href="#cb1-122" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┗ 📜updateLocationInDatabaseService.js</span>
|
||||
<span id="cb1-123"><a href="#cb1-123" aria-hidden="true" tabindex="-1"></a> <span class="ex">┣</span> 📂utils</span>
|
||||
<span id="cb1-124"><a href="#cb1-124" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┗ 📜fetchWithTimeout.js</span>
|
||||
<span id="cb1-125"><a href="#cb1-125" aria-hidden="true" tabindex="-1"></a> <span class="ex">┗</span> 📂webservice</span>
|
||||
<span id="cb1-126"><a href="#cb1-126" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜fetchGisLinesStatusService.js</span>
|
||||
<span id="cb1-127"><a href="#cb1-127" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜fetchGisStationsMeasurementsService.js</span>
|
||||
<span id="cb1-128"><a href="#cb1-128" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜fetchGisStationsStaticDistrictService.js</span>
|
||||
<span id="cb1-129"><a href="#cb1-129" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜fetchGisStationsStatusDistrictService.js</span>
|
||||
<span id="cb1-130"><a href="#cb1-130" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┣ 📜fetchGisSystemStaticService.js</span>
|
||||
<span id="cb1-131"><a href="#cb1-131" aria-hidden="true" tabindex="-1"></a> <span class="ex">┃</span> ┗ 📜fetchUserRightsService.js</span></code></pre></div>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,23 @@
|
||||
<!-- /docs/guide/redux-zustand.md-->
|
||||
<h2 id="zustand-redux">🧠 Zustand: Redux</h2>
|
||||
<p>Die Anwendung verwendet vollständig <strong>Redux Toolkit</strong>
|
||||
für die globale Zustandverwaltung.</p>
|
||||
<ul>
|
||||
<li>Dynamische Gerätegruppen (Layer) werden automatisch über
|
||||
<code>IdSystem</code> aus <code>GisSystemStatic</code>
|
||||
initialisiert</li>
|
||||
<li>Layer-Steuerung erfolgt über <code>system-<IdSystem></code>
|
||||
Keys im Redux <code>mapLayersSlice</code></li>
|
||||
<li>Marker für Geräte werden über Vergleich <code>System</code> ↔︎
|
||||
<code>IdSystem</code> angezeigt</li>
|
||||
</ul>
|
||||
<h3 id="gründe-für-redux">Gründe für Redux :</h3>
|
||||
<ul>
|
||||
<li>Bessere Nachvollziehbarkeit durch zentrale Store-Struktur</li>
|
||||
<li>Unterstützung für DevTools, Logging, Debugging</li>
|
||||
<li>Einheitliche Behandlung von Status, auch bei komplexen
|
||||
Komponenten</li>
|
||||
</ul>
|
||||
<p>➡ Neue Features bitte ausschließlich mit Redux umsetzen!</p>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,46 @@
|
||||
<h1 id="lokale-entwicklung-mit-nodemap">🧑💻 Lokale Entwicklung mit
|
||||
NodeMap</h1>
|
||||
<p>Diese Anleitung richtet sich an Entwickler, die NodeMap lokal
|
||||
weiterentwickeln möchten.</p>
|
||||
<hr />
|
||||
<h2 id="voraussetzungen">Voraussetzungen</h2>
|
||||
<ul>
|
||||
<li>Node.js v18+</li>
|
||||
<li>NPM</li>
|
||||
<li>Chrome / Edge / Firefox</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="schritte">Schritte</h2>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">npm</span> install</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ex">npm</span> run dev</span></code></pre></div>
|
||||
<hr />
|
||||
<h2 id="optionen">Optionen</h2>
|
||||
<ul>
|
||||
<li><strong>Mockdaten-Modus aktivieren:</strong></li>
|
||||
</ul>
|
||||
<pre class="env"><code>NEXT_PUBLIC_USE_MOCKS=true</code></pre>
|
||||
<ul>
|
||||
<li><strong>Umgebungsvariablen lokal definieren:</strong></li>
|
||||
</ul>
|
||||
<p>Datei <code>.env.development</code> mit Inhalten wie:</p>
|
||||
<pre><code>NEXT_PUBLIC_API_URL=http://localhost:3000
|
||||
NEXT_PUBLIC_USE_MOCKS=true</code></pre>
|
||||
<hr />
|
||||
<h2 id="debugging">Debugging</h2>
|
||||
<ul>
|
||||
<li>Verwende <code>console.log</code> in Komponenten oder
|
||||
Redux-Slices</li>
|
||||
<li>Browser-DevTools & Redux DevTools empfohlen</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="weitere-dokumentation">Weitere Dokumentation</h2>
|
||||
<ul>
|
||||
<li>Projektstruktur: <a
|
||||
href="project-structure.md">project-structure.md</a></li>
|
||||
<li>Webservices: <a href="webservices.md">webservices.md</a></li>
|
||||
<li>Zustandverwaltung: <a
|
||||
href="redux-zustand.md">redux-zustand.md</a></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!-- /docs/quide/user-guide.md -->
|
||||
<h2 id="benutzeranleitung">🧭 Benutzeranleitung</h2>
|
||||
<ul>
|
||||
<li><strong>Station öffnen:</strong> Rechte Maustaste → “Station öffnen”
|
||||
oder “Station öffnen (Tab)”</li>
|
||||
<li><strong>POI hinzufügen:</strong> Rechtsklick → “POI hinzufügen” →
|
||||
Formular ausfüllen</li>
|
||||
<li><strong>POI bearbeiten/löschen:</strong> Kontextmenü verwenden</li>
|
||||
<li><strong>POI verschieben:</strong> Drag & Drop des Markers,
|
||||
automatische DB-Aktualisierung</li>
|
||||
<li><strong>Koordinaten anzeigen:</strong> Kontextmenüoption nutzen</li>
|
||||
<li><strong>Zoom:</strong> Mausrad oder Kontextmenüoption</li>
|
||||
<li><strong>Layer steuern:</strong> GIS-Geräte-Layer (z. B. TALAS, WAGO,
|
||||
GMA) ein-/ausblenden über Checkboxen im rechten Panel
|
||||
(<code>MapLayersControlPanel</code>)</li>
|
||||
<li><strong>Station auswählen:</strong> Dropdown oben rechts</li>
|
||||
<li><strong>Zentrieren:</strong> Rechtsklick → “Hier zentrieren”</li>
|
||||
<li><strong>Geräte-Kontextmenü:</strong> Rechtsklick auf Marker →
|
||||
„Station öffnen (Tab)“</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,67 @@
|
||||
<h2 id="webservice-anbindung-backend-talas.web">📡 Webservice-Anbindung
|
||||
(Backend: TALAS.web)</h2>
|
||||
<p>NodeMap verwendet verschiedene Webservices, die von <strong>TALAS
|
||||
V5/TALAS.web</strong> im IIS bereitgestellt werden.<br />
|
||||
Diese Services liefern dynamische GIS-, Geräte- und Statusdaten für die
|
||||
MapComponent.</p>
|
||||
<h3 id="url-des-webservice">URL des Webservice:</h3>
|
||||
<pre><code>http://localhost/talas5/ClientData/WebServiceMap.asmx</code></pre>
|
||||
<blockquote>
|
||||
<p>🔧 In <code>.env.production</code> oder <code>config.js</code> muss
|
||||
die Adresse je nach Umgebung angepasst werden (z. B.
|
||||
<code>http://10.10.0.13/talas5/...</code>)</p>
|
||||
</blockquote>
|
||||
<h3 id="verfügbare-methoden-auszug">Verfügbare Methoden (Auszug):</h3>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style="width: 39%" />
|
||||
<col style="width: 60%" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Endpunkt</th>
|
||||
<th>Zweck / Datenquelle</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>CablesStatic</code></td>
|
||||
<td>Liste aller Stränge</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GetIconsStatic</code></td>
|
||||
<td>Liste aller Icons</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GisLinesStatus</code></td>
|
||||
<td>Liste aller Status der Linien</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GisStationsMeasurements</code></td>
|
||||
<td>Liste aller Messungen der Geräte</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GisStationsStaticDistrict</code></td>
|
||||
<td>Liste aller Geräte einer bestimmten Karte</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GisStationsStatusDistrict</code></td>
|
||||
<td>Liste aller Statis der Geräte</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>GisSystemStatic</code></td>
|
||||
<td>Liste aller angezeigten Systeme</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Die Webservices liefern JSON und werden im Frontend über
|
||||
<code>services/*.js</code> abgefragt.<br />
|
||||
Die Daten werden verarbeitet, zwischengespeichert und z. T. über Redux
|
||||
in der Karte dargestellt.</p>
|
||||
<p>➡ Damit alles funktioniert, müssen:</p>
|
||||
<ul>
|
||||
<li>der IIS laufen</li>
|
||||
<li>der <code>WebServiceMap.asmx</code> erreichbar sein</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,11 @@
|
||||
<h1 id="übersicht-docshooks">📄 Übersicht: docs/hooks</h1>
|
||||
<ul>
|
||||
<li><a href="useCreateAndSetDevices.md">useCreateAndSetDevices</a></li>
|
||||
<li><a href="useDynamicMarkerLayers.md">useDynamicMarkerLayers</a></li>
|
||||
<li><a href="useLayerVisibility.md">useLayerVisibility</a></li>
|
||||
<li><a href="useLineData.md">useLineData</a></li>
|
||||
<li><a href="useMapComponentState.md">useMapComponentState</a></li>
|
||||
<li><a href="useMarkerLayers.md">useMarkerLayers</a></li>
|
||||
<li><a
|
||||
href="usePolylineTooltipLayer.md">usePolylineTooltipLayer</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,28 @@
|
||||
<h1 id="übersicht-docshookslayers">📄 Übersicht: docs/hooks/layers</h1>
|
||||
<ul>
|
||||
<li><a href="useAreaMarkersLayer.md">useAreaMarkersLayer</a></li>
|
||||
<li><a
|
||||
href="useCiscoRouterMarkersLayer.md">useCiscoRouterMarkersLayer</a></li>
|
||||
<li><a href="useDauzMarkersLayer.md">useDauzMarkersLayer</a></li>
|
||||
<li><a href="useDrawLines.md">useDrawLines</a></li>
|
||||
<li><a href="useEciMarkersLayer.md">useEciMarkersLayer</a></li>
|
||||
<li><a href="useGmaMarkersLayer.md">useGmaMarkersLayer</a></li>
|
||||
<li><a
|
||||
href="useLteModemMarkersLayer.md">useLteModemMarkersLayer</a></li>
|
||||
<li><a
|
||||
href="useMessstellenMarkersLayer.md">useMessstellenMarkersLayer</a></li>
|
||||
<li><a href="useOtdrMarkersLayer.md">useOtdrMarkersLayer</a></li>
|
||||
<li><a href="useSiemensMarkersLayer.md">useSiemensMarkersLayer</a></li>
|
||||
<li><a
|
||||
href="useSmsfunkmodemMarkersLayer.md">useSmsfunkmodemMarkersLayer</a></li>
|
||||
<li><a
|
||||
href="useSonstigeMarkersLayer.md">useSonstigeMarkersLayer</a></li>
|
||||
<li><a href="useTalasMarkersLayer.md">useTalasMarkersLayer</a></li>
|
||||
<li><a
|
||||
href="useTalasiclMarkersLayer.md">useTalasiclMarkersLayer</a></li>
|
||||
<li><a
|
||||
href="useTkComponentsMarkersLayer.md">useTkComponentsMarkersLayer</a></li>
|
||||
<li><a href="useUlafMarkersLayer.md">useUlafMarkersLayer</a></li>
|
||||
<li><a href="useWagoMarkersLayer.md">useWagoMarkersLayer</a></li>
|
||||
<li><a href="useWdmMarkersLayer.md">useWdmMarkersLayer</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,16 @@
|
||||
<!-- /docs/hooks/layers/useAreaMarkersLayer.md -->
|
||||
<h1 id="useareamarkerslayer.js">🗺️ useAreaMarkersLayer.js</h1>
|
||||
<p>Lädt Bereichs-/Stationsmarker aus einer API und rendert sie auf der
|
||||
Karte.</p>
|
||||
<h2 id="features">Features</h2>
|
||||
<ul>
|
||||
<li>Marker mit Tooltip für Standort & Bereich</li>
|
||||
<li>Draggable Marker (verschiebbar)</li>
|
||||
<li>Automatischer API-Fetch mit <code>fetch(...)</code></li>
|
||||
<li>Dynamisches Layer-Handling via localStorage
|
||||
(“mapLayersVisibility”)</li>
|
||||
<li>Automatisches Speichern neuer Koordinaten per
|
||||
<code>updateAreaThunk()</code></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,13 @@
|
||||
<!-- /docs/hooks/layers/useDrawLines.md -->
|
||||
<h1 id="usedrawlines.js">🧬 useDrawLines.js</h1>
|
||||
<p>Hook zur Konvertierung von GIS-Linien in kartentaugliche
|
||||
Koordinatenpaare.</p>
|
||||
<h2 id="schritte">Schritte</h2>
|
||||
<ul>
|
||||
<li>Lädt Linien mit <code>fetchGisLinesThunk()</code></li>
|
||||
<li>Wandelt <code>points[x, y]</code> in Leaflet-Koordinaten
|
||||
<code>[lat, lng]</code> um</li>
|
||||
<li>Gibt <code>setLinePositions([...])</code> zurück</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,24 @@
|
||||
<!-- /docs/hooks/useCreateAndSetDevices.md -->
|
||||
<h1 id="usecreateandsetdevices.js">🛠️ useCreateAndSetDevices.js</h1>
|
||||
<p>Custom Hook zur Initialisierung von Leaflet-Markern für ein
|
||||
bestimmtes System.<br />
|
||||
Bindet <code>createAndSetDevices(...)</code> automatisch in einen
|
||||
<code>useEffect</code>.</p>
|
||||
<p>Beispiel: TALAS Layer ist mit Pfeilen markiert<br />
|
||||
<img src="../screenshots/TALAS-Layer.png" alt="TALAS-Layer" /></p>
|
||||
<h2 id="parameter">Parameter</h2>
|
||||
<ul>
|
||||
<li><code>systemId</code>: ID des Gerätesystems (z. B. 1 = TALAS)</li>
|
||||
<li><code>setMarkersFunction</code>: Funktion zum Speichern der
|
||||
erzeugten Marker</li>
|
||||
<li><code>GisSystemStatic</code>: Systemdaten aus Redux</li>
|
||||
<li><code>priorityConfig</code>: Konfigurationsobjekt zur
|
||||
Prioritätsbewertung</li>
|
||||
</ul>
|
||||
<h2 id="redux">Redux</h2>
|
||||
<ul>
|
||||
<li>Bezieht <code>polylineEventsDisabled</code> aus Redux zur Steuerung
|
||||
der Interaktivität</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,22 @@
|
||||
<!-- /docs/hooks/useDynamicMarkerLayers.md -->
|
||||
<h1 id="usedynamicmarkerlayers.js">🔄 useDynamicMarkerLayers.js</h1>
|
||||
<p>Verwaltet alle Marker-Layergruppen dynamisch und modular in einem
|
||||
zentralen Hook.</p>
|
||||
<p>Beispiel: TALAS Layer ist mit Pfeilen markiert<br />
|
||||
<img src="../screenshots/TALAS-Layer.png" alt="TALAS-Layer" /></p>
|
||||
<h2 id="funktionen">Funktionen</h2>
|
||||
<ul>
|
||||
<li>Initialisiert LayerGroups für 15+ Gerätesysteme</li>
|
||||
<li>Ruft <code>createAndSetDevices()</code> pro System-ID auf</li>
|
||||
<li>Führt automatisch Overlap-Check aus
|
||||
(<code>checkOverlappingMarkers</code>)</li>
|
||||
<li>Speichert erzeugte Marker in <code>setMarkerStates</code></li>
|
||||
</ul>
|
||||
<h2 id="voraussetzungen">Voraussetzungen</h2>
|
||||
<ul>
|
||||
<li>Karte (<code>map</code>) muss bereit sein</li>
|
||||
<li><code>GisSystemStatic</code> + <code>priorityConfig</code> +
|
||||
Marker-Setter müssen übergeben werden</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,25 @@
|
||||
<!-- /docs/hooks/useLayerVisibility.md -->
|
||||
<h1 id="uselayervisibility.js">👁️ useLayerVisibility.js</h1>
|
||||
<p>Custom Hook zur dynamischen Steuerung von Layer-Sichtbarkeit
|
||||
basierend auf Redux.</p>
|
||||
<p>Beispiel: TALAS Layer ist mit Pfeilen markiert<br />
|
||||
<img src="../screenshots/mapLayersVisibilityTALAS.png"
|
||||
alt="TALAS-Layer" /><br />
|
||||
Redux<br />
|
||||
<img src="../screenshots/mapLayersVisibilityRedux.png"
|
||||
alt="TALAS-Layer" /><br />
|
||||
Local Storage<br />
|
||||
<img src="../screenshots/mapLayersVisibility.png"
|
||||
alt="TALAS-Layer" /></p>
|
||||
<h2 id="features">Features</h2>
|
||||
<ul>
|
||||
<li>Entfernt oder zeigt Marker je nach
|
||||
<code>mapLayersVisibility</code></li>
|
||||
<li>Nutzt <code>OverlappingMarkerSpiderfier</code></li>
|
||||
<li>Nutzt Layer-IDs</li>
|
||||
</ul>
|
||||
<h2 id="intern">Intern</h2>
|
||||
<p>Verwendet <code>addContextMenuToMarker()</code> zur
|
||||
Kontextmenüintegration pro Marker.</p>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!-- /docs/hooks/useLineData.md -->
|
||||
<h1 id="uselinedata.js">📊 useLineData.js</h1>
|
||||
<p>Lädt Linienstatusdaten (Farben, Tooltips) aus zwei Webservices in
|
||||
Redux und bereitet sie auf.</p>
|
||||
<h2 id="rückgabe">Rückgabe</h2>
|
||||
<ul>
|
||||
<li><code>lineColors</code>: Farben pro Linie basierend auf Status</li>
|
||||
<li><code>tooltipContents</code>: HTML-Tooltip pro Modul/Station</li>
|
||||
</ul>
|
||||
<h2 id="datenquellen">Datenquellen</h2>
|
||||
<ul>
|
||||
<li><code>fetchGisLinesThunk()</code> (Struktur)</li>
|
||||
<li><code>fetchGisLinesStatusThunk()</code> (Statusdaten)</li>
|
||||
</ul>
|
||||
<h2 id="intern">Intern</h2>
|
||||
<ul>
|
||||
<li>Nutzt Map <code>valueMap</code>, um Messwert, Schleifenwert,
|
||||
Meldungen zu gruppieren</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!-- /docs/hooks/useMapComponentState.md -->
|
||||
<h1 id="usemapcomponentstate.js">🧠 useMapComponentState.js</h1>
|
||||
<p>Sammelt zentrale UI-Zustände und Redux-Daten für die
|
||||
<code>MapComponent</code>.</p>
|
||||
<h2 id="rückgabe">Rückgabe</h2>
|
||||
<ul>
|
||||
<li>POI-Typen + Ladezustand</li>
|
||||
<li><code>deviceName</code> (z. B. erstes Gerät)</li>
|
||||
<li><code>locationDeviceData</code></li>
|
||||
<li><code>priorityConfig</code></li>
|
||||
<li><code>menuItemAdded</code>, <code>setMenuItemAdded</code></li>
|
||||
<li>Sichtbarkeit des POI-Layers</li>
|
||||
</ul>
|
||||
<h2 id="redux">Redux</h2>
|
||||
<ul>
|
||||
<li><code>fetchPoiTypThunk</code>,
|
||||
<code>fetchGisStationsStaticDistrictThunk</code>,
|
||||
<code>fetchPriorityConfigThunk</code></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,13 @@
|
||||
<!-- /docs/hooks/useMarkerLayers.md -->
|
||||
<h1 id="usemarkerlayers.js">📍 useMarkerLayers.js</h1>
|
||||
<p>Steuert das Hinzufügen oder Entfernen von Markern in ein
|
||||
Leaflet-Map-Layer.</p>
|
||||
<h2 id="verwendung">Verwendung</h2>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">useMarkerLayers</span>(map<span class="op">,</span> gmaMarkers<span class="op">,</span> <span class="st">"GMA"</span>)<span class="op">;</span></span></code></pre></div>
|
||||
<h2 id="redux">Redux</h2>
|
||||
<ul>
|
||||
<li>Liest <code>mapLayersVisibility</code> aus dem Store</li>
|
||||
<li>Reagiert automatisch auf Änderungen</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,20 @@
|
||||
<!-- /docs/hooks/usePolylineTooltipLayer.md -->
|
||||
<h1 id="usepolylinetooltiplayer.js">💬 usePolylineTooltipLayer.js</h1>
|
||||
<p>Initialisiert und steuert Polylinien + Tooltip-Verhalten für
|
||||
Linienmessdaten.</p>
|
||||
<h2 id="funktion">Funktion</h2>
|
||||
<ul>
|
||||
<li>Nutzt <code>setupPolylines(...)</code> zur Marker- und
|
||||
Linienerstellung</li>
|
||||
<li>Tooltip-Anzeige bei <code>mouseover</code>, dynamisch
|
||||
positioniert</li>
|
||||
<li>Entfernt alte Marker und Polylinien automatisch</li>
|
||||
</ul>
|
||||
<h2 id="parameter-gekürzt">Parameter (gekürzt)</h2>
|
||||
<ul>
|
||||
<li><code>map</code>, <code>markers</code>, <code>setMarkers</code>,
|
||||
<code>setPolylines</code>, <code>linePositions</code>,
|
||||
<code>tooltipContents</code>, <code>lineColors</code>, etc.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,53 @@
|
||||
<!-- /docs/nssm-exe-installation.md -->
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode markdown"><code class="sourceCode markdown"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ss">- </span>Sicherstellen, dass <span class="in">`nssm.exe`</span> in <span class="in">`C:\inetpub\wwwroot\talas5\nodeMap\`</span> vorhanden ist</span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="ss">- </span>Als Administrator Eingabeaufforderung oder PowerShell öffnen</span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a><span class="ss">- </span>Navigiere zu dem NodeMap Projekt Verzeichnis:</span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> <span class="in">```shell</span></span>
|
||||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a> <span class="ex">C:\Users\Administrator</span><span class="op">></span>cd C:<span class="dt">\i</span>netpub<span class="dt">\w</span>wwroot<span class="dt">\t</span>alas5<span class="dt">\n</span>odeMap</span>
|
||||
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a> <span class="in">```</span></span></code></pre></div>
|
||||
<ul>
|
||||
<li><p>Befehl zum Erstellen eines Dienstes: Führen Sie den folgenden
|
||||
Befehl aus, um einen neuen Dienst zu erstellen:</p>
|
||||
<pre class="shell"><code>.\nssm.exe install NodeMapService</code></pre>
|
||||
<p>Nachdem Sie diesen Befehl ausgeführt haben, öffnet sich ein
|
||||
NSSM-Dialogfenster.</p>
|
||||
<figure>
|
||||
<img src="/docs/screenshots/nssm-service-editor.png"
|
||||
alt="NSSM service editor" />
|
||||
<figcaption aria-hidden="true">NSSM service editor</figcaption>
|
||||
</figure>
|
||||
<p><strong>Dienstkonfiguration:</strong> In dem geöffneten
|
||||
NSSM-Dialogfenster müssen Sie einige Parameter angeben:</p>
|
||||
<ul>
|
||||
<li><p><strong>Path:</strong> Der Pfad zur ausführbaren Datei, die der
|
||||
Dienst ausführen soll.</p>
|
||||
<pre class="shell"><code>C:\inetpub\wwwroot\talas5\nodeMap\StartNodeApp.bat</code></pre></li>
|
||||
<li><p><strong>Startup directory:</strong> Das Verzeichnis, in dem die
|
||||
Anwendung gestartet werden soll.</p>
|
||||
<pre class="shell"><code>C:\inetpub\wwwroot\talas5\nodeMap</code></pre></li>
|
||||
<li><p><strong>Arguments:</strong> kann leer gelassen werden.</p></li>
|
||||
</ul></li>
|
||||
<li><p>Dienst starten: Sobald der Dienst erstellt wurde, können Sie ihn
|
||||
starten. Das können Sie entweder über die Eingabeaufforderung oder über
|
||||
die Diensteverwaltung von Windows tun.</p>
|
||||
<figure>
|
||||
<img src="/docs/screenshots/Dienst-beenden.png" alt="nodeMap Dienst" />
|
||||
<figcaption aria-hidden="true">nodeMap Dienst</figcaption>
|
||||
</figure>
|
||||
<p>Um den Dienst über die Eingabeaufforderung zu starten, verwenden Sie
|
||||
den folgenden Befehl:</p>
|
||||
<pre class="shell"><code>nssm.exe start DienstName</code></pre></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<ul>
|
||||
<li><p><strong>Dienst bearbeiten:</strong></p>
|
||||
<pre class="shell"><code>nssm.exe edit NodeMapService</code></pre></li>
|
||||
<li><p><strong>Dienst entfernen:</strong></p>
|
||||
<pre class="shell"><code>nssm.exe remove NodeMapService confirm</code></pre>
|
||||
<p>dauert bis 1 Minute</p></li>
|
||||
</ul>
|
||||
<pre><code></code></pre>
|
||||
<hr />
|
||||
<p><a href="README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,5 @@
|
||||
<h1 id="übersicht-docspages">📄 Übersicht: docs/pages</h1>
|
||||
<ul>
|
||||
<li><a href="_app.md">_app</a></li>
|
||||
<li><a href="index.md">index</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!-- /docs/pages/_app.md -->
|
||||
<h1 id="app.js">🌐 _app.js</h1>
|
||||
<p>Diese Datei stellt die Haupt-Wrap-Komponente der Next.js-App
|
||||
dar.<br />
|
||||
Sie initialisiert globale Provider wie den Redux Store.</p>
|
||||
<h2 id="features">Features</h2>
|
||||
<ul>
|
||||
<li>Importiert globales CSS (<code>styles/global.css</code>)</li>
|
||||
<li>Bindet Redux <code>Provider</code> um alle Seiten-Komponenten</li>
|
||||
<li>Ermöglicht Zugriff auf Store in allen Seiten</li>
|
||||
</ul>
|
||||
<h2 id="struktur">Struktur</h2>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode jsx"><code class="sourceCode javascriptreact"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu"><Provider</span> <span class="ot">store</span><span class="op">=</span><span class="va">{</span>store<span class="va">}</span><span class="fu">></span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="fu"><Component</span> <span class="va">{</span><span class="op">...</span>pageProps<span class="va">}</span> <span class="fu">/></span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="fu"></Provider></span></span></code></pre></div>
|
||||
<h2 id="pfad">Pfad</h2>
|
||||
<div class="sourceCode" id="cb2"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">/pages/_app.js</span></span></code></pre></div>
|
||||
<hr />
|
||||
<p><a href="../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,4 @@
|
||||
<h1 id="übersicht-docspagesapi">📄 Übersicht: docs/pages/api</h1>
|
||||
<ul>
|
||||
<li><a href="%5B...path%5D.md">[…path]</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,37 @@
|
||||
<!-- /docs/pages/api/[...path].md -->
|
||||
<h1 id="path.js">🌐 […path].js</h1>
|
||||
<p>Next.js API-Proxy-Handler mit
|
||||
<code>http-proxy-middleware</code>.<br />
|
||||
Dient als Middleware zur Weiterleitung von API-Requests an das Backend
|
||||
(z. B. Raspberry Pi oder Entwicklungsserver).</p>
|
||||
<hr />
|
||||
<h2 id="funktion">🔧 Funktion</h2>
|
||||
<ul>
|
||||
<li>Leitet alle Requests von <code>/api/...</code> an das definierte
|
||||
<code>target</code> weiter</li>
|
||||
<li>Entfernt <code>/api</code> aus dem URL-Pfad</li>
|
||||
<li>Erlaubt Cross-Origin Requests mit
|
||||
<code>changeOrigin: true</code></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="ziel-logik">Ziel-Logik</h2>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode js"><code class="sourceCode javascript"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> mode <span class="op">=</span> <span class="bu">process</span><span class="op">.</span><span class="at">env</span><span class="op">.</span><span class="at">NEXT_PUBLIC_API_PORT_MODE</span><span class="op">;</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> target <span class="op">=</span> mode <span class="op">===</span> <span class="st">"dev"</span> <span class="op">?</span> <span class="st">"http://localhost:80"</span> <span class="op">:</span> <span class="st">"http://localhost"</span><span class="op">;</span></span></code></pre></div>
|
||||
<hr />
|
||||
<h2 id="beispiel">Beispiel</h2>
|
||||
<ul>
|
||||
<li>Frontend-Request:
|
||||
<code>GET /api/GisStationsStaticDistrict</code></li>
|
||||
<li>Weitergeleitet an:
|
||||
<code>GET http://localhost:80/GisStationsStaticDistrict</code></li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="besonderheiten">Besonderheiten</h2>
|
||||
<ul>
|
||||
<li>Ermöglicht portunabhängige Proxy-Nutzung über <code>.env</code></li>
|
||||
<li>Setzt <code>logLevel: "debug"</code> zur Diagnose</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="pfad">Pfad</h2>
|
||||
<div class="sourceCode" id="cb2"><pre
|
||||
class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">/pages/api/[...path].js</span></span></code></pre></div>
|
||||
@@ -0,0 +1,5 @@
|
||||
<h1 id="übersicht-docspagesapitalas_v5_db">📄 Übersicht:
|
||||
docs/pages/api/talas_v5_DB</h1>
|
||||
<ul>
|
||||
<li><a href="priorityConfig.md">priorityConfig</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,6 @@
|
||||
<h1 id="übersicht-docspagesapitalas_v5_dbarea">📄 Übersicht:
|
||||
docs/pages/api/talas_v5_DB/area</h1>
|
||||
<ul>
|
||||
<li><a href="readArea.md">readArea</a></li>
|
||||
<li><a href="updateArea.md">updateArea</a></li>
|
||||
</ul>
|
||||
@@ -0,0 +1,40 @@
|
||||
<!-- /docs/pages/api/talas_v5_DB/area/readArea.md -->
|
||||
<h1 id="readarea.js">📥 readArea.js</h1>
|
||||
<p>Liest Bereichskoordinaten (<code>location_coordinates</code>) aus der
|
||||
Datenbank basierend auf <code>idMaps</code> (und optional
|
||||
<code>idLocation</code>).</p>
|
||||
<h2 id="methode">Methode</h2>
|
||||
<ul>
|
||||
<li><code>GET</code></li>
|
||||
</ul>
|
||||
<h2 id="url-parameter">URL-Parameter</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Beschreibung</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>m</code></td>
|
||||
<td>Karten-ID (entspricht <code>idMaps</code>)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>idLocation</code></td>
|
||||
<td>(optional) ID eines bestimmten Bereichs</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="verhalten">Verhalten</h2>
|
||||
<ul>
|
||||
<li>Joint <code>location</code>, <code>location_coordinates</code> und
|
||||
<code>area</code>-Tabelle</li>
|
||||
<li>Gibt strukturierte Daten mit <code>x</code>, <code>y</code>,
|
||||
<code>location_name</code>, <code>area_name</code> zurück</li>
|
||||
<li>Nutzt MySQL-Pool (<code>getPool()</code>)</li>
|
||||
</ul>
|
||||
<h2 id="beispiel">Beispiel</h2>
|
||||
<pre class="http"><code>GET /api/talas_v5_DB/area/readArea?m=3</code></pre>
|
||||
<hr />
|
||||
<p><a href="../../../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,32 @@
|
||||
<!-- /docs/pages/api/talas_v5_DB/area/updateArea.md -->
|
||||
<h1 id="updatearea.js">📤 updateArea.js</h1>
|
||||
<p>Aktualisiert die Koordinaten eines Bereichs
|
||||
(<code>location_coordinates</code>) basierend auf
|
||||
<code>idLocation</code> und <code>idMap</code>.</p>
|
||||
<h2 id="methode">Methode</h2>
|
||||
<ul>
|
||||
<li><code>PUT</code></li>
|
||||
</ul>
|
||||
<h2 id="request-body">Request-Body</h2>
|
||||
<div class="sourceCode" id="cb1"><pre
|
||||
class="sourceCode json"><code class="sourceCode json"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">{</span></span>
|
||||
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">"idLocation"</span><span class="fu">:</span> <span class="dv">12</span><span class="fu">,</span></span>
|
||||
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a> <span class="dt">"idMap"</span><span class="fu">:</span> <span class="dv">3</span><span class="fu">,</span></span>
|
||||
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> <span class="dt">"x"</span><span class="fu">:</span> <span class="fl">53.21421</span><span class="fu">,</span></span>
|
||||
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true" tabindex="-1"></a> <span class="dt">"y"</span><span class="fu">:</span> <span class="fl">8.43212</span></span>
|
||||
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a><span class="fu">}</span></span></code></pre></div>
|
||||
<h2 id="verhalten">Verhalten</h2>
|
||||
<ul>
|
||||
<li>Führt
|
||||
<code>UPDATE location_coordinates SET x=?, y=? WHERE idLocation=? AND idMaps=?</code></li>
|
||||
<li>Gibt bei Erfolg <code>success: true</code> zurück</li>
|
||||
<li>Nutzt MySQL-Pool und <code>connection.release()</code></li>
|
||||
</ul>
|
||||
<h2 id="fehlerbehandlung">Fehlerbehandlung</h2>
|
||||
<ul>
|
||||
<li>400: Fehlende Daten</li>
|
||||
<li>404: Kein Eintrag gefunden</li>
|
||||
<li>500: Interner Fehler</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<p><a href="../../../../README.md">Zurück zur Übersicht</a></p>
|
||||
@@ -0,0 +1,6 @@
|
||||
<h1 id="übersicht-docspagesapitalas_v5_dbdevice">📄 Übersicht:
|
||||
docs/pages/api/talas_v5_DB/device</h1>
|
||||
<ul>
|
||||
<li><a href="getAllStationsNames.md">getAllStationsNames</a></li>
|
||||
<li><a href="getDevices.md">getDevices</a></li>
|
||||
</ul>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user