/** * Mercedes-Benz MYP Admin Dashboard - Unified JavaScript * Konsolidierte Admin-Funktionalitäten ohne Event-Handler-Konflikte */ // Globale Variablen und State-Management class AdminDashboard { constructor() { this.csrfToken = null; this.updateInterval = null; this.eventListenersAttached = false; this.apiBaseUrl = this.detectApiBaseUrl(); this.retryCount = 0; this.maxRetries = 3; this.isInitialized = false; this.init(); } detectApiBaseUrl() { const currentHost = window.location.hostname; const currentPort = window.location.port; if (currentPort === '5000') { return ''; } return `http://${currentHost}:5000`; } init() { if (this.isInitialized) { console.log('🔄 Admin Dashboard bereits initialisiert, überspringe...'); return; } console.log('🚀 Initialisiere Mercedes-Benz MYP Admin Dashboard'); // CSRF Token mit verbesserter Extraktion this.csrfToken = this.extractCSRFToken(); console.log('🔒 CSRF Token:', this.csrfToken ? 'verfügbar' : 'FEHLT!'); // Event-Listener nur einmal registrieren this.attachEventListeners(); // Live-Updates starten this.startLiveUpdates(); // Initiale Daten laden this.loadInitialData(); this.isInitialized = true; console.log('✅ Admin Dashboard erfolgreich initialisiert'); } extractCSRFToken() { // Methode 1: Meta Tag const metaToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content'); if (metaToken) { console.log('🔒 CSRF Token aus meta Tag geladen'); return metaToken; } // Methode 2: Hidden Input const hiddenInput = document.querySelector('input[name="csrf_token"]')?.value; if (hiddenInput) { console.log('🔒 CSRF Token aus hidden input geladen'); return hiddenInput; } // Methode 3: Cookie (falls verfügbar) const cookieToken = document.cookie.split('; ').find(row => row.startsWith('csrf_token='))?.split('=')[1]; if (cookieToken) { console.log('🔒 CSRF Token aus Cookie geladen'); return cookieToken; } // Methode 4: Flask-WTF Standard const flaskToken = document.querySelector('meta[name="csrf-token"]')?.content; if (flaskToken) { console.log('🔒 CSRF Token aus Flask-WTF Meta geladen'); return flaskToken; } console.error('❌ CSRF Token konnte nicht gefunden werden!'); return null; } attachEventListeners() { if (this.eventListenersAttached) { console.log('⚠️ Event-Listener bereits registriert, überspringe...'); return; } // System-Action-Buttons mit Event-Delegation this.attachSystemButtons(); this.attachUserManagement(); this.attachPrinterManagement(); this.attachJobManagement(); this.attachModalEvents(); this.eventListenersAttached = true; console.log('📌 Event-Listener erfolgreich registriert'); } attachSystemButtons() { // System Status Button this.addEventListenerSafe('#system-status-btn', 'click', (e) => { e.preventDefault(); e.stopPropagation(); this.showSystemStatus(); }); // Analytics Button this.addEventListenerSafe('#analytics-btn', 'click', (e) => { e.preventDefault(); e.stopPropagation(); this.showAnalytics(); }); // Maintenance Button - DEAKTIVIERT wegen Konflikt mit MaintenanceModal // Das Wartungs-Modal wird jetzt direkt in admin.html verwaltet // this.addEventListenerSafe('#maintenance-btn', 'click', (e) => { // e.preventDefault(); // e.stopPropagation(); // this.showMaintenance(); // }); // Cache leeren this.addEventListenerSafe('#clear-cache-btn', 'click', (e) => { e.preventDefault(); e.stopPropagation(); this.clearSystemCache(); }); // Datenbank optimieren this.addEventListenerSafe('#optimize-db-btn', 'click', (e) => { e.preventDefault(); e.stopPropagation(); this.optimizeDatabase(); }); // Backup erstellen this.addEventListenerSafe('#create-backup-btn', 'click', (e) => { e.preventDefault(); e.stopPropagation(); this.createSystemBackup(); }); // Drucker-Initialisierung erzwingen this.addEventListenerSafe('#force-init-printers-btn', 'click', (e) => { e.preventDefault(); e.stopPropagation(); this.forceInitializePrinters(); }); } attachUserManagement() { // Neuer Benutzer Button this.addEventListenerSafe('#add-user-btn', 'click', (e) => { e.preventDefault(); e.stopPropagation(); this.showUserModal(); }); // Event-Delegation für Benutzer-Aktionen document.addEventListener('click', (e) => { if (e.target.closest('.edit-user-btn')) { e.preventDefault(); e.stopPropagation(); const userId = e.target.closest('button').dataset.userId; this.editUser(userId); } if (e.target.closest('.delete-user-btn')) { e.preventDefault(); e.stopPropagation(); const userId = e.target.closest('button').dataset.userId; const userName = e.target.closest('button').dataset.userName; this.deleteUser(userId, userName); } }); } attachPrinterManagement() { // Drucker hinzufügen Button this.addEventListenerSafe('#add-printer-btn', 'click', (e) => { e.preventDefault(); e.stopPropagation(); this.showPrinterModal(); }); // Event-Delegation für Drucker-Aktionen document.addEventListener('click', (e) => { if (e.target.closest('.manage-printer-btn')) { e.preventDefault(); e.stopPropagation(); const printerId = e.target.closest('button').dataset.printerId; this.managePrinter(printerId); } if (e.target.closest('.settings-printer-btn')) { e.preventDefault(); e.stopPropagation(); const printerId = e.target.closest('button').dataset.printerId; this.showPrinterSettings(printerId); } }); } attachJobManagement() { // Event-Delegation für Job-Aktionen document.addEventListener('click', (e) => { if (e.target.closest('.job-action-btn')) { e.preventDefault(); e.stopPropagation(); const action = e.target.closest('button').dataset.action; const jobId = e.target.closest('button').dataset.jobId; this.handleJobAction(action, jobId); } }); } attachModalEvents() { // Error-Alert Buttons this.addEventListenerSafe('#fix-errors-btn', 'click', (e) => { e.preventDefault(); e.stopPropagation(); this.fixErrors(); }); this.addEventListenerSafe('#dismiss-errors-btn', 'click', (e) => { e.preventDefault(); e.stopPropagation(); this.dismissErrors(); }); this.addEventListenerSafe('#view-error-details-btn', 'click', (e) => { e.preventDefault(); e.stopPropagation(); window.location.href = '/admin-dashboard?tab=logs'; }); // Logs-Funktionalität this.addEventListenerSafe('#refresh-logs-btn', 'click', (e) => { e.preventDefault(); e.stopPropagation(); this.loadLogs(); }); this.addEventListenerSafe('#export-logs-btn', 'click', (e) => { e.preventDefault(); e.stopPropagation(); this.exportLogs(); }); this.addEventListenerSafe('#log-level-filter', 'change', (e) => { this.loadLogs(); }); } addEventListenerSafe(selector, event, handler) { const element = document.querySelector(selector); if (element && !element.dataset.listenerAttached) { element.addEventListener(event, handler); element.dataset.listenerAttached = 'true'; } } startLiveUpdates() { if (this.updateInterval) { clearInterval(this.updateInterval); } // Statistiken alle 30 Sekunden aktualisieren this.updateInterval = setInterval(() => { this.loadLiveStats(); }, 30000); // Live-Zeit jede Sekunde aktualisieren setInterval(() => { this.updateLiveTime(); }, 1000); // System-Health alle 30 Sekunden prüfen setInterval(() => { this.checkSystemHealth(); }, 30000); console.log('🔄 Live-Updates gestartet'); } async loadInitialData() { await this.loadLiveStats(); await this.checkSystemHealth(); // Button-Test ausführen setTimeout(() => { this.testButtons(); }, 1000); // Logs laden falls wir auf dem Logs-Tab sind if (window.location.search.includes('tab=logs') || document.querySelector('.tabs [href*="logs"]')?.classList.contains('active')) { await this.loadLogs(); } // Prüfe auch ob der Logs-Tab durch die URL-Parameter aktiv ist const urlParams = new URLSearchParams(window.location.search); const activeTab = urlParams.get('tab'); if (activeTab === 'logs') { await this.loadLogs(); } // Oder prüfe ob das Logs-Container-Element sichtbar ist const logsContainer = document.getElementById('logs-container'); if (logsContainer && logsContainer.offsetParent !== null) { await this.loadLogs(); } } async loadLiveStats() { try { const url = `${this.apiBaseUrl}/api/stats`; const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); this.updateStatsDisplay(data); this.retryCount = 0; } catch (error) { console.error('Fehler beim Laden der Live-Statistiken:', error); this.retryCount++; if (this.retryCount <= this.maxRetries) { setTimeout(() => this.loadLiveStats(), 5000); } } } updateStatsDisplay(data) { // Sichere Updates mit null-Checks this.updateElement('live-users-count', data.total_users || 0); this.updateElement('live-printers-count', data.total_printers || 0); this.updateElement('live-printers-online', `${data.online_printers || 0} online`); this.updateElement('live-jobs-active', data.active_jobs || 0); this.updateElement('live-jobs-queued', `${data.queued_jobs || 0} in Warteschlange`); this.updateElement('live-success-rate', `${data.success_rate || 0}%`); // Progress Bars aktualisieren this.updateProgressBar('users-progress', data.total_users, 20); this.updateProgressBar('printers-progress', data.online_printers, data.total_printers); this.updateProgressBar('jobs-progress', data.active_jobs, 10); this.updateProgressBar('success-progress', data.success_rate, 100); console.log('📊 Live-Statistiken aktualisiert'); } updateElement(elementId, value) { const element = document.getElementById(elementId); if (element) { element.textContent = value; } } updateProgressBar(progressId, currentValue, maxValue) { const progressEl = document.getElementById(progressId); if (progressEl && currentValue !== undefined && maxValue > 0) { const percentage = Math.min(100, Math.max(0, (currentValue / maxValue) * 100)); progressEl.style.width = `${percentage}%`; } } updateLiveTime() { const timeElement = document.getElementById('live-time'); if (timeElement) { const now = new Date(); timeElement.textContent = now.toLocaleTimeString('de-DE'); } } // System-Funktionen async showSystemStatus() { console.log('🔧 System Status wird angezeigt'); this.showNotification('System Status wird geladen...', 'info'); } async showAnalytics() { console.log('📈 Analytics wird angezeigt'); this.showNotification('Analytics werden geladen...', 'info'); } async showMaintenance() { console.log('🛠️ Wartung wird angezeigt'); const systemTab = document.querySelector('a[href*="tab=system"]'); if (systemTab) { systemTab.click(); } } async clearSystemCache() { if (!confirm('🗑️ Möchten Sie wirklich den System-Cache leeren?')) return; try { const response = await fetch(`${this.apiBaseUrl}/api/admin/cache/clear`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': this.csrfToken } }); const data = await response.json(); if (data.success) { this.showNotification('✅ Cache erfolgreich geleert!', 'success'); setTimeout(() => window.location.reload(), 2000); } else { this.showNotification('❌ Fehler beim Leeren des Cache', 'error'); } } catch (error) { this.showNotification('❌ Fehler beim Leeren des Cache', 'error'); } } async optimizeDatabase() { if (!confirm('🔧 Möchten Sie die Datenbank optimieren?')) return; this.showNotification('🔄 Datenbank wird optimiert...', 'info'); try { const response = await fetch(`${this.apiBaseUrl}/api/admin/database/optimize`, { method: 'POST', headers: { 'X-CSRFToken': this.csrfToken } }); const data = await response.json(); if (data.success) { this.showNotification('✅ Datenbank erfolgreich optimiert!', 'success'); } else { this.showNotification('❌ Fehler bei der Datenbank-Optimierung', 'error'); } } catch (error) { this.showNotification('❌ Fehler bei der Datenbank-Optimierung', 'error'); } } async createSystemBackup() { if (!confirm('💾 Möchten Sie ein System-Backup erstellen?')) return; this.showNotification('🔄 Backup wird erstellt...', 'info'); try { const response = await fetch(`${this.apiBaseUrl}/api/admin/backup/create`, { method: 'POST', headers: { 'X-CSRFToken': this.csrfToken } }); const data = await response.json(); if (data.success) { this.showNotification('✅ Backup erfolgreich erstellt!', 'success'); } else { this.showNotification('❌ Fehler beim Erstellen des Backups', 'error'); } } catch (error) { this.showNotification('❌ Fehler beim Erstellen des Backups', 'error'); } } async forceInitializePrinters() { if (!confirm('🔄 Möchten Sie die Drucker-Initialisierung erzwingen?')) return; this.showNotification('🔄 Drucker werden initialisiert...', 'info'); try { const response = await fetch(`${this.apiBaseUrl}/api/admin/printers/force-init`, { method: 'POST', headers: { 'X-CSRFToken': this.csrfToken } }); const data = await response.json(); if (data.success) { this.showNotification('✅ Drucker erfolgreich initialisiert!', 'success'); setTimeout(() => window.location.reload(), 2000); } else { this.showNotification('❌ Fehler bei der Drucker-Initialisierung', 'error'); } } catch (error) { this.showNotification('❌ Fehler bei der Drucker-Initialisierung', 'error'); } } // User-Management showUserModal(userId = null) { const isEdit = userId !== null; const title = isEdit ? 'Benutzer bearbeiten' : 'Neuer Benutzer'; // Modal HTML erstellen const modalHtml = `

${title}

${isEdit ? `
` : ''}
`; // Modal zum DOM hinzufügen document.body.insertAdjacentHTML('beforeend', modalHtml); // Event-Listener für das Formular const form = document.getElementById('user-form'); form.addEventListener('submit', (e) => { e.preventDefault(); e.stopPropagation(); if (isEdit) { this.updateUser(userId, new FormData(form)); } else { this.createUser(new FormData(form)); } }); // Bei Bearbeitung: Benutzer-Daten laden if (isEdit) { this.loadUserData(userId); } // Fokus auf erstes Eingabefeld setTimeout(() => { document.getElementById('user-email').focus(); }, 100); } async loadUserData(userId) { try { const response = await fetch(`${this.apiBaseUrl}/api/admin/users/${userId}`); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); if (data.success) { const user = data.user; // Formular mit Benutzerdaten füllen document.getElementById('user-email').value = user.email || ''; document.getElementById('user-username').value = user.username || ''; document.getElementById('user-name').value = user.name || ''; document.getElementById('user-role').value = user.is_admin ? 'admin' : 'user'; const activeCheckbox = document.getElementById('user-active'); if (activeCheckbox) { activeCheckbox.checked = user.is_active !== false; } } else { this.showNotification('❌ Fehler beim Laden der Benutzerdaten', 'error'); } } catch (error) { console.error('Fehler beim Laden der Benutzerdaten:', error); this.showNotification('❌ Fehler beim Laden der Benutzerdaten', 'error'); } } async createUser(formData) { const submitBtn = document.getElementById('user-submit-btn'); const originalText = submitBtn.innerHTML; try { // Loading-Zustand submitBtn.innerHTML = '
'; submitBtn.disabled = true; // FormData zu JSON konvertieren const userData = { email: formData.get('email'), username: formData.get('username') || formData.get('email').split('@')[0], name: formData.get('name'), password: formData.get('password'), is_admin: formData.get('role') === 'admin' }; const response = await fetch(`${this.apiBaseUrl}/api/admin/users`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': this.csrfToken }, body: JSON.stringify(userData) }); const data = await response.json(); if (data.success) { this.showNotification('✅ Benutzer erfolgreich erstellt!', 'success'); document.getElementById('user-modal').remove(); // Seite nach 1 Sekunde neu laden um neue Benutzerliste zu zeigen setTimeout(() => { window.location.reload(); }, 1000); } else { this.showNotification(`❌ Fehler: ${data.error}`, 'error'); } } catch (error) { console.error('Fehler beim Erstellen des Benutzers:', error); this.showNotification('❌ Fehler beim Erstellen des Benutzers', 'error'); } finally { // Button zurücksetzen submitBtn.innerHTML = originalText; submitBtn.disabled = false; } } async updateUser(userId, formData) { const submitBtn = document.getElementById('user-submit-btn'); const originalText = submitBtn.innerHTML; try { // Loading-Zustand submitBtn.innerHTML = '
'; submitBtn.disabled = true; // FormData zu JSON konvertieren const userData = { email: formData.get('email'), username: formData.get('username'), name: formData.get('name'), is_admin: formData.get('role') === 'admin', is_active: formData.get('is_active') === 'on' }; // Passwort nur hinzufügen wenn es gesetzt wurde const password = formData.get('password'); if (password && password.trim()) { userData.password = password; } const response = await fetch(`${this.apiBaseUrl}/api/admin/users/${userId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': this.csrfToken }, body: JSON.stringify(userData) }); const data = await response.json(); if (data.success) { this.showNotification('✅ Benutzer erfolgreich aktualisiert!', 'success'); document.getElementById('user-modal').remove(); // Seite nach 1 Sekunde neu laden um aktualisierte Benutzerliste zu zeigen setTimeout(() => { window.location.reload(); }, 1000); } else { this.showNotification(`❌ Fehler: ${data.error}`, 'error'); } } catch (error) { console.error('Fehler beim Aktualisieren des Benutzers:', error); this.showNotification('❌ Fehler beim Aktualisieren des Benutzers', 'error'); } finally { // Button zurücksetzen submitBtn.innerHTML = originalText; submitBtn.disabled = false; } } editUser(userId) { console.log(`✏️ Benutzer ${userId} wird bearbeitet`); this.showUserModal(userId); } async deleteUser(userId, userName) { if (!confirm(`🗑️ Möchten Sie den Benutzer "${userName}" wirklich löschen?\n\nDiese Aktion kann nicht rückgängig gemacht werden!`)) { return; } try { this.showNotification(`🔄 Benutzer "${userName}" wird gelöscht...`, 'info'); const response = await fetch(`${this.apiBaseUrl}/api/admin/users/${userId}`, { method: 'DELETE', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': this.csrfToken } }); const data = await response.json(); if (data.success) { this.showNotification(`✅ Benutzer "${userName}" erfolgreich gelöscht!`, 'success'); // Seite nach 1 Sekunde neu laden um aktualisierte Benutzerliste zu zeigen setTimeout(() => { window.location.reload(); }, 1000); } else { this.showNotification(`❌ Fehler beim Löschen: ${data.error}`, 'error'); } } catch (error) { console.error('Fehler beim Löschen des Benutzers:', error); this.showNotification('❌ Fehler beim Löschen des Benutzers', 'error'); } } // Printer-Management showPrinterModal() { console.log('🖨️ Drucker-Modal wird angezeigt'); this.showNotification('Drucker-Funktionen werden geladen...', 'info'); } managePrinter(printerId) { console.log(`🔧 Drucker ${printerId} wird verwaltet`); this.showNotification(`Drucker ${printerId} wird verwaltet...`, 'info'); } showPrinterSettings(printerId) { console.log(`⚙️ Drucker-Einstellungen ${printerId} werden angezeigt`); this.showNotification(`Drucker-Einstellungen werden geladen...`, 'info'); } // Job-Management handleJobAction(action, jobId) { console.log(`📋 Job-Aktion "${action}" für Job ${jobId}`); this.showNotification(`Job-Aktion "${action}" wird ausgeführt...`, 'info'); } // Error-Management async checkSystemHealth() { try { const response = await fetch('/api/admin/system-health'); const data = await response.json(); if (data.success) { this.updateHealthDisplay(data); this.updateErrorAlerts(data); } } catch (error) { console.error('Fehler bei System-Health-Check:', error); } } updateHealthDisplay(data) { const statusIndicator = document.getElementById('db-status-indicator'); const statusText = document.getElementById('db-status-text'); if (statusIndicator && statusText) { if (data.health_status === 'critical') { statusIndicator.className = 'w-3 h-3 bg-red-500 rounded-full animate-pulse'; statusText.textContent = 'Kritisch'; statusText.className = 'text-sm font-medium text-red-600 dark:text-red-400'; } else if (data.health_status === 'warning') { statusIndicator.className = 'w-3 h-3 bg-yellow-500 rounded-full animate-pulse'; statusText.textContent = 'Warnung'; statusText.className = 'text-sm font-medium text-yellow-600 dark:text-yellow-400'; } else { statusIndicator.className = 'w-3 h-3 bg-green-400 rounded-full animate-pulse'; statusText.textContent = 'Gesund'; statusText.className = 'text-sm font-medium text-green-600 dark:text-green-400'; } } this.updateElement('last-migration', data.last_migration || 'Unbekannt'); this.updateElement('schema-integrity', data.schema_integrity || 'Prüfung'); this.updateElement('recent-errors-count', data.recent_errors_count || 0); } updateErrorAlerts(data) { const alertContainer = document.getElementById('critical-errors-alert'); if (!alertContainer) return; const allErrors = [...(data.critical_errors || []), ...(data.warnings || [])]; if (allErrors.length > 0) { alertContainer.classList.remove('hidden'); } else { alertContainer.classList.add('hidden'); } } async fixErrors() { if (!confirm('🔧 Möchten Sie die automatische Fehlerkorrektur durchführen?')) return; this.showNotification('🔄 Fehler werden automatisch behoben...', 'info'); // Debug: CSRF Token prüfen if (!this.csrfToken) { console.error('❌ CSRF Token fehlt! Versuche Token neu zu laden...'); this.csrfToken = this.extractCSRFToken(); if (!this.csrfToken) { this.showNotification('❌ Sicherheitsfehler: CSRF Token nicht verfügbar', 'error'); return; } } console.log('🔧 Starte automatische Fehlerkorrektur...'); console.log('🔒 CSRF Token für Request:', this.csrfToken.substring(0, 10) + '...'); try { const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': this.csrfToken } }; console.log('📡 Sende Request an:', '/api/admin/fix-errors'); console.log('📝 Request Headers:', requestOptions.headers); const response = await fetch('/api/admin/fix-errors', requestOptions); console.log('📡 Response Status:', response.status); console.log('📡 Response Headers:', Object.fromEntries(response.headers.entries())); if (!response.ok) { const errorText = await response.text(); console.error('❌ Response Error:', errorText); throw new Error(`HTTP ${response.status}: ${response.statusText} - ${errorText}`); } const data = await response.json(); console.log('✅ Response Data:', data); if (data.success) { this.showNotification('✅ Automatische Reparatur erfolgreich!', 'success'); setTimeout(() => this.checkSystemHealth(), 2000); } else { this.showNotification(`❌ Automatische Reparatur fehlgeschlagen: ${data.message || 'Unbekannter Fehler'}`, 'error'); } } catch (error) { console.error('❌ Fehler bei automatischer Reparatur:', error); this.showNotification(`❌ Fehler bei der automatischen Reparatur: ${error.message}`, 'error'); } } dismissErrors() { const alertContainer = document.getElementById('critical-errors-alert'); if (alertContainer) { alertContainer.classList.add('hidden'); } } // Notification System showNotification(message, type = 'info') { let notification = document.getElementById('admin-notification'); if (!notification) { notification = document.createElement('div'); notification.id = 'admin-notification'; notification.className = 'fixed top-4 right-4 z-50 p-4 rounded-lg shadow-lg max-w-sm transition-all duration-300'; document.body.appendChild(notification); } const colors = { success: 'bg-green-500 text-white', error: 'bg-red-500 text-white', info: 'bg-blue-500 text-white', warning: 'bg-yellow-500 text-white' }; notification.className = `fixed top-4 right-4 z-50 p-4 rounded-lg shadow-lg max-w-sm transition-all duration-300 ${colors[type]}`; notification.textContent = message; notification.style.transform = 'translateX(0)'; // Auto-Hide nach 3 Sekunden setTimeout(() => { if (notification) { notification.style.transform = 'translateX(100%)'; setTimeout(() => { if (notification && notification.parentNode) { notification.parentNode.removeChild(notification); } }, 300); } }, 3000); } /** * Logs-Management Funktionen */ async loadLogs(level = null) { const logsContainer = document.getElementById('logs-container'); if (!logsContainer) return; // Loading-Indikator anzeigen logsContainer.innerHTML = `
Logs werden geladen...
`; try { const filter = level || document.getElementById('log-level-filter')?.value || 'all'; const url = `${this.apiBaseUrl}/api/admin/logs?level=${filter}&limit=100`; const response = await fetch(url, { headers: { 'X-CSRFToken': this.csrfToken } }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } const data = await response.json(); this.displayLogs(data.logs || []); console.log('📋 Logs erfolgreich geladen'); } catch (error) { console.error('Fehler beim Laden der Logs:', error); logsContainer.innerHTML = `

Fehler beim Laden der Logs

${error.message}

`; } } displayLogs(logs) { const logsContainer = document.getElementById('logs-container'); if (!logsContainer) return; if (!logs || logs.length === 0) { logsContainer.innerHTML = `

Keine Logs gefunden

Es sind keine Logs für die ausgewählten Kriterien vorhanden.

`; return; } const logsHtml = logs.map(log => { const levelColors = { 'error': 'bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800 text-red-800 dark:text-red-200', 'warning': 'bg-yellow-50 dark:bg-yellow-900/20 border-yellow-200 dark:border-yellow-800 text-yellow-800 dark:text-yellow-200', 'info': 'bg-blue-50 dark:bg-blue-900/20 border-blue-200 dark:border-blue-800 text-blue-800 dark:text-blue-200', 'debug': 'bg-gray-50 dark:bg-gray-900/20 border-gray-200 dark:border-gray-800 text-gray-800 dark:text-gray-200', 'critical': 'bg-red-100 dark:bg-red-900/40 border-red-300 dark:border-red-700 text-red-900 dark:text-red-100' }; const levelIcons = { 'error': '❌', 'warning': '⚠️', 'info': 'ℹ️', 'debug': '🔍', 'critical': '🚨' }; const levelClass = levelColors[log.level] || levelColors['info']; const levelIcon = levelIcons[log.level] || 'ℹ️'; return `
${levelIcon} ${log.level} ${log.component || 'System'}
${this.formatLogTimestamp(log.timestamp)}

${this.escapeHtml(log.message)}

${log.details ? `

${this.escapeHtml(log.details)}

` : ''}
${log.user ? `
Benutzer: ${this.escapeHtml(log.user)}
` : ''} ${log.ip_address ? `
IP: ${this.escapeHtml(log.ip_address)}
` : ''} ${log.request_id ? `
Request-ID: ${this.escapeHtml(log.request_id)}
` : ''}
`; }).join(''); logsContainer.innerHTML = logsHtml; } formatLogTimestamp(timestamp) { if (!timestamp) return 'Unbekannt'; try { const date = new Date(timestamp); return date.toLocaleString('de-DE', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit' }); } catch (error) { return timestamp; } } escapeHtml(text) { if (!text) return ''; const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } async exportLogs() { try { this.showNotification('📥 Logs werden exportiert...', 'info'); const filter = document.getElementById('log-level-filter')?.value || 'all'; const url = `${this.apiBaseUrl}/api/admin/logs/export?level=${filter}`; const response = await fetch(url, { headers: { 'X-CSRFToken': this.csrfToken } }); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } // Download als Datei const blob = await response.blob(); const downloadUrl = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = downloadUrl; a.download = `system-logs-${new Date().toISOString().split('T')[0]}.csv`; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(downloadUrl); this.showNotification('✅ Logs erfolgreich exportiert!', 'success'); } catch (error) { console.error('Fehler beim Exportieren der Logs:', error); this.showNotification('❌ Fehler beim Exportieren der Logs: ' + error.message, 'error'); } } // ===== BUTTON-FUNKTIONALITÄT-TEST ===== testButtons() { console.log('🧪 Teste Button-Funktionalität...'); // Teste Fix-Errors Button const fixBtn = document.querySelector('#fix-errors-btn'); if (fixBtn) { console.log('✅ Fix-Errors Button gefunden:', fixBtn); console.log('🔗 Event-Listener-Status:', fixBtn.dataset.listenerAttached); // Manueller Test-Click fixBtn.addEventListener('click', (e) => { console.log('🖱️ Fix-Errors Button wurde geklickt (manueller Listener)'); e.preventDefault(); e.stopPropagation(); this.testFixErrors(); }); } else { console.error('❌ Fix-Errors Button NICHT gefunden!'); } // Teste View-Details Button const viewBtn = document.querySelector('#view-error-details-btn'); if (viewBtn) { console.log('✅ View-Details Button gefunden:', viewBtn); console.log('🔗 Event-Listener-Status:', viewBtn.dataset.listenerAttached); // Manueller Test-Click viewBtn.addEventListener('click', (e) => { console.log('🖱️ View-Details Button wurde geklickt (manueller Listener)'); e.preventDefault(); e.stopPropagation(); console.log('🔄 Weiterleitung zu Logs-Tab...'); window.location.href = '/admin-dashboard?tab=logs'; }); } else { console.error('❌ View-Details Button NICHT gefunden!'); } } // Test-Version der Fix-Errors Funktion async testFixErrors() { console.log('🧪 TEST: Fix-Errors wird ausgeführt...'); // Token-Test console.log('🔒 Aktueller CSRF Token:', this.csrfToken); if (!this.csrfToken) { console.error('❌ CSRF Token fehlt - versuche neu zu laden...'); this.csrfToken = this.extractCSRFToken(); console.log('🔒 Neu geladener Token:', this.csrfToken); } this.showNotification('🧪 TEST: Starte automatische Fehlerkorrektur...', 'info'); try { const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRFToken': this.csrfToken, 'X-Requested-With': 'XMLHttpRequest' } }; console.log('📡 TEST Request an:', '/api/admin/fix-errors'); console.log('📝 TEST Headers:', requestOptions.headers); const response = await fetch('/api/admin/fix-errors', requestOptions); console.log('📡 TEST Response Status:', response.status); console.log('📡 TEST Response Headers:', Object.fromEntries(response.headers.entries())); if (!response.ok) { const errorText = await response.text(); console.error('❌ TEST Response Error:', errorText); this.showNotification(`❌ TEST Fehler: ${response.status} - ${errorText}`, 'error'); return; } const data = await response.json(); console.log('✅ TEST Response Data:', data); if (data.success) { this.showNotification('✅ TEST: Automatische Reparatur erfolgreich!', 'success'); } else { this.showNotification(`❌ TEST: Reparatur fehlgeschlagen - ${data.message}`, 'error'); } } catch (error) { console.error('❌ TEST Fehler:', error); this.showNotification(`❌ TEST Netzwerk-Fehler: ${error.message}`, 'error'); } } } // Sichere Initialisierung - nur einmal ausführen let adminDashboardInstance = null; document.addEventListener('DOMContentLoaded', function() { if (!adminDashboardInstance) { adminDashboardInstance = new AdminDashboard(); window.AdminDashboard = adminDashboardInstance; console.log('🎯 Admin Dashboard erfolgreich initialisiert (unified)'); } }); // Export für globalen Zugriff window.AdminDashboard = AdminDashboard;