/** * Admin Panel JavaScript * Handles the functionality of the admin panel interface */ document.addEventListener('DOMContentLoaded', function() { // Initialize admin panel initializeAdminPanel(); // Load initial data loadAdminStats(); // Initialisiere den aktiven Tab basierend auf der URL oder default initializeActiveTab(); // Initialize modals and button event handlers initializeEventHandlers(); // Set up auto-refresh timer (every 30 seconds) setInterval(function() { if (document.visibilityState === 'visible') { refreshActiveTabData(); } }, 30000); }); // Initialisiere den aktiven Tab function initializeActiveTab() { // Prüfe URL Hash const hash = window.location.hash.substring(1); if (hash) { activateTab(hash); } else { // Default Tab laden const defaultTab = document.querySelector('.nav-tab'); if (defaultTab) { const tabName = defaultTab.getAttribute('data-tab'); activateTab(tabName); } } } // Aktiviere einen Tab und lade seine Daten function activateTab(tabName) { // UI aktualisieren const tabs = document.querySelectorAll('.nav-tab'); tabs.forEach(tab => { if (tab.getAttribute('data-tab') === tabName) { tab.classList.add('active'); } else { tab.classList.remove('active'); } }); // Inhalte anzeigen/verstecken const tabPanes = document.querySelectorAll('.tab-pane'); tabPanes.forEach(pane => { if (pane.id === `${tabName}-tab`) { pane.classList.add('active'); pane.classList.remove('hidden'); } else { pane.classList.remove('active'); pane.classList.add('hidden'); } }); // Daten für den Tab laden switch(tabName) { case 'users': loadUsers(); break; case 'printers': loadPrinters(); break; case 'scheduler': loadSchedulerStatus(); break; case 'system': loadSystemStats(); break; case 'logs': loadLogs(); break; } // URL Hash aktualisieren window.location.hash = tabName; } // Refresh only the data for the active tab function refreshActiveTabData() { const activeTab = document.querySelector('.nav-tab.active'); if (!activeTab) return; const tabName = activeTab.getAttribute('data-tab'); switch(tabName) { case 'users': loadUsers(); break; case 'printers': loadPrinters(); break; case 'scheduler': loadSchedulerStatus(); break; case 'system': loadSystemStats(); break; case 'logs': loadLogs(); break; } // Always refresh the stats loadAdminStats(); } // Initialize event handlers for buttons that previously used onclick function initializeEventHandlers() { // Add user button const addUserBtn = document.getElementById('add-user-btn'); if (addUserBtn) { addUserBtn.addEventListener('click', showAddUserModal); } // Add printer button const addPrinterBtn = document.getElementById('add-printer-btn'); if (addPrinterBtn) { addPrinterBtn.addEventListener('click', showAddPrinterModal); } // Refresh logs button const refreshLogsBtn = document.getElementById('refresh-logs-btn'); if (refreshLogsBtn) { refreshLogsBtn.addEventListener('click', refreshLogs); } // Delete modal close buttons const closeDeleteModalBtn = document.getElementById('close-delete-modal'); if (closeDeleteModalBtn) { closeDeleteModalBtn.addEventListener('click', closeDeleteModal); } const cancelDeleteBtn = document.getElementById('cancel-delete'); if (cancelDeleteBtn) { cancelDeleteBtn.addEventListener('click', closeDeleteModal); } // Add user modal handlers const closeAddUserBtn = document.getElementById('close-add-user-modal'); if (closeAddUserBtn) { closeAddUserBtn.addEventListener('click', closeAddUserModal); } const cancelAddUserBtn = document.getElementById('cancel-add-user'); if (cancelAddUserBtn) { cancelAddUserBtn.addEventListener('click', closeAddUserModal); } const confirmAddUserBtn = document.getElementById('confirm-add-user'); if (confirmAddUserBtn) { confirmAddUserBtn.addEventListener('click', addUser); } // Add printer modal handlers const closeAddPrinterBtn = document.getElementById('close-add-printer-modal'); if (closeAddPrinterBtn) { closeAddPrinterBtn.addEventListener('click', closeAddPrinterModal); } const cancelAddPrinterBtn = document.getElementById('cancel-add-printer'); if (cancelAddPrinterBtn) { cancelAddPrinterBtn.addEventListener('click', closeAddPrinterModal); } const confirmAddPrinterBtn = document.getElementById('confirm-add-printer'); if (confirmAddPrinterBtn) { confirmAddPrinterBtn.addEventListener('click', addPrinter); } // Scheduler buttons const startSchedulerBtn = document.getElementById('start-scheduler'); if (startSchedulerBtn) { startSchedulerBtn.addEventListener('click', startScheduler); } const stopSchedulerBtn = document.getElementById('stop-scheduler'); if (stopSchedulerBtn) { stopSchedulerBtn.addEventListener('click', stopScheduler); } // Global refresh button const refreshButton = document.createElement('button'); refreshButton.id = 'refresh-admin-btn'; refreshButton.className = 'fixed bottom-8 right-8 p-3 bg-primary text-white rounded-full shadow-lg z-40'; refreshButton.innerHTML = ` `; refreshButton.title = 'Alle Daten aktualisieren'; refreshButton.addEventListener('click', refreshAllData); // Füge den Button zum Body hinzu, falls er noch nicht existiert if (!document.getElementById('refresh-admin-btn')) { document.body.appendChild(refreshButton); } } // Modal functions function showAddUserModal() { const modal = document.getElementById('add-user-modal'); if (modal) { // Reset form const form = document.getElementById('add-user-form'); if (form) { form.reset(); } // Show modal modal.classList.remove('hidden'); modal.classList.add('show'); modal.style.display = 'flex'; } } function closeAddUserModal() { const modal = document.getElementById('add-user-modal'); if (modal) { modal.classList.remove('show'); modal.classList.add('hidden'); modal.style.display = 'none'; } } async function addUser() { const form = document.getElementById('add-user-form'); if (!form) return; const userData = { email: document.getElementById('user-email').value, name: document.getElementById('user-name').value, password: document.getElementById('user-password').value, role: document.getElementById('user-role').value, status: document.getElementById('user-status').value }; try { const response = await fetch('/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': getCSRFToken() }, body: JSON.stringify(userData) }); if (!response.ok) { throw new Error('Fehler beim Hinzufügen des Benutzers'); } // Erfolgsmeldung anzeigen showNotification('Benutzer erfolgreich hinzugefügt', 'success'); // Modal schließen closeAddUserModal(); // Benutzerliste aktualisieren loadUsers(); } catch (error) { console.error('Error adding user:', error); showNotification(error.message, 'error'); } } function showAddPrinterModal() { const modal = document.getElementById('add-printer-modal'); if (modal) { // Reset form const form = document.getElementById('add-printer-form'); if (form) { form.reset(); } // Show modal modal.classList.remove('hidden'); modal.classList.add('show'); modal.style.display = 'flex'; } } function closeAddPrinterModal() { const modal = document.getElementById('add-printer-modal'); if (modal) { modal.classList.remove('show'); modal.classList.add('hidden'); modal.style.display = 'none'; } } async function addPrinter() { const form = document.getElementById('add-printer-form'); if (!form) return; const printerData = { name: document.getElementById('printer-name').value, model: document.getElementById('printer-model').value, ip_address: document.getElementById('printer-ip').value, location: document.getElementById('printer-location').value, status: document.getElementById('printer-status').value }; try { const response = await fetch('/api/printers', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': getCSRFToken() }, body: JSON.stringify(printerData) }); if (!response.ok) { throw new Error('Fehler beim Hinzufügen des Druckers'); } // Erfolgsmeldung anzeigen showNotification('Drucker erfolgreich hinzugefügt', 'success'); // Modal schließen closeAddPrinterModal(); // Druckerliste aktualisieren loadPrinters(); } catch (error) { console.error('Error adding printer:', error); showNotification(error.message, 'error'); } } function refreshLogs() { loadLogs(); showNotification('Logs aktualisiert', 'info'); } function closeDeleteModal() { const modal = document.getElementById('delete-confirm-modal'); if (modal) { modal.classList.remove('show'); modal.style.display = 'none'; } } function showDeleteConfirmation(id, type, name, callback) { const modal = document.getElementById('delete-confirm-modal'); const messageEl = document.getElementById('delete-message'); const idField = document.getElementById('delete-id'); const typeField = document.getElementById('delete-type'); const confirmBtn = document.getElementById('confirm-delete'); if (modal && messageEl && idField && typeField && confirmBtn) { messageEl.textContent = `Möchten Sie ${type === 'user' ? 'den Benutzer' : 'den Drucker'} "${name}" wirklich löschen?`; idField.value = id; typeField.value = type; confirmBtn.onclick = function() { if (typeof callback === 'function') { callback(id, name); } closeDeleteModal(); }; modal.classList.add('show'); modal.style.display = 'flex'; } } function initializeAdminPanel() { // Tab Navigation const tabs = document.querySelectorAll('.nav-tab'); tabs.forEach(tab => { tab.addEventListener('click', function() { const tabName = this.getAttribute('data-tab'); if (!tabName) return; activateTab(tabName); }); }); // Log Level Filter const logLevelFilter = document.getElementById('log-level-filter'); if (logLevelFilter) { logLevelFilter.addEventListener('change', function() { if (window.logsData) { const level = this.value; if (level === 'all') { window.filteredLogs = [...window.logsData]; } else { window.filteredLogs = window.logsData.filter(log => log.level.toLowerCase() === level); } renderLogs(); } }); } // Confirm Delete const confirmDeleteBtn = document.getElementById('confirm-delete'); if (confirmDeleteBtn) { confirmDeleteBtn.addEventListener('click', function() { const id = document.getElementById('delete-id').value; const type = document.getElementById('delete-type').value; if (type === 'user') { deleteUser(id); } else if (type === 'printer') { deletePrinter(id); } closeDeleteModal(); }); } } async function loadAdminStats() { try { const response = await fetch('/api/admin/stats'); if (!response.ok) { throw new Error('Fehler beim Laden der Admin-Statistiken'); } const data = await response.json(); // Aktualisiere die Statistik-Karten const statsContainer = document.getElementById('admin-stats'); if (!statsContainer) return; statsContainer.innerHTML = `
Benutzer
${data.total_users || 0}
Registrierte Benutzer
Drucker
${data.total_printers || 0}
Verbundene Drucker
Aktive Jobs
${data.active_jobs || 0}
Laufende Druckaufträge
Erfolgsrate
${data.success_rate || '0%'}
Erfolgreiche Druckaufträge
`; } catch (error) { console.error('Error loading admin stats:', error); showNotification('Fehler beim Laden der Admin-Statistiken', 'error'); } } // Lade Benutzer für die Benutzerverwaltung async function loadUsers() { try { const response = await fetch('/api/users'); if (!response.ok) { throw new Error('Fehler beim Laden der Benutzer'); } const data = await response.json(); // Benutzer in der Tabelle anzeigen const userTableBody = document.querySelector('#users-tab table tbody'); if (!userTableBody) return; let html = ''; if (data.users && data.users.length > 0) { data.users.forEach(user => { html += ` ${user.id} ${user.name || '-'} ${user.email} ${user.active ? 'Aktiv' : 'Inaktiv'} ${user.role || 'Benutzer'}
`; }); } else { html = ` Keine Benutzer gefunden `; } userTableBody.innerHTML = html; } catch (error) { console.error('Error loading users:', error); showNotification('Fehler beim Laden der Benutzer', 'error'); } } // Lade Drucker für die Druckerverwaltung async function loadPrinters() { try { const response = await fetch('/api/printers'); if (!response.ok) { throw new Error('Fehler beim Laden der Drucker'); } const data = await response.json(); // Drucker in der Tabelle anzeigen const printerTableBody = document.querySelector('#printers-tab table tbody'); if (!printerTableBody) return; let html = ''; if (data.printers && data.printers.length > 0) { data.printers.forEach(printer => { html += ` ${printer.id} ${printer.name} ${printer.model || '-'} ${printer.ip_address || '-'} ${printer.location || '-'} ${printer.status === 'online' ? 'Online' : 'Offline'}
`; }); } else { html = ` Keine Drucker gefunden `; } printerTableBody.innerHTML = html; } catch (error) { console.error('Error loading printers:', error); showNotification('Fehler beim Laden der Drucker', 'error'); } } // Lade Scheduler-Status async function loadSchedulerStatus() { try { const response = await fetch('/api/scheduler/status'); if (!response.ok) { throw new Error('Fehler beim Laden des Scheduler-Status'); } const data = await response.json(); // Status-Anzeige aktualisieren const statusIndicator = document.getElementById('scheduler-status-indicator'); const statusText = document.getElementById('scheduler-status-text'); const startSchedulerBtn = document.getElementById('start-scheduler'); const stopSchedulerBtn = document.getElementById('stop-scheduler'); if (statusIndicator && statusText) { if (data.active) { statusIndicator.classList.remove('bg-red-500'); statusIndicator.classList.add('bg-green-500'); statusText.textContent = 'Aktiv'; if (startSchedulerBtn && stopSchedulerBtn) { startSchedulerBtn.disabled = true; stopSchedulerBtn.disabled = false; } } else { statusIndicator.classList.remove('bg-green-500'); statusIndicator.classList.add('bg-red-500'); statusText.textContent = 'Inaktiv'; if (startSchedulerBtn && stopSchedulerBtn) { startSchedulerBtn.disabled = false; stopSchedulerBtn.disabled = true; } } } // Scheduler-Details aktualisieren const schedulerDetails = document.getElementById('scheduler-details'); if (schedulerDetails) { schedulerDetails.innerHTML = `

Letzte Ausführung

${data.last_run ? new Date(data.last_run).toLocaleString('de-DE') : 'Nie'}

Nächste Ausführung

${data.next_run ? new Date(data.next_run).toLocaleString('de-DE') : 'Nicht geplant'}

Ausführungsintervall

${data.interval || '60'} Sekunden

Verarbeitete Jobs

${data.processed_jobs || 0} Jobs seit dem letzten Neustart

`; } // Job-Warteschlange aktualisieren const jobQueueContainer = document.getElementById('job-queue'); if (jobQueueContainer && data.pending_jobs) { let queueHtml = ''; if (data.pending_jobs.length > 0) { queueHtml = `
`; data.pending_jobs.forEach(job => { queueHtml += ` `; }); queueHtml += `
Job ID Name Geplant für Status
${job.id} ${job.name} ${new Date(job.start_time).toLocaleString('de-DE')} Warten
`; } else { queueHtml = `

Keine ausstehenden Jobs in der Warteschlange

`; } jobQueueContainer.innerHTML = queueHtml; } } catch (error) { console.error('Error loading scheduler status:', error); showNotification('Fehler beim Laden des Scheduler-Status', 'error'); } } // Lade Systemstatistiken async function loadSystemStats() { try { const response = await fetch('/api/system/stats'); if (!response.ok) { throw new Error('Fehler beim Laden der Systemstatistiken'); } const data = await response.json(); // CPU-Auslastung const cpuUsageElement = document.getElementById('cpu-usage'); if (cpuUsageElement) { cpuUsageElement.style.width = `${data.cpu_usage || 0}%`; cpuUsageElement.textContent = `${data.cpu_usage || 0}%`; } // RAM-Auslastung const ramUsageElement = document.getElementById('ram-usage'); if (ramUsageElement) { ramUsageElement.style.width = `${data.ram_usage_percent || 0}%`; ramUsageElement.textContent = `${data.ram_usage_percent || 0}%`; } // Speichernutzung const diskUsageElement = document.getElementById('disk-usage'); if (diskUsageElement) { diskUsageElement.style.width = `${data.disk_usage_percent || 0}%`; diskUsageElement.textContent = `${data.disk_usage_percent || 0}%`; } // Weitere Systemdetails const systemDetailsElement = document.getElementById('system-details'); if (systemDetailsElement) { systemDetailsElement.innerHTML = `

System

${data.os_name || 'Unbekannt'} ${data.os_version || ''}

Laufzeit

${data.uptime || 'Unbekannt'}

Python-Version

${data.python_version || 'Unbekannt'}

Server-Zeit

${data.server_time ? new Date(data.server_time).toLocaleString('de-DE') : 'Unbekannt'}

`; } // Systemereignisse anzeigen const systemEventsElement = document.getElementById('system-events'); if (systemEventsElement && data.recent_events) { let eventsHtml = ''; if (data.recent_events.length > 0) { eventsHtml = ''; } else { eventsHtml = '

Keine Ereignisse vorhanden

'; } systemEventsElement.innerHTML = eventsHtml; } } catch (error) { console.error('Error loading system stats:', error); showNotification('Fehler beim Laden der Systemstatistiken', 'error'); } } // Lade Logs async function loadLogs() { try { const response = await fetch('/api/logs'); if (!response.ok) { throw new Error('Fehler beim Laden der Logs'); } const data = await response.json(); // Logs im globalen Objekt speichern window.logsData = data.logs || []; window.filteredLogs = [...window.logsData]; // Logs rendern renderLogs(); } catch (error) { console.error('Error loading logs:', error); showNotification('Fehler beim Laden der Logs', 'error'); } } // Hilfsfunktion zum Rendern der Logs function renderLogs() { const logsContainer = document.getElementById('logs-container'); if (!logsContainer) return; if (!window.filteredLogs || window.filteredLogs.length === 0) { logsContainer.innerHTML = '
Keine Logs gefunden
'; return; } let html = ''; window.filteredLogs.forEach(log => { let levelClass = ''; switch (log.level.toLowerCase()) { case 'error': levelClass = 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200'; break; case 'warning': levelClass = 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200'; break; case 'info': levelClass = 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-200'; break; case 'debug': levelClass = 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200'; break; default: levelClass = 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-200'; } html += `
${log.level} ${log.timestamp ? new Date(log.timestamp).toLocaleString('de-DE') : ''}
${log.source || 'System'}
${log.message}
${log.details ? `
${log.details}
` : ''}
`; }); logsContainer.innerHTML = html; } // Funktionen zum Löschen von Benutzern und Druckern async function deleteUser(userId) { try { const response = await fetch(`/api/users/${userId}`, { method: 'DELETE', headers: { 'X-CSRF-Token': getCSRFToken() } }); if (!response.ok) { throw new Error('Fehler beim Löschen des Benutzers'); } showNotification('Benutzer erfolgreich gelöscht', 'success'); loadUsers(); } catch (error) { console.error('Error deleting user:', error); showNotification(error.message, 'error'); } } async function deletePrinter(printerId) { try { const response = await fetch(`/api/printers/${printerId}`, { method: 'DELETE', headers: { 'X-CSRF-Token': getCSRFToken() } }); if (!response.ok) { throw new Error('Fehler beim Löschen des Druckers'); } showNotification('Drucker erfolgreich gelöscht', 'success'); loadPrinters(); } catch (error) { console.error('Error deleting printer:', error); showNotification(error.message, 'error'); } } // Scheduler-Steuerungsfunktionen async function startScheduler() { try { const response = await fetch('/api/scheduler/start', { method: 'POST', headers: { 'X-CSRF-Token': getCSRFToken() } }); if (!response.ok) { throw new Error('Fehler beim Starten des Schedulers'); } showNotification('Scheduler erfolgreich gestartet', 'success'); loadSchedulerStatus(); } catch (error) { console.error('Error starting scheduler:', error); showNotification(error.message, 'error'); } } async function stopScheduler() { try { const response = await fetch('/api/scheduler/stop', { method: 'POST', headers: { 'X-CSRF-Token': getCSRFToken() } }); if (!response.ok) { throw new Error('Fehler beim Stoppen des Schedulers'); } showNotification('Scheduler erfolgreich gestoppt', 'success'); loadSchedulerStatus(); } catch (error) { console.error('Error stopping scheduler:', error); showNotification(error.message, 'error'); } } // Hilfs-Funktion, um den CSRF-Token aus den Meta-Tags zu bekommen function getCSRFToken() { return document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || ''; } // Refresh all data function refreshAllData() { loadAdminStats(); const activeTab = document.querySelector('.nav-tab.active'); if (activeTab) { const tabName = activeTab.getAttribute('data-tab'); activateTab(tabName); } showNotification('Daten wurden aktualisiert', 'success'); } /** * Show a notification message * @param {string} message - The message to show * @param {string} type - The type of notification (success, error, warning, info) */ function showNotification(message, type = 'info') { const notification = document.getElementById('notification'); const messageEl = document.getElementById('notification-message'); const iconEl = document.getElementById('notification-icon'); if (!notification || !messageEl || !iconEl) return; // Set message messageEl.textContent = message; // Remove all previous classes notification.classList.remove('notification-success', 'notification-error', 'notification-warning', 'notification-info'); // Add appropriate class based on type notification.classList.add(`notification-${type}`); // Set appropriate icon let icon = ''; switch(type) { case 'success': icon = ''; break; case 'error': icon = ''; break; case 'warning': icon = ''; break; case 'info': default: icon = ''; break; } iconEl.innerHTML = icon; // Show notification notification.classList.remove('hidden'); notification.classList.add('show'); // Hide after 5 seconds setTimeout(() => { notification.classList.remove('show'); setTimeout(() => { notification.classList.add('hidden'); }, 300); }, 5000); } // Weitere Funktionen aus dem ursprünglichen Code...