diff --git a/NEXT_STEPS.md b/NEXT_STEPS.md index 6648520..d4830a5 100644 --- a/NEXT_STEPS.md +++ b/NEXT_STEPS.md @@ -1,6 +1,6 @@ -# 📋 NÄCHSTE ARBEITSPAKETE +# 📋 NÄCHSTE ARBEITSPAKETE -## 🎯 Für die nächsten Sessions +## 🎯 Für die nächsten Sessions ### Package 1: Fehlerbehandlung & Sessions (1-2h) - [ ] Session-Handling in `bootstrap.php` implementieren @@ -9,9 +9,9 @@ - [ ] Validierungsfehler anzeigen ### Package 2: Delete-Funktionen (1h) -- [ ] DELETE-Endpoints für alle Module -- [ ] AJAX-Bestätigung vor Löschen -- [ ] Kaskadierendes Löschen prüfen (z.B. Floor → Racks) +- [ ] DELETE-Endpoints für alle Module +- [ ] AJAX-Bestätigung vor Löschen +- [ ] Kaskadierendes Löschen prüfen (z.B. Floor → Racks) ### Package 3: Port-Management (2-3h) - [ ] Ports zu Device-Types verwalten @@ -19,23 +19,23 @@ - [ ] Port-Status (aktiv/inaktiv) - [ ] VLAN-Zuordnung zu Ports -### Package 4: SVG-Editor für Floorplans (4-5h) -- [ ] Interaktiver SVG-Editor für Rooms +### Package 4: SVG-Editor für Floorplans (4-5h) +- [ ] Interaktiver SVG-Editor für Rooms - [ ] Netzwerkdosen platzieren - [ ] Dosen nummerieren - [ ] Speicher-Integration ### Package 5: Navigation & UI (1-2h) -- [ ] Breadcrumbs hinzufügen -- [ ] Mobile-Menü verbessern -- [ ] CSS polieren (Farben, Abstände) +- [ ] Breadcrumbs hinzufügen +- [ ] Mobile-Menü verbessern +- [ ] CSS polieren (Farben, Abstände) - [ ] Dark-Mode (optional) --- -## 📚 Code-Referenzen +## 📚 Code-Referenzen -### Template für neue CRUD-Module: +### Template für neue CRUD-Module: ```php // list.php: Filter + Tabelle // edit.php: Formular @@ -71,7 +71,7 @@ $whereSql = $where ? "WHERE " . implode(" AND ", $where) : ""; --- -## 🔧 Bekannte TODOs im Code +## 🔧 Bekannte TODOs im Code Alle noch offenen Punkte sind mit `// TODO:` gekennzeichnet: @@ -83,48 +83,48 @@ grep -r "TODO:" app/modules/ --include="*.php" Wichtigste TODOs: - `index.php:19` - Session starten - `*/save.php` - Fehlerbehandlung -- `connections/` - Port-Verknüpfung +- `connections/` - Port-Verknüpfung - `lib/auth.php` - Auth-Logik --- -## 💾 Datenbank-Setup +## 💾 Datenbank-Setup Die Datenbank wird automatisch durch `init.sql` initialisiert. Wichtige Tabellen: - `locations` - Standorte -- `buildings` - Gebäude +- `buildings` - Gebäude - `floors` - Stockwerke -- `rooms` - Räume +- `rooms` - Räume - `network_outlets` - Netzwerkdosen -- `device_types` - Gerätetypen +- `device_types` - Gerätetypen - `device_type_ports` - Port-Templates -- `devices` - konkrete Geräte -- `device_ports` - Gerätports +- `devices` - konkrete Geräte +- `device_ports` - Gerätports - `racks` - Racks - `connections` - Verbindungen zwischen Ports --- -## 🧪 Testing-Checklist +## 🧪 Testing-Checklist -Bei jeder Änderung checken: +Bei jeder Änderung checken: - [ ] Formular sendet Daten korrekt - [ ] Daten werden in DB gespeichert - [ ] Liste zeigt neue Daten -- [ ] Edit lädt existierende Daten vor +- [ ] Edit lädt existierende Daten vor - [ ] Filter funktioniert - [ ] Validierungsfehler werden angezeigt --- -## 🎨 Design-Richtlinien +## 🎨 Design-Richtlinien ### Farben: - Primary (Buttons): `#007bff` (Blau) -- Success (Speichern): `#28a745` (Grün) -- Danger (Löschen): `#dc3545` (Rot) +- Success (Speichern): `#28a745` (Grün) +- Danger (Löschen): `#dc3545` (Rot) - Background: `#f9f9f9` (Hell) - Border: `#ddd` (Hell-Grau) @@ -135,8 +135,28 @@ Bei jeder Änderung checken: ### Schriftarten: - Erben von HTML (derzeit: System) -- Monospace für Code/IDs: `font-family: monospace` +- Monospace für Code/IDs: `font-family: monospace` --- -**Happy Coding! 🚀** +**Happy Coding! 🚀** + +## Aktuell offene TODOs (Stand: 18. Februar 2026) + +- [ ] #15 Neue Verbindung: Es kann keine Netzwerkdose ausgewahlt werden. +- [ ] #14 Hilfslinien der Stockwerkskarten nur im Edit-Mode anzeigen; im Anzeige-Mode ausblenden. +- [ ] #11 Encoding- und Umlautfehler beheben (inkl. ae/oe/ue-Themen). +- [ ] #10 Dashboard-Grafik erzeugen: + - Oberste Ebene: Locations, ggf. mit Unterordnung. + - Darunter: Gebaudekomplexe mit Rack-Verbindungen. + - Darunter: Stockwerke. + - Darunter: Etagenweise Verbindungen. +- [ ] #8 Gerate löschen fehlt: Es erfolgt Weiterleitung, aber keine echte Fehlermeldung. +- [ ] #7 Letzten Punkt im Floor-Editor löschen: + - URL: `http://localhost/?module=floors&action=edit&id=1` +- [ ] #5 Dashboard als zoombare und verschiebbare SVG-Flache: + - Gerate anordnen. + - Gerate, Ports und Verbindungen anklickbar. + - Sprechblase mit Infos und Buttons zu Bereichen (editieren, entfernen, ...). +- [ ] #4 `device_types/edit`: Option "Ports automatisch erstellen" nur beim Erstellen anzeigen, nicht beim Editieren. + diff --git a/TODO.md b/TODO.md index 8023301..6cf7f5b 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,4 @@ -# TODO +# TODO Bereinigte und aktuelle TODO-Liste (Stand: 18. Februar 2026). Quelle: vorhandene `TODO`-Marker im Repository plus offene Architekturpunkte. @@ -14,12 +14,9 @@ Quelle: vorhandene `TODO`-Marker im Repository plus offene Architekturpunkte. ## Offen (direkt im Code markiert) -- [ ] `app/modules/dashboard/list.php:11`: - Grosse zoombare/verschiebbare SVG-Wand mit Punkten + Overlay-Drilldown (z. B. Rack-Ansicht). -- [ ] `app/modules/connections/list.php:387`: - Verbindung im UI bearbeiten/loeschen. -- [ ] `app/lib/helpers.php:300`: - Generischer Platzhalter fuer weitere Helper (nur bei konkretem Bedarf ergaenzen). +- [x] `app/modules/dashboard/list.php`: zoombare/verschiebbare SVG-Wand mit klickbaren Punkten und Overlay-Drilldown umgesetzt. +- [x] `app/modules/connections/list.php`: Detailbereich fuer ausgewaehlte Verbindung inkl. Bearbeiten/Loeschen im UI umgesetzt. +- [x] `app/lib/helpers.php`: konkrete allgemeine Helper ergaenzt (`formatDateTime`, `formatBytes`, `generateUuidV4`, `normalizeSvgCoordinate`). ## Offen (Bugs / Doku / Statusdateien) diff --git a/app/lib/helpers.php b/app/lib/helpers.php index 9746082..cd3d98c 100644 --- a/app/lib/helpers.php +++ b/app/lib/helpers.php @@ -297,8 +297,83 @@ HTML, [ * Sonstiges * ========================= */ -// TODO: Weitere Helfer nach Bedarf -// - Datum formatieren -// - Bytes → MB -// - UUID erzeugen -// - SVG-Koordinaten normalisieren +/** + * Formatiert Datum/Uhrzeit robust oder gibt Fallback zurueck. + * + * @param string|null $value + * @param string $format + * @param string $fallback + * @return string + */ +function formatDateTime(?string $value, string $format = 'd.m.Y H:i', string $fallback = '-'): string +{ + if ($value === null || trim($value) === '') { + return $fallback; + } + + $timestamp = strtotime($value); + if ($timestamp === false) { + return $fallback; + } + + return date($format, $timestamp); +} + +/** + * Formatiert Byte-Werte in menschenlesbare Einheit. + * + * @param int|float $bytes + * @param int $precision + * @return string + */ +function formatBytes($bytes, int $precision = 2): string +{ + $value = (float)$bytes; + if ($value <= 0) { + return '0 B'; + } + + $units = ['B', 'KB', 'MB', 'GB', 'TB']; + $power = min((int)floor(log($value, 1024)), count($units) - 1); + $scaled = $value / (1024 ** $power); + + return number_format($scaled, $precision, '.', '') . ' ' . $units[$power]; +} + +/** + * Erzeugt eine UUID v4. + * + * @return string + * @throws Exception + */ +function generateUuidV4(): string +{ + $bytes = random_bytes(16); + $bytes[6] = chr((ord($bytes[6]) & 0x0f) | 0x40); + $bytes[8] = chr((ord($bytes[8]) & 0x3f) | 0x80); + $hex = bin2hex($bytes); + + return sprintf( + '%s-%s-%s-%s-%s', + substr($hex, 0, 8), + substr($hex, 8, 4), + substr($hex, 12, 4), + substr($hex, 16, 4), + substr($hex, 20, 12) + ); +} + +/** + * Klemmt eine SVG-Koordinate auf gueltigen Bereich. + * + * @param float $value + * @param float $min + * @param float $max + * @param int $precision + * @return float + */ +function normalizeSvgCoordinate(float $value, float $min, float $max, int $precision = 2): float +{ + $normalized = max($min, min($max, $value)); + return round($normalized, $precision); +} diff --git a/app/modules/connections/delete.php b/app/modules/connections/delete.php new file mode 100644 index 0000000..fb0797a --- /dev/null +++ b/app/modules/connections/delete.php @@ -0,0 +1,41 @@ +single( + "SELECT id FROM connections WHERE id = ?", + "i", + [$connectionId] +); + +if (!$connection) { + $_SESSION['error'] = 'Verbindung nicht gefunden'; + header('Location: ?module=connections&action=list'); + exit; +} + +$rows = $sql->set( + "DELETE FROM connections WHERE id = ?", + "i", + [$connectionId] +); + +if ($rows > 0) { + $_SESSION['success'] = 'Verbindung geloescht'; +} else { + $_SESSION['error'] = 'Verbindung konnte nicht geloescht werden'; +} + +header('Location: ?module=connections&action=list'); +exit; diff --git a/app/modules/connections/list.php b/app/modules/connections/list.php index 192bc8f..9cb4ff3 100644 --- a/app/modules/connections/list.php +++ b/app/modules/connections/list.php @@ -2,19 +2,13 @@ /** * app/modules/connections/list.php * - * Übersicht der Netzwerkverbindungen - * - Tabellarische Liste aller Verbindungen - * - Filter nach Geräten, VLANs, Status - * - Später: Visuelle Netzwerk-Topologie + * Uebersicht der Netzwerkverbindungen */ -// ========================= -// Filter einlesen -// ========================= $search = trim($_GET['search'] ?? ''); $deviceId = (int)($_GET['device_id'] ?? 0); +$selectedConnectionId = (int)($_GET['connection_id'] ?? 0); -// Einheitliche Endpunkt-Aufloesung fuer polymorphe Port-Typen. $endpointUnionSql = " SELECT 'device' AS endpoint_type, @@ -60,16 +54,13 @@ $endpointUnionSql = " LEFT JOIN floors f ON f.id = fp.floor_id "; -// ========================= -// WHERE-Clause bauen -// ========================= $where = []; $types = ''; $params = []; if ($search !== '') { $where[] = "(e1.owner_name LIKE ? OR e2.owner_name LIKE ? OR e1.port_name LIKE ? OR e2.port_name LIKE ?)"; - $types .= "ssss"; + $types .= 'ssss'; $params[] = "%$search%"; $params[] = "%$search%"; $params[] = "%$search%"; @@ -78,16 +69,13 @@ if ($search !== '') { if ($deviceId > 0) { $where[] = "(e1.owner_device_id = ? OR e2.owner_device_id = ?)"; - $types .= "ii"; + $types .= 'ii'; $params[] = $deviceId; $params[] = $deviceId; } -$whereSql = $where ? "WHERE " . implode(" AND ", $where) : ""; +$whereSql = $where ? 'WHERE ' . implode(' AND ', $where) : ''; -// ========================= -// Verbindungen laden -// ========================= $connections = $sql->get( "SELECT c.id, @@ -125,10 +113,22 @@ $connections = $sql->get( $params ); -// ========================= -// Filter-Daten -// ========================= -$devices = $sql->get("SELECT id, name FROM devices ORDER BY name", "", []); +$devices = $sql->get('SELECT id, name FROM devices ORDER BY name', '', []); + +$selectedConnection = null; +if ($selectedConnectionId > 0) { + foreach ((array)$connections as $entry) { + if ((int)($entry['id'] ?? 0) === $selectedConnectionId) { + $selectedConnection = $entry; + break; + } + } +} + +if ($selectedConnection === null && !empty($connections)) { + $selectedConnection = $connections[0]; + $selectedConnectionId = (int)($selectedConnection['id'] ?? 0); +} $selectedDevice = null; $selectedDevicePorts = []; @@ -140,7 +140,7 @@ if ($deviceId > 0) { FROM devices d LEFT JOIN device_types dt ON d.device_type_id = dt.id WHERE d.id = ?", - "i", + 'i', [$deviceId] ); @@ -159,7 +159,7 @@ if ($deviceId > 0) { JOIN device_ports dp ON dp.id = dpm.device_port_id WHERE dp.device_id = ? ) p", - "ii", + 'ii', [$deviceId, $deviceId] )['cnt'] ?? 0); @@ -187,7 +187,7 @@ if ($deviceId > 0) { OR (c.port_b_type = 'patchpanel' AND e2.endpoint_type = 'floor_patchpanel') ) WHERE e1.owner_device_id = ? OR e2.owner_device_id = ?", - "ii", + 'ii', [$deviceId, $deviceId] )['cnt'] ?? 0); @@ -207,7 +207,7 @@ if ($deviceId > 0) { ) p ORDER BY sort_id LIMIT 12", - "ii", + 'ii', [$deviceId, $deviceId] ); @@ -230,159 +230,247 @@ if ($deviceId > 0) { } } +$buildListUrl = static function (array $extra = []) use ($search, $deviceId): string { + $query = ['module' => 'connections', 'action' => 'list']; + if ($search !== '') { + $query['search'] = $search; + } + if ($deviceId > 0) { + $query['device_id'] = $deviceId; + } + foreach ($extra as $key => $value) { + if ($value === null || $value === '') { + continue; + } + $query[$key] = $value; + } + return '?' . http_build_query($query); +}; ?> -
| Von (Gerät → Port) | -Nach (Gerät → Port) | -VLANs | -Beschreibung | -Status | -Aktionen | -
|---|---|---|---|---|---|
|
- - - |
+
Keine Verbindungen gefunden.
- -Bitte ein Geraet im Filter auswaehlen.
+ + +Mausrad zoomt, Ziehen verschiebt. Klick auf einen Punkt zoomt auf den Rack-Kontext und oeffnet die Detailkarte.
+ + + +| - | - | - | - | Bearbeiten | ++ | + | + | + | Bearbeiten |
Noch keine Geräte vorhanden. Starten Sie mit Gerätetypen.
+Noch keine Geraete vorhanden. Starten Sie mit Geraetetypen.