"feat: Update error handling documentation in frontend files"

This commit is contained in:
Till Tomczak 2025-05-29 20:55:15 +02:00
parent 2ed13acf21
commit 6bbae62b21
5 changed files with 274 additions and 44 deletions

View File

@ -196,3 +196,127 @@ Komplettes Live-Druckererkennungs-System mit Session-Caching und automatischer S
--- ---
## [2024-12-29] Template-Ladeproblem behoben ✅ ## [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
<script src="{{ url_for('static', filename='js/printer_monitor.js') }}"></script>
```
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
<div id="live-status-indicator" class="w-2 h-2 bg-green-500 rounded-full mr-2 animate-pulse"></div>
```
4. **Erweiterte Status-Kategorien**:
- **standby**: Gelb - Drucker bereit aber inaktiv
- **unreachable**: Grau - Netzwerk nicht erreichbar
- **unconfigured**: Indigo - Nicht konfiguriert
5. **Status-Filter erweitert**:
```html
<option value="standby">Standby</option>
<option value="unreachable">Unerreichbar</option>
<option value="unconfigured">Nicht konfiguriert</option>
```
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
---

View File

@ -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") @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]]: 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: Args:
printers: Liste von Drucker-Dictionaries mit 'id' und 'ip_address' printers: Liste der zu prüfenden Drucker
timeout: Timeout in Sekunden pro Drucker (Standard: 7) timeout: Timeout für jeden einzelnen Drucker
Returns: Returns:
Dict[int, Tuple[str, bool]]: Dictionary mit Drucker-ID als Key und (Status, Aktiv) als Value Dict[int, Tuple[str, bool]]: Dictionary mit Drucker-ID als Key und (Status, Aktiv) als Value
""" """
results = {} 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 # 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 # Futures für alle Drucker erstellen
future_to_printer = { future_to_printer = {
executor.submit(check_printer_status, printer.get('ip_address'), timeout): 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)}") printers_logger.error(f"Fehler bei Status-Check für Drucker {printer['name']}: {str(e)}")
results[printer['id']] = ("offline", False) results[printer['id']] = ("offline", False)
printers_logger.info(f"✅ Status-Check abgeschlossen für {len(results)} Drucker")
return results return results
# ===== UI-ROUTEN ===== # ===== UI-ROUTEN =====

Binary file not shown.

Binary file not shown.

View File

@ -789,25 +789,84 @@
width: 100% !important; width: 100% !important;
left: 0 !important; left: 0 !important;
right: 0 !important; right: 0 !important;
@apply bg-white/60 dark:bg-black/70; /* Verstärktes Glassmorphism Design */
backdrop-filter: blur(24px) saturate(200%); background: rgba(255, 255, 255, 0.15) !important;
-webkit-backdrop-filter: blur(24px) saturate(200%); backdrop-filter: blur(40px) saturate(200%) brightness(110%) contrast(105%) !important;
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.08); -webkit-backdrop-filter: blur(40px) saturate(200%) brightness(110%) contrast(105%) !important;
border-bottom: 1px solid rgba(255, 255, 255, 0.15); 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 { .dark .navbar {
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.3), 0 1px 2px rgba(0, 0, 0, 0.2); background: rgba(0, 0, 0, 0.25) !important;
border-bottom: 1px solid rgba(255, 255, 255, 0.05); 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 { .navbar-menu-new {
@apply flex items-center justify-center space-x-0.5 md:space-x-1; @apply flex items-center justify-center space-x-0.5 md:space-x-1;
max-width: 100%; max-width: 100%;
overflow-x: auto; overflow-x: auto;
scrollbar-width: none; scrollbar-width: none;
-ms-overflow-style: 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 { .navbar-menu-new::-webkit-scrollbar {
@ -815,60 +874,95 @@
} }
.nav-item { .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; @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.8); color: rgba(15, 23, 42, 0.85);
background: rgba(255, 255, 255, 0.04); /* 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); border: 1px solid rgba(255, 255, 255, 0.1);
white-space: nowrap; box-shadow:
min-width: fit-content; 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 { .dark .nav-item {
color: rgba(255, 255, 255, 0.8); color: rgba(255, 255, 255, 0.85);
background: rgba(0, 0, 0, 0.2); background: rgba(0, 0, 0, 0.15);
border: 1px solid rgba(255, 255, 255, 0.05); 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 { .nav-item:hover {
@apply transform -translate-y-0.5;
color: rgba(15, 23, 42, 1); color: rgba(15, 23, 42, 1);
background: rgba(255, 255, 255, 0.15); background: rgba(255, 255, 255, 0.2);
border: 1px solid 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: box-shadow:
0 8px 16px rgba(0, 0, 0, 0.05), 0 8px 20px rgba(0, 0, 0, 0.12),
0 2px 4px rgba(0, 0, 0, 0.04), inset 0 1px 0 rgba(255, 255, 255, 0.3),
0 0 1px rgba(0, 0, 0, 0.1); 0 0 0 1px rgba(255, 255, 255, 0.1);
transform: translateY(-2px) scale(1.02);
} }
.dark .nav-item:hover { .dark .nav-item:hover {
color: rgba(255, 255, 255, 1); color: rgba(255, 255, 255, 1);
background: rgba(255, 255, 255, 0.05); background: rgba(0, 0, 0, 0.25);
border: 1px solid rgba(255, 255, 255, 0.1); 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: box-shadow:
0 8px 16px rgba(0, 0, 0, 0.2), 0 8px 20px rgba(0, 0, 0, 0.3),
0 2px 4px rgba(0, 0, 0, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.15),
0 0 1px rgba(255, 255, 255, 0.05); 0 0 0 1px rgba(255, 255, 255, 0.05);
} }
.nav-item.active { .nav-item.active {
color: rgba(15, 23, 42, 1); color: rgba(15, 23, 42, 1);
background: rgba(255, 255, 255, 0.9); background: rgba(255, 255, 255, 0.35);
border: 1px solid rgba(255, 255, 255, 0.25); 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: box-shadow:
0 8px 20px rgba(0, 0, 0, 0.08), 0 12px 24px rgba(0, 0, 0, 0.15),
0 3px 6px rgba(0, 0, 0, 0.06), inset 0 1px 0 rgba(255, 255, 255, 0.5),
0 1px 2px rgba(0, 0, 0, 0.04); 0 0 0 1px rgba(59, 130, 246, 0.3);
font-weight: 600; transform: translateY(-1px);
} }
.dark .nav-item.active { .dark .nav-item.active {
color: rgba(255, 255, 255, 1); color: rgba(255, 255, 255, 1);
background: rgba(0, 0, 0, 0.7); background: rgba(0, 0, 0, 0.4);
border: 1px solid rgba(255, 255, 255, 0.15); 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: box-shadow:
0 8px 20px rgba(0, 0, 0, 0.3), 0 12px 24px rgba(0, 0, 0, 0.4),
0 3px 6px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.2),
0 0 0 1px rgba(255, 255, 255, 0.06); 0 0 0 1px rgba(59, 130, 246, 0.2);
} }
/* Dark Mode Toggle - Kompakteres Design */ /* Dark Mode Toggle - Kompakteres Design */