Initial commit: Wake-on-LAN Manager mit Go und Web-Oberfläche
This commit is contained in:
265
web/static/script.js
Normal file
265
web/static/script.js
Normal file
@ -0,0 +1,265 @@
|
||||
// JavaScript für Medi-WOL Web-Oberfläche
|
||||
|
||||
class PCManager {
|
||||
constructor() {
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.loadPCs();
|
||||
this.setupEventListeners();
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
async loadPCs() {
|
||||
try {
|
||||
const response = await fetch('/api/pcs');
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
this.displayPCs(data.pcs);
|
||||
} else {
|
||||
this.showNotification('Fehler', data.message, 'danger');
|
||||
}
|
||||
} catch (error) {
|
||||
this.showNotification('Fehler', 'Fehler beim Laden der PCs', 'danger');
|
||||
}
|
||||
}
|
||||
|
||||
displayPCs(pcs) {
|
||||
const tableBody = document.getElementById('pcTableBody');
|
||||
const noPCs = document.getElementById('noPCs');
|
||||
const pcList = document.getElementById('pcList');
|
||||
|
||||
if (pcs.length === 0) {
|
||||
tableBody.innerHTML = '';
|
||||
noPCs.style.display = 'block';
|
||||
pcList.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
noPCs.style.display = 'none';
|
||||
pcList.style.display = 'block';
|
||||
|
||||
tableBody.innerHTML = pcs.map(pc => `
|
||||
<tr>
|
||||
<td><strong>${this.escapeHtml(pc.name)}</strong></td>
|
||||
<td><code>${this.escapeHtml(pc.mac)}</code></td>
|
||||
<td>${new Date(pc.created_at).toLocaleDateString('de-DE')}</td>
|
||||
<td>
|
||||
<div class="btn-group" role="group">
|
||||
<button class="btn btn-success btn-sm" onclick="pcManager.wakePC(${pc.id})"
|
||||
title="PC aufwecken">
|
||||
<i class="fas fa-power-off"></i> Aufwecken
|
||||
</button>
|
||||
<button class="btn btn-warning btn-sm" onclick="pcManager.editPC(${pc.id}, '${this.escapeHtml(pc.name)}', '${this.escapeHtml(pc.mac)}')"
|
||||
title="PC bearbeiten">
|
||||
<i class="fas fa-edit"></i> Bearbeiten
|
||||
</button>
|
||||
<button class="btn btn-danger btn-sm" onclick="pcManager.deletePC(${pc.id})"
|
||||
title="PC löschen">
|
||||
<i class="fas fa-trash"></i> Löschen
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
}
|
||||
|
||||
async addPC() {
|
||||
const name = document.getElementById('pcName').value.trim();
|
||||
const mac = document.getElementById('macAddress').value.trim();
|
||||
|
||||
if (!name || !mac) {
|
||||
this.showNotification('Warnung', 'Bitte füllen Sie alle Felder aus', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/pcs', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ name, mac })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
this.showNotification('Erfolg', 'PC erfolgreich hinzugefügt', 'success');
|
||||
document.getElementById('addPCForm').reset();
|
||||
this.loadPCs();
|
||||
} else {
|
||||
this.showNotification('Fehler', data.message, 'danger');
|
||||
}
|
||||
} catch (error) {
|
||||
this.showNotification('Fehler', 'Fehler beim Hinzufügen des PCs', 'danger');
|
||||
}
|
||||
}
|
||||
|
||||
editPC(id, name, mac) {
|
||||
// Modal mit PC-Daten füllen
|
||||
document.getElementById('editPCId').value = id;
|
||||
document.getElementById('editPCName').value = name;
|
||||
document.getElementById('editMACAddress').value = mac;
|
||||
|
||||
// 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();
|
||||
|
||||
if (!name || !mac) {
|
||||
this.showNotification('Warnung', 'Bitte füllen Sie alle Felder aus', 'warning');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/pcs/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ name, mac })
|
||||
});
|
||||
|
||||
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();
|
||||
|
||||
// PC-Liste neu laden
|
||||
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');
|
||||
this.loadPCs();
|
||||
} 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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
});
|
||||
148
web/static/style.css
Normal file
148
web/static/style.css
Normal file
@ -0,0 +1,148 @@
|
||||
/* Custom Styles für Medi-WOL */
|
||||
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
transition: transform 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 15px 15px 0 0 !important;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn {
|
||||
border-radius: 25px;
|
||||
padding: 8px 20px;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-success {
|
||||
background: linear-gradient(135deg, #56ab2f 0%, #a8e6cf 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: linear-gradient(135deg, #ff416c 0%, #ff4b2b 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.table {
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table thead th {
|
||||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.table tbody tr {
|
||||
transition: background-color 0.2s ease;
|
||||
}
|
||||
|
||||
.table tbody tr:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
border-radius: 10px;
|
||||
border: 2px solid #e9ecef;
|
||||
transition: border-color 0.3s ease;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
|
||||
}
|
||||
|
||||
.toast {
|
||||
border-radius: 15px;
|
||||
border: none;
|
||||
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.toast-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border-radius: 15px 15px 0 0;
|
||||
}
|
||||
|
||||
.btn-close {
|
||||
filter: invert(1);
|
||||
}
|
||||
|
||||
/* Animationen */
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(20px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.card {
|
||||
animation: fadeIn 0.5s ease-out;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.table-responsive {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Custom Scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: linear-gradient(135deg, #5a6fd8 0%, #6a4190 100%);
|
||||
}
|
||||
Reference in New Issue
Block a user