// JavaScript für Medi-WOL Web-Oberfläche class PCManager { constructor() { this.allPCs = []; // Alle PCs im Speicher this.filteredPCs = []; // Gefilterte PCs this.searchTerm = ''; // Aktueller Suchbegriff this.statusTimer = null; // Intervall für Auto-Status this.refreshing = false; // Guard gegen parallele Status-Requests this.init(); } init() { this.loadPCs(); this.setupEventListeners(); this.startAutoStatus(); } setupEventListeners() { // Formular für neuen PC document.getElementById('addPCForm').addEventListener('submit', (e) => { e.preventDefault(); this.addPC(); }); // Edit PC Modal speichern Button document.getElementById('saveEditBtn').addEventListener('click', () => { this.saveEditPC(); }); // MAC-Adresse Formatierung für Edit-Formular document.getElementById('editMACAddress')?.addEventListener('input', (e) => { this.formatMACAddress(e.target); }); // Suchfeld Event Listener document.getElementById('searchInput').addEventListener('input', (e) => { this.searchPCs(e.target.value); }); // Suchfeld löschen Button document.getElementById('clearSearchBtn').addEventListener('click', () => { this.clearSearch(); }); // Status aktualisieren Button document.getElementById('refreshStatusBtn').addEventListener('click', () => { this.refreshStatus(); }); } async loadPCs() { try { const response = await fetch('/api/pcs'); const data = await response.json(); if (data.success) { this.allPCs = data.pcs; this.filteredPCs = [...this.allPCs]; this.displayPCs(); // Ersten Status direkt nach dem Laden abfragen this.refreshStatus(); } else { this.showNotification('Fehler', data.message, 'danger'); } } catch (error) { this.showNotification('Fehler', 'Fehler beim Laden der PCs', 'danger'); } } startAutoStatus() { if (this.statusTimer) { clearInterval(this.statusTimer); } this.statusTimer = setInterval(() => { this.refreshStatus(); }, 30000); // alle 30 Sekunden } searchPCs(searchTerm) { this.searchTerm = searchTerm.toLowerCase().trim(); if (this.searchTerm === '') { // Keine Suche - alle PCs anzeigen this.filteredPCs = [...this.allPCs]; this.hideClearSearchButton(); } else { // PCs nach Namen filtern this.filteredPCs = this.allPCs.filter(pc => pc.name.toLowerCase().includes(this.searchTerm) ); this.showClearSearchButton(); } this.displayPCs(); } clearSearch() { document.getElementById('searchInput').value = ''; this.searchPCs(''); this.hideClearSearchButton(); } showClearSearchButton() { document.getElementById('clearSearchBtn').style.display = 'block'; } hideClearSearchButton() { document.getElementById('clearSearchBtn').style.display = 'none'; } displayPCs() { const tableBody = document.getElementById('pcTableBody'); const noPCs = document.getElementById('noPCs'); const pcList = document.getElementById('pcList'); const noSearchResults = document.getElementById('noSearchResults'); const searchTerm = document.getElementById('searchTerm'); const resultCount = document.getElementById('resultCount'); // Ergebnis-Zähler aktualisieren resultCount.textContent = `${this.filteredPCs.length} PC${this.filteredPCs.length !== 1 ? 's' : ''} gefunden`; if (this.allPCs.length === 0) { // Keine PCs vorhanden tableBody.innerHTML = ''; noPCs.style.display = 'block'; pcList.style.display = 'none'; noSearchResults.style.display = 'none'; return; } if (this.filteredPCs.length === 0 && this.searchTerm !== '') { // Keine Suchergebnisse tableBody.innerHTML = ''; noPCs.style.display = 'none'; pcList.style.display = 'none'; noSearchResults.style.display = 'block'; searchTerm.textContent = this.searchTerm; return; } // PCs anzeigen noPCs.style.display = 'none'; noSearchResults.style.display = 'none'; pcList.style.display = 'block'; tableBody.innerHTML = this.filteredPCs.map(pc => ` ${this.escapeHtml(pc.name)} ${this.escapeHtml(pc.mac)} ${this.escapeHtml(pc.ip || 'N/A')} ${pc.online ? 'Online' : 'Offline'} ${new Date(pc.created_at).toLocaleDateString('de-DE')}
Autostart: ${pc.autostart_enabled ? `${this.escapeHtml(pc.autostart_cron || '30 7 * * Mon-Fri')}` : 'Deaktiviert' }
`).join(''); // Tooltips für alle PC-Zeilen laden this.loadTooltipsForAllPCs(); } async addPC() { const name = document.getElementById('pcName').value.trim(); const mac = document.getElementById('macAddress').value.trim(); const ip = document.getElementById('ipAddress').value.trim(); const autostartCron = document.getElementById('autostartCron').value.trim(); const autostartEnabled = document.getElementById('autostartEnabled').checked; if (!name || !mac || !ip) { this.showNotification('Warnung', 'Bitte füllen Sie alle Pflichtfelder aus', 'warning'); return; } try { const response = await fetch('/api/pcs', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name, mac, ip, autostart_cron: autostartCron || '30 7 * * Mon-Fri', autostart_enabled: autostartEnabled }) }); const data = await response.json(); if (data.success) { this.showNotification('Erfolg', 'PC erfolgreich hinzugefügt', 'success'); document.getElementById('addPCForm').reset(); await this.loadPCs(); // PCs neu laden } else { this.showNotification('Fehler', data.message, 'danger'); } } catch (error) { this.showNotification('Fehler', 'Fehler beim Hinzufügen des PCs', 'danger'); } } editPC(id, name, mac, ip, autostartCron, autostartEnabled) { // Modal mit PC-Daten füllen document.getElementById('editPCId').value = id; document.getElementById('editPCName').value = name; document.getElementById('editMACAddress').value = mac; document.getElementById('editIPAddress').value = ip; document.getElementById('editAutostartCron').value = autostartCron || '30 7 * * Mon-Fri'; document.getElementById('editAutostartEnabled').checked = autostartEnabled || false; // Modal öffnen const editModal = new bootstrap.Modal(document.getElementById('editPCModal')); editModal.show(); } async saveEditPC() { const id = document.getElementById('editPCId').value; const name = document.getElementById('editPCName').value.trim(); const mac = document.getElementById('editMACAddress').value.trim(); const ip = document.getElementById('editIPAddress').value.trim(); const autostartCron = document.getElementById('editAutostartCron').value.trim(); const autostartEnabled = document.getElementById('editAutostartEnabled').checked; if (!name || !mac || !ip) { this.showNotification('Warnung', 'Bitte füllen Sie alle Pflichtfelder aus', 'warning'); return; } try { const response = await fetch(`/api/pcs/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ name, mac, ip, autostart_cron: autostartCron || '30 7 * * Mon-Fri', autostart_enabled: autostartEnabled }) }); const data = await response.json(); if (data.success) { this.showNotification('Erfolg', 'PC erfolgreich aktualisiert', 'success'); // Modal schließen const editModal = bootstrap.Modal.getInstance(document.getElementById('editPCModal')); editModal.hide(); // PCs neu laden await this.loadPCs(); } else { this.showNotification('Fehler', data.message, 'danger'); } } catch (error) { this.showNotification('Fehler', 'Fehler beim Aktualisieren des PCs', 'danger'); } } async deletePC(id) { if (!confirm('Sind Sie sicher, dass Sie diesen PC löschen möchten?')) { return; } try { const response = await fetch(`/api/pcs/${id}`, { method: 'DELETE' }); const data = await response.json(); if (data.success) { this.showNotification('Erfolg', 'PC erfolgreich gelöscht', 'success'); await this.loadPCs(); // PCs neu laden } else { this.showNotification('Fehler', data.message, 'danger'); } } catch (error) { this.showNotification('Fehler', 'Fehler beim Löschen des PCs', 'danger'); } } async wakePC(id) { try { const response = await fetch(`/api/pcs/${id}/wake`, { method: 'POST' }); const data = await response.json(); if (data.success) { this.showNotification('Erfolg', data.message, 'success'); } else { this.showNotification('Fehler', data.message, 'danger'); } } catch (error) { this.showNotification('Fehler', 'Fehler beim Senden des Wake-on-LAN Pakets', 'danger'); } } showNotification(title, message, type = 'info') { const toast = document.getElementById('notificationToast'); const toastTitle = document.getElementById('toastTitle'); const toastMessage = document.getElementById('toastMessage'); // Toast-Typ setzen toast.className = `toast ${type === 'success' ? 'bg-success' : type === 'danger' ? 'bg-danger' : type === 'warning' ? 'bg-warning' : 'bg-info'} text-white`; toastTitle.textContent = title; toastMessage.textContent = message; // Toast anzeigen const bsToast = new bootstrap.Toast(toast); bsToast.show(); } async refreshStatus() { if (this.refreshing) return; this.refreshing = true; try { const response = await fetch('/api/pcs/status'); const data = await response.json(); if (data.success) { // Status für jeden PC aktualisieren data.status.forEach(pcStatus => { const statusElement = document.getElementById(`status-${pcStatus.id}`); if (statusElement) { statusElement.className = `badge ${pcStatus.online ? 'bg-success' : 'bg-danger'}`; statusElement.innerHTML = ` ${pcStatus.online ? 'Online' : 'Offline'} `; } }); this.showNotification('Info', 'Online-Status aktualisiert', 'info'); } else { this.showNotification('Fehler', data.message, 'danger'); } } catch (error) { this.showNotification('Fehler', 'Fehler beim Aktualisieren des Online-Status', 'danger'); } finally { this.refreshing = false; } } escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } formatMACAddress(input) { let value = input.value.replace(/[^0-9A-Fa-f]/g, ''); if (value.length > 12) { value = value.substring(0, 12); } // MAC-Adresse mit Doppelpunkten formatieren if (value.length >= 2) { value = value.match(/.{1,2}/g).join(':'); } input.value = value.toUpperCase(); } // Tooltip für alle PCs laden async loadTooltipsForAllPCs() { for (const pc of this.filteredPCs) { await this.loadTooltipForPC(pc.id); } } // Tooltip für einen bestimmten PC laden async loadTooltipForPC(pcId) { try { const response = await fetch(`/api/logs/pc/${pcId}/recent`); const data = await response.json(); if (data.success) { const tooltipContent = this.createTooltipContent(data.logs); const row = document.querySelector(`tr[data-pc-id="${pcId}"]`); if (row) { // Tooltip-Attribut setzen row.setAttribute('data-bs-toggle', 'tooltip'); row.setAttribute('data-bs-html', 'true'); row.setAttribute('title', tooltipContent); // Bootstrap Tooltip initialisieren new bootstrap.Tooltip(row, { placement: 'top', trigger: 'hover', html: true }); } } } catch (error) { console.error(`Fehler beim Laden des Tooltips für PC ${pcId}:`, error); } } // Tooltip-Inhalt erstellen createTooltipContent(logs) { if (!logs || logs.length === 0) { return '
Keine WOL-Ereignisse
'; } let content = '
Letzte WOL-Ereignisse:
'; logs.forEach(log => { const timestamp = new Date(log.timestamp).toLocaleString('de-DE', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' }); const triggerText = log.trigger === 'button' ? 'Button' : log.trigger === 'cron' ? 'Auto' : log.trigger; content += `• ${timestamp} (${triggerText})
`; }); content += '
'; return content; } } // PC Manager initialisieren, wenn die Seite geladen ist document.addEventListener('DOMContentLoaded', () => { window.pcManager = new PCManager(); }); // MAC-Adresse Formatierung für das Hauptformular document.getElementById('macAddress')?.addEventListener('input', (e) => { let value = e.target.value.replace(/[^0-9A-Fa-f]/g, ''); if (value.length > 12) { value = value.substring(0, 12); } // MAC-Adresse mit Doppelpunkten formatieren if (value.length >= 2) { value = value.match(/.{1,2}/g).join(':'); } e.target.value = value.toUpperCase(); });