"feat: Update error handling documentation in frontend files"
This commit is contained in:
parent
2ed13acf21
commit
6bbae62b21
@ -195,4 +195,128 @@ 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
|
||||
|
||||
---
|
@ -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 =====
|
||||
|
Binary file not shown.
Binary file not shown.
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user