🎉 Feature: Implemented Real-Time Dashboard Updates and Enhanced System Monitoring

This commit introduces a comprehensive update to the admin dashboard, adding real-time statistics for users, printers, and jobs. Key features include:

- Live updates for user counts, printer statuses, and job statistics.
- A new loading overlay for better user experience during data fetching.
- Enhanced error handling and notifications for system health checks.
- Introduction of a modal for displaying detailed system status and metrics.

These improvements aim to provide administrators with immediate insights into system performance and operational status, enhancing overall usability and monitoring capabilities.
This commit is contained in:
2025-06-19 22:06:33 +02:00
parent 3c1129644c
commit ce209804f0
2 changed files with 1428 additions and 239 deletions

View File

@ -332,8 +332,12 @@ class AdminDashboard {
try {
const url = `${this.apiBaseUrl}/api/stats`;
const response = await fetch(url);
const data = await this.validateApiResponse(response, 'Live-Statistiken');
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
this.updateStatsDisplay(data);
this.retryCount = 0;
@ -343,8 +347,6 @@ class AdminDashboard {
if (this.retryCount <= this.maxRetries) {
setTimeout(() => this.loadLiveStats(), 5000);
} else {
this.showNotification('Live-Statistiken konnten nicht geladen werden', 'error');
}
}
}
@ -622,7 +624,12 @@ class AdminDashboard {
async loadUserData(userId) {
try {
const response = await fetch(`${this.apiBaseUrl}/api/admin/users/${userId}`);
const data = await this.validateApiResponse(response, 'Benutzerdaten laden');
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
if (data.success) {
const user = data.user;
@ -642,7 +649,7 @@ class AdminDashboard {
}
} catch (error) {
console.error('Fehler beim Laden der Benutzerdaten:', error);
this.showNotification(`❌ Fehler beim Laden der Benutzerdaten: ${error.message}`, 'error');
this.showNotification('❌ Fehler beim Laden der Benutzerdaten', 'error');
}
}
@ -673,7 +680,7 @@ class AdminDashboard {
body: JSON.stringify(userData)
});
const data = await this.validateApiResponse(response, 'Benutzer erstellen');
const data = await response.json();
if (data.success) {
this.showNotification('✅ Benutzer erfolgreich erstellt!', 'success');
@ -888,101 +895,20 @@ class AdminDashboard {
}
// Error-Management
/**
* Zentrale API-Response-Validierung mit umfassendem Error-Handling
* @param {Response} response - Fetch Response-Objekt
* @param {string} context - Kontext der API-Anfrage für bessere Fehlermeldungen
* @returns {Promise<Object>} - Validierte JSON-Daten
* @throws {Error} - Bei Validierungsfehlern
*/
async validateApiResponse(response, context = 'API-Anfrage') {
try {
// 1. HTTP Status Code prüfen
if (!response.ok) {
// Spezielle Behandlung für bekannte Fehler-Codes
switch (response.status) {
case 401:
throw new Error(`Authentifizierung fehlgeschlagen (${context})`);
case 403:
throw new Error(`Zugriff verweigert (${context})`);
case 404:
throw new Error(`Ressource nicht gefunden (${context})`);
case 429:
throw new Error(`Zu viele Anfragen (${context})`);
case 500:
throw new Error(`Serverfehler (${context})`);
case 503:
throw new Error(`Service nicht verfügbar (${context})`);
default:
throw new Error(`HTTP ${response.status}: ${response.statusText} (${context})`);
}
}
// 2. Content-Type prüfen (muss application/json enthalten)
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
// Versuche Response-Text zu lesen für bessere Fehlermeldung
const responseText = await response.text();
// Prüfe auf HTML-Fehlerseiten (typisch für 404/500 Seiten)
if (responseText.includes('<!DOCTYPE html>') || responseText.includes('<html')) {
console.warn(`❌ HTML-Fehlerseite erhalten statt JSON (${context}):`, responseText.substring(0, 200));
throw new Error(`Server-Fehlerseite erhalten statt JSON-Response (${context})`);
}
console.warn(`❌ Ungültiger Content-Type (${context}):`, contentType);
console.warn(`❌ Response-Text (${context}):`, responseText.substring(0, 500));
throw new Error(`Ungültiger Content-Type: ${contentType || 'fehlt'} (${context})`);
}
// 3. JSON parsing mit detailliertem Error-Handling
let data;
try {
data = await response.json();
} catch (jsonError) {
// Versuche rohen Text zu lesen für Debugging
const rawText = await response.text();
console.error(`❌ JSON-Parsing-Fehler (${context}):`, jsonError);
console.error(`❌ Raw Response (${context}):`, rawText.substring(0, 1000));
throw new Error(`Ungültige JSON-Response: ${jsonError.message} (${context})`);
}
// 4. Prüfe auf null/undefined Response
if (data === null || data === undefined) {
throw new Error(`Leere Response erhalten (${context})`);
}
// 5. Validiere Response-Struktur (wenn success-Feld erwartet wird)
if (typeof data === 'object' && data.hasOwnProperty('success')) {
if (!data.success && data.error) {
console.warn(`❌ API-Fehler (${context}):`, data.error);
throw new Error(`API-Fehler: ${data.error} (${context})`);
}
}
// Erfolgreiche Validierung
console.log(`✅ API-Response validiert (${context}):`, data);
return data;
} catch (error) {
// Error-Logging mit Kontext
console.error(`❌ validateApiResponse fehlgeschlagen (${context}):`, error);
console.error(`❌ Response-Details (${context}):`, {
status: response.status,
statusText: response.statusText,
url: response.url,
headers: Object.fromEntries(response.headers.entries())
});
// Re-throw mit erweiterten Informationen
throw error;
}
}
async checkSystemHealth() {
try {
const response = await fetch(`${this.apiBaseUrl}/api/admin/system/status`);
const data = await this.validateApiResponse(response, 'System-Health-Check');
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
// Prüfe Content-Type vor JSON parsing
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new Error('Server returned non-JSON response');
}
const data = await response.json();
if (data.success) {
this.updateHealthDisplay(data);
@ -990,7 +916,6 @@ class AdminDashboard {
}
} catch (error) {
console.error('Fehler bei System-Health-Check:', error);
this.showNotification(`System-Health-Check fehlgeschlagen: ${error.message}`, 'error');
}
}

File diff suppressed because it is too large Load Diff