From 6bbae62b21eb96dd68caff469f2e5bafb3b500a8 Mon Sep 17 00:00:00 2001 From: Till Tomczak Date: Thu, 29 May 2025 20:55:15 +0200 Subject: [PATCH] "feat: Update error handling documentation in frontend files" --- backend/app/FEHLER_BEHOBEN.md | 126 ++++++++++++++++++++++- backend/app/app.py | 22 +++- backend/app/database/myp.db-shm | Bin 32768 -> 32768 bytes backend/app/database/myp.db-wal | Bin 32992 -> 41232 bytes backend/app/static/css/input.css | 170 ++++++++++++++++++++++++------- 5 files changed, 274 insertions(+), 44 deletions(-) diff --git a/backend/app/FEHLER_BEHOBEN.md b/backend/app/FEHLER_BEHOBEN.md index dfa19d34..3b9990a2 100644 --- a/backend/app/FEHLER_BEHOBEN.md +++ b/backend/app/FEHLER_BEHOBEN.md @@ -195,4 +195,128 @@ Komplettes Live-Druckererkennungs-System mit Session-Caching und automatischer S --- -## [2024-12-29] Template-Ladeproblem behoben ✅ \ No newline at end of file +## [2024-12-29] Template-Ladeproblem behoben ✅ + +## 2025-05-29 20:45 - Live-Drucker-Status-Integration behoben + +### Problem +Obwohl das Live-Drucker-Erkennungssystem vollständig implementiert war, wurden die Drucker nicht als online angezeigt. Das Frontend nutzte noch die alten API-Endpunkte ohne Live-Status-Updates. + +### Ursache +1. **Fehlende Frontend-Integration**: Das `printer_monitor.js` System war implementiert, aber nicht in die HTML-Templates eingebunden +2. **Veraltete API-Aufrufe**: Die PrinterManager-Klasse nutzte noch `/api/printers` statt der neuen Live-Monitor-Endpunkte +3. **Fehlende Status-Kategorien**: Die neuen Status-Kategorien (standby, unreachable, unconfigured) waren nicht im Frontend implementiert + +### Lösung +1. **JavaScript-Einbindung in base.html**: + ```html + + ``` + +2. **PrinterManager-Integration erweitert**: + ```javascript + // Nutze das neue PrinterMonitor-System für Live-Status + if (window.printerMonitor) { + window.printerMonitor.onUpdate((data) => { + if (data.type === 'update') { + allPrinters = Array.from(data.printers.values()); + // Update UI mit Live-Daten + } + }); + await window.printerMonitor.forceUpdate(); + } + ``` + +3. **Live-Status-Indikator hinzugefügt**: + ```html +
+ ``` + +4. **Erweiterte Status-Kategorien**: + - **standby**: Gelb - Drucker bereit aber inaktiv + - **unreachable**: Grau - Netzwerk nicht erreichbar + - **unconfigured**: Indigo - Nicht konfiguriert + +5. **Status-Filter erweitert**: + ```html + + + + ``` + +6. **CSS-Styling für neue Status**: + ```css + .status-standby { border-left: 4px solid #f59e0b; } + .status-unreachable { border-left: 4px solid #6b7280; } + .status-unconfigured { border-left: 4px solid #6366f1; } + ``` + +### Funktionen nach der Behebung +- ✅ Live-Status-Updates alle 30 Sekunden +- ✅ Session-Caching für bessere Performance +- ✅ Automatische Steckdosen-Initialisierung beim Start +- ✅ Visuelle Live-Status-Indikatoren +- ✅ Erweiterte Status-Kategorien +- ✅ Fallback zu Standard-API bei Fehlern +- ✅ Detaillierte Status-Logging in der Konsole + +### API-Endpunkte +- `GET /api/printers/monitor/live-status` - Live-Status mit Caching +- `GET /api/printers/monitor/summary` - Schnelle Übersicht +- `POST /api/printers/monitor/clear-cache` - Cache-Management +- `POST /api/printers/monitor/initialize-outlets` - Steckdosen-Init + +### Verhalten +- **Automatischer Start**: PrinterMonitor startet automatisch auf der Drucker-Seite +- **Adaptive Intervalle**: 30s normal, 60s wenn Tab versteckt, 5s bei kritischen Operationen +- **Fehlerbehandlung**: Automatischer Fallback zu Standard-API bei Problemen +- **Performance**: Multi-Level-Caching (Session 30s, DB 5min) + +### Test-Ergebnisse +- Live-Status-Updates funktionieren korrekt +- Drucker werden mit korrekten Status-Kategorien angezeigt +- Performance-Optimierungen greifen +- Fallback-Mechanismen funktionieren + +--- + +## 2025-05-29 18:30 - Rate Limiting Decorator Fehler behoben + +### Problem +``` +TypeError: limit_requests() takes 1 positional argument but 3 were given +``` + +### Ursache +Falsche Verwendung des Rate-Limiting-Decorators: +```python +# Falsch: +@limit_requests("printer_monitor_live", 60, 5) + +# Richtig: +@limit_requests("printer_monitor_live") +``` + +### Lösung +1. **Rate Limits in Konfiguration definiert**: + ```python + RATE_LIMITS = { + "printer_monitor_live": {"requests": 5, "window": 60}, + "printer_monitor_summary": {"requests": 10, "window": 30}, + "printer_monitor_cache": {"requests": 3, "window": 120}, + "printer_monitor_init": {"requests": 2, "window": 300} + } + ``` + +2. **Decorator-Syntax korrigiert**: + ```python + @limit_requests("printer_monitor_live") + def get_live_printer_status(): + ``` + +### Betroffene Dateien +- `utils/rate_limiter.py` - Rate Limits hinzugefügt +- `blueprints/printer_monitor.py` - Decorator-Syntax korrigiert +- `docs/live_drucker_system.md` - Dokumentation aktualisiert + +--- \ No newline at end of file diff --git a/backend/app/app.py b/backend/app/app.py index af7e2be7..3386f235 100644 --- a/backend/app/app.py +++ b/backend/app/app.py @@ -1386,19 +1386,29 @@ def check_printer_status(ip_address: str, timeout: int = 7) -> Tuple[str, bool]: @measure_execution_time(logger=printers_logger, task_name="Mehrere-Drucker-Status-Prüfung") def check_multiple_printers_status(printers: List[Dict], timeout: int = 7) -> Dict[int, Tuple[str, bool]]: """ - Überprüft den Status mehrerer Drucker parallel mit Timeout. + Überprüft den Status mehrerer Drucker parallel. Args: - printers: Liste von Drucker-Dictionaries mit 'id' und 'ip_address' - timeout: Timeout in Sekunden pro Drucker (Standard: 7) - + printers: Liste der zu prüfenden Drucker + timeout: Timeout für jeden einzelnen Drucker + Returns: Dict[int, Tuple[str, bool]]: Dictionary mit Drucker-ID als Key und (Status, Aktiv) als Value """ results = {} + # Wenn keine Drucker vorhanden sind, gebe leeres Dict zurück + if not printers: + printers_logger.info("ℹ️ Keine Drucker zum Status-Check gefunden") + return results + + printers_logger.info(f"🔍 Prüfe Status von {len(printers)} Druckern parallel...") + # Parallel-Ausführung mit ThreadPoolExecutor - with ThreadPoolExecutor(max_workers=min(len(printers), 10)) as executor: + # Sicherstellen, dass max_workers mindestens 1 ist + max_workers = min(max(len(printers), 1), 10) + + with ThreadPoolExecutor(max_workers=max_workers) as executor: # Futures für alle Drucker erstellen future_to_printer = { executor.submit(check_printer_status, printer.get('ip_address'), timeout): printer @@ -1416,6 +1426,8 @@ def check_multiple_printers_status(printers: List[Dict], timeout: int = 7) -> Di printers_logger.error(f"Fehler bei Status-Check für Drucker {printer['name']}: {str(e)}") results[printer['id']] = ("offline", False) + printers_logger.info(f"✅ Status-Check abgeschlossen für {len(results)} Drucker") + return results # ===== UI-ROUTEN ===== diff --git a/backend/app/database/myp.db-shm b/backend/app/database/myp.db-shm index 7af6484d9b4440484baee7ac30aad3da826ab0a8..7a10644be8d99f217bb0f1c1799477590deb10e6 100644 GIT binary patch delta 159 zcmZo@U}|V!s+V}A%K!q55G=q2q@{rPcDeUyFRqEpUfxjuV_x}m(Yjmd`xBGis*|c7 pXcQQL%>9o9pu$WHoD&4EJ&-j`c0RZaeHQ@jN delta 160 zcmZo@U}|V!s+V}A%K!q55G=q6q@{qETP!a0yqt3U%Ny!{%qyQR>eH6*`JC!$PO5sK pQD6Wv_dgPV3NtZqOl;KNxWUJD;sKV)e_VMsZaTug`HZiL5diP;F*^VN diff --git a/backend/app/database/myp.db-wal b/backend/app/database/myp.db-wal index c402a335e9b0648e69296545d1ba0d1d60d3b93b..b8984763887ea39e84312dc2942d49e46cf5a0da 100644 GIT binary patch delta 193 zcmaFR$TZ;)(}o8PlLHh4I6~vZxZ{=O&TkG72;?`-D~!x5Ne;{o%1VyXGtVn?E^;X_ zD|Ii@&r43r^UR3y^K;A#DmC=4DoOY8GB?RK@-%b|pZrcggvZpt%GgNH$il$L$Y7Fz z6xi(3-sQKKP2}=|m|bO7WoBAwSrUgD delta 9 QcmbPmi0MHi(}o8P02fpQ$N&HU diff --git a/backend/app/static/css/input.css b/backend/app/static/css/input.css index 740362f1..c3a34542 100644 --- a/backend/app/static/css/input.css +++ b/backend/app/static/css/input.css @@ -789,25 +789,84 @@ width: 100% !important; left: 0 !important; right: 0 !important; - @apply bg-white/60 dark:bg-black/70; - backdrop-filter: blur(24px) saturate(200%); - -webkit-backdrop-filter: blur(24px) saturate(200%); - box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.08); - border-bottom: 1px solid rgba(255, 255, 255, 0.15); + /* Verstärktes Glassmorphism Design */ + background: rgba(255, 255, 255, 0.15) !important; + backdrop-filter: blur(40px) saturate(200%) brightness(110%) contrast(105%) !important; + -webkit-backdrop-filter: blur(40px) saturate(200%) brightness(110%) contrast(105%) !important; + box-shadow: + 0 8px 32px rgba(0, 0, 0, 0.12), + 0 2px 8px rgba(0, 0, 0, 0.08), + inset 0 1px 0 rgba(255, 255, 255, 0.3), + 0 0 0 1px rgba(255, 255, 255, 0.15) !important; + border-bottom: 1px solid rgba(255, 255, 255, 0.2) !important; + transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; } .dark .navbar { - box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2); - border-bottom: 1px solid rgba(255, 255, 255, 0.05); + background: rgba(0, 0, 0, 0.25) !important; + backdrop-filter: blur(45px) saturate(180%) brightness(120%) contrast(115%) !important; + -webkit-backdrop-filter: blur(45px) saturate(180%) brightness(120%) contrast(115%) !important; + box-shadow: + 0 8px 32px rgba(0, 0, 0, 0.4), + 0 2px 8px rgba(0, 0, 0, 0.3), + inset 0 1px 0 rgba(255, 255, 255, 0.15), + 0 0 0 1px rgba(255, 255, 255, 0.08) !important; + border-bottom: 1px solid rgba(255, 255, 255, 0.1) !important; } -/* Neue Navbar-Komponenten */ +/* Navbar Scroll-Effekt */ +.navbar.scrolled { + background: rgba(255, 255, 255, 0.25) !important; + backdrop-filter: blur(50px) saturate(220%) brightness(115%) contrast(110%) !important; + -webkit-backdrop-filter: blur(50px) saturate(220%) brightness(115%) contrast(110%) !important; + box-shadow: + 0 12px 40px rgba(0, 0, 0, 0.15), + 0 4px 12px rgba(0, 0, 0, 0.1), + inset 0 1px 0 rgba(255, 255, 255, 0.4), + 0 0 0 1px rgba(255, 255, 255, 0.2) !important; +} + +.dark .navbar.scrolled { + background: rgba(0, 0, 0, 0.35) !important; + backdrop-filter: blur(55px) saturate(200%) brightness(125%) contrast(120%) !important; + -webkit-backdrop-filter: blur(55px) saturate(200%) brightness(125%) contrast(120%) !important; + box-shadow: + 0 12px 40px rgba(0, 0, 0, 0.5), + 0 4px 12px rgba(0, 0, 0, 0.4), + inset 0 1px 0 rgba(255, 255, 255, 0.2), + 0 0 0 1px rgba(255, 255, 255, 0.1) !important; +} + +/* Neue Navbar-Komponenten mit verbessertem Glassmorphism */ .navbar-menu-new { @apply flex items-center justify-center space-x-0.5 md:space-x-1; max-width: 100%; overflow-x: auto; scrollbar-width: none; -ms-overflow-style: none; + /* Glassmorphism für das Menü */ + background: rgba(255, 255, 255, 0.1); + backdrop-filter: blur(25px) saturate(170%) brightness(108%); + -webkit-backdrop-filter: blur(25px) saturate(170%) brightness(108%); + border-radius: 16px; + padding: 8px; + margin: 0 16px; + border: 1px solid rgba(255, 255, 255, 0.15); + box-shadow: + 0 6px 20px rgba(0, 0, 0, 0.1), + inset 0 1px 0 rgba(255, 255, 255, 0.2), + 0 0 0 1px rgba(255, 255, 255, 0.05); +} + +.dark .navbar-menu-new { + background: rgba(0, 0, 0, 0.2); + backdrop-filter: blur(30px) saturate(150%) brightness(115%); + -webkit-backdrop-filter: blur(30px) saturate(150%) brightness(115%); + border: 1px solid rgba(255, 255, 255, 0.1); + box-shadow: + 0 6px 20px rgba(0, 0, 0, 0.3), + inset 0 1px 0 rgba(255, 255, 255, 0.1), + 0 0 0 1px rgba(255, 255, 255, 0.03); } .navbar-menu-new::-webkit-scrollbar { @@ -815,60 +874,95 @@ } .nav-item { - @apply flex items-center space-x-1.5 px-1.5 py-1.5 rounded-md text-xs font-medium transition-all duration-300; - color: rgba(15, 23, 42, 0.8); - background: rgba(255, 255, 255, 0.04); + @apply flex items-center space-x-1.5 px-3 py-2.5 rounded-xl text-sm font-medium transition-all duration-300; + color: rgba(15, 23, 42, 0.85); + /* Gläserner Nav-Item */ + background: rgba(255, 255, 255, 0.08); + backdrop-filter: blur(15px) saturate(140%); + -webkit-backdrop-filter: blur(15px) saturate(140%); border: 1px solid rgba(255, 255, 255, 0.1); - white-space: nowrap; - min-width: fit-content; + box-shadow: + 0 4px 12px rgba(0, 0, 0, 0.05), + inset 0 1px 0 rgba(255, 255, 255, 0.15); + position: relative; + overflow: hidden; +} + +/* Glassmorphism Hover-Effekt */ +.nav-item::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent); + transition: left 0.5s; +} + +.nav-item:hover::before { + left: 100%; } .dark .nav-item { - color: rgba(255, 255, 255, 0.8); - background: rgba(0, 0, 0, 0.2); - border: 1px solid rgba(255, 255, 255, 0.05); + color: rgba(255, 255, 255, 0.85); + background: rgba(0, 0, 0, 0.15); + backdrop-filter: blur(20px) saturate(130%); + -webkit-backdrop-filter: blur(20px) saturate(130%); + border: 1px solid rgba(255, 255, 255, 0.08); + box-shadow: + 0 4px 12px rgba(0, 0, 0, 0.2), + inset 0 1px 0 rgba(255, 255, 255, 0.08); } .nav-item:hover { - @apply transform -translate-y-0.5; color: rgba(15, 23, 42, 1); - background: rgba(255, 255, 255, 0.15); - border: 1px solid rgba(255, 255, 255, 0.2); + background: rgba(255, 255, 255, 0.2); + backdrop-filter: blur(25px) saturate(160%) brightness(110%); + -webkit-backdrop-filter: blur(25px) saturate(160%) brightness(110%); + border: 1px solid rgba(255, 255, 255, 0.25); box-shadow: - 0 8px 16px rgba(0, 0, 0, 0.05), - 0 2px 4px rgba(0, 0, 0, 0.04), - 0 0 1px rgba(0, 0, 0, 0.1); + 0 8px 20px rgba(0, 0, 0, 0.12), + inset 0 1px 0 rgba(255, 255, 255, 0.3), + 0 0 0 1px rgba(255, 255, 255, 0.1); + transform: translateY(-2px) scale(1.02); } .dark .nav-item:hover { color: rgba(255, 255, 255, 1); - background: rgba(255, 255, 255, 0.05); - border: 1px solid rgba(255, 255, 255, 0.1); + background: rgba(0, 0, 0, 0.25); + backdrop-filter: blur(30px) saturate(150%) brightness(120%); + -webkit-backdrop-filter: blur(30px) saturate(150%) brightness(120%); + border: 1px solid rgba(255, 255, 255, 0.15); box-shadow: - 0 8px 16px rgba(0, 0, 0, 0.2), - 0 2px 4px rgba(0, 0, 0, 0.15), - 0 0 1px rgba(255, 255, 255, 0.05); + 0 8px 20px rgba(0, 0, 0, 0.3), + inset 0 1px 0 rgba(255, 255, 255, 0.15), + 0 0 0 1px rgba(255, 255, 255, 0.05); } .nav-item.active { color: rgba(15, 23, 42, 1); - background: rgba(255, 255, 255, 0.9); - border: 1px solid rgba(255, 255, 255, 0.25); + background: rgba(255, 255, 255, 0.35); + backdrop-filter: blur(35px) saturate(180%) brightness(115%); + -webkit-backdrop-filter: blur(35px) saturate(180%) brightness(115%); + border: 1px solid rgba(255, 255, 255, 0.4); box-shadow: - 0 8px 20px rgba(0, 0, 0, 0.08), - 0 3px 6px rgba(0, 0, 0, 0.06), - 0 1px 2px rgba(0, 0, 0, 0.04); - font-weight: 600; + 0 12px 24px rgba(0, 0, 0, 0.15), + inset 0 1px 0 rgba(255, 255, 255, 0.5), + 0 0 0 1px rgba(59, 130, 246, 0.3); + transform: translateY(-1px); } .dark .nav-item.active { color: rgba(255, 255, 255, 1); - background: rgba(0, 0, 0, 0.7); - border: 1px solid rgba(255, 255, 255, 0.15); + background: rgba(0, 0, 0, 0.4); + backdrop-filter: blur(40px) saturate(160%) brightness(125%); + -webkit-backdrop-filter: blur(40px) saturate(160%) brightness(125%); + border: 1px solid rgba(255, 255, 255, 0.2); box-shadow: - 0 8px 20px rgba(0, 0, 0, 0.3), - 0 3px 6px rgba(0, 0, 0, 0.2), - 0 0 0 1px rgba(255, 255, 255, 0.06); + 0 12px 24px rgba(0, 0, 0, 0.4), + inset 0 1px 0 rgba(255, 255, 255, 0.2), + 0 0 0 1px rgba(59, 130, 246, 0.2); } /* Dark Mode Toggle - Kompakteres Design */