"feat: Added debug server and related components for improved development experience"
This commit is contained in:
505
frontend/debug-server/public/js/script.js
Normal file
505
frontend/debug-server/public/js/script.js
Normal file
@@ -0,0 +1,505 @@
|
||||
// DOM-Element-Referenzen
|
||||
const navButtons = document.querySelectorAll('.nav-button');
|
||||
const panels = document.querySelectorAll('.panel');
|
||||
|
||||
// Panel-Navigation
|
||||
navButtons.forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const panelId = button.getAttribute('data-panel');
|
||||
|
||||
// Aktiven Button und Panel wechseln
|
||||
navButtons.forEach(btn => btn.classList.remove('active'));
|
||||
panels.forEach(panel => panel.classList.remove('active'));
|
||||
|
||||
button.classList.add('active');
|
||||
document.getElementById(panelId).classList.add('active');
|
||||
|
||||
// Lade Panel-Daten, wenn sie noch nicht geladen wurden
|
||||
if (panelId === 'system' && document.getElementById('system-container').style.display === 'none') {
|
||||
loadSystemInfo();
|
||||
} else if (panelId === 'network' && document.getElementById('network-container').style.display === 'none') {
|
||||
loadNetworkInfo();
|
||||
} else if (panelId === 'services' && document.getElementById('services-container').style.display === 'none') {
|
||||
loadServicesInfo();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// API-Anfragen
|
||||
async function fetchData(endpoint) {
|
||||
try {
|
||||
const response = await fetch(endpoint);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP-Fehler: ${response.status}`);
|
||||
}
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error(`Fehler beim Abrufen von ${endpoint}:`, error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// System-Informationen laden
|
||||
async function loadSystemInfo() {
|
||||
const loader = document.getElementById('system-loader');
|
||||
const container = document.getElementById('system-container');
|
||||
|
||||
loader.style.display = 'block';
|
||||
container.style.display = 'none';
|
||||
|
||||
const data = await fetchData('/api/system');
|
||||
if (!data) {
|
||||
loader.textContent = 'Fehler beim Laden der Systemdaten';
|
||||
return;
|
||||
}
|
||||
|
||||
// Betriebssystem-Info
|
||||
document.getElementById('os-info').innerHTML = `
|
||||
<p><strong>Plattform:</strong> ${data.os.platform}</p>
|
||||
<p><strong>Distribution:</strong> ${data.os.distro}</p>
|
||||
<p><strong>Version:</strong> ${data.os.release}</p>
|
||||
<p><strong>Architektur:</strong> ${data.os.arch}</p>
|
||||
<p><strong>Betriebszeit:</strong> ${data.os.uptime}</p>
|
||||
`;
|
||||
|
||||
// CPU-Info
|
||||
document.getElementById('cpu-info').innerHTML = `
|
||||
<p><strong>Hersteller:</strong> ${data.cpu.manufacturer}</p>
|
||||
<p><strong>Modell:</strong> ${data.cpu.brand}</p>
|
||||
<p><strong>Geschwindigkeit:</strong> ${data.cpu.speed} GHz</p>
|
||||
<p><strong>Kerne:</strong> ${data.cpu.cores} (${data.cpu.physicalCores} physisch)</p>
|
||||
`;
|
||||
|
||||
// Speicher-Info
|
||||
document.getElementById('memory-info').innerHTML = `
|
||||
<p><strong>Gesamt:</strong> ${data.memory.total}</p>
|
||||
<p><strong>Verwendet:</strong> ${data.memory.used} (${data.memory.usedPercent}%)</p>
|
||||
<p><strong>Frei:</strong> ${data.memory.free}</p>
|
||||
`;
|
||||
|
||||
document.getElementById('memory-bar').style.width = `${data.memory.usedPercent}%`;
|
||||
document.getElementById('memory-bar').style.backgroundColor = getColorByPercentage(data.memory.usedPercent);
|
||||
|
||||
// Festplatten-Info
|
||||
let diskHTML = '<table><tr><th>Laufwerk</th><th>Typ</th><th>Größe</th><th>Verwendet</th><th>Verfügbar</th><th>Nutzung</th></tr>';
|
||||
|
||||
data.filesystem.forEach(fs => {
|
||||
diskHTML += `
|
||||
<tr>
|
||||
<td>${fs.mount}</td>
|
||||
<td>${fs.type}</td>
|
||||
<td>${fs.size}</td>
|
||||
<td>${fs.used}</td>
|
||||
<td>${fs.available}</td>
|
||||
<td>
|
||||
<div class="progress-container" style="margin: 0; width: 100%">
|
||||
<div class="progress-bar" style="width: ${fs.usePercent}%; background-color: ${getColorByPercentage(fs.usePercent)}"></div>
|
||||
</div>
|
||||
${fs.usePercent}%
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
diskHTML += '</table>';
|
||||
document.getElementById('disk-info').innerHTML = diskHTML;
|
||||
|
||||
// UI anzeigen
|
||||
loader.style.display = 'none';
|
||||
container.style.display = 'grid';
|
||||
}
|
||||
|
||||
// Netzwerk-Informationen laden
|
||||
async function loadNetworkInfo() {
|
||||
const loader = document.getElementById('network-loader');
|
||||
const container = document.getElementById('network-container');
|
||||
|
||||
loader.style.display = 'block';
|
||||
container.style.display = 'none';
|
||||
|
||||
const data = await fetchData('/api/network');
|
||||
if (!data) {
|
||||
loader.textContent = 'Fehler beim Laden der Netzwerkdaten';
|
||||
return;
|
||||
}
|
||||
|
||||
// Netzwerkschnittstellen
|
||||
let interfacesHTML = '<table><tr><th>Name</th><th>Status</th><th>IPv4</th><th>IPv6</th><th>MAC</th><th>Typ</th><th>DHCP</th></tr>';
|
||||
|
||||
data.interfaces.forEach(iface => {
|
||||
interfacesHTML += `
|
||||
<tr>
|
||||
<td>${iface.iface}</td>
|
||||
<td><span class="status ${iface.operstate === 'up' ? 'status-online' : 'status-offline'}">${iface.operstate}</span></td>
|
||||
<td>${iface.ip4 || '-'}</td>
|
||||
<td>${iface.ip6 || '-'}</td>
|
||||
<td>${iface.mac || '-'}</td>
|
||||
<td>${iface.type || '-'}</td>
|
||||
<td>${iface.dhcp ? 'Ja' : 'Nein'}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
interfacesHTML += '</table>';
|
||||
document.getElementById('network-interfaces').innerHTML = interfacesHTML;
|
||||
|
||||
// DNS-Server
|
||||
let dnsHTML = '<ul>';
|
||||
data.dns.forEach(server => {
|
||||
dnsHTML += `<li>${server}</li>`;
|
||||
});
|
||||
dnsHTML += '</ul>';
|
||||
document.getElementById('dns-servers').innerHTML = dnsHTML;
|
||||
|
||||
// Gateway
|
||||
document.getElementById('default-gateway').innerHTML = `<p>${data.gateway || 'Nicht verfügbar'}</p>`;
|
||||
|
||||
// Netzwerkstatistiken
|
||||
let statsHTML = '<table><tr><th>Schnittstelle</th><th>Empfangen</th><th>Gesendet</th><th>Empfangen/s</th><th>Gesendet/s</th></tr>';
|
||||
|
||||
data.stats.forEach(stat => {
|
||||
statsHTML += `
|
||||
<tr>
|
||||
<td>${stat.iface}</td>
|
||||
<td>${stat.rx_bytes}</td>
|
||||
<td>${stat.tx_bytes}</td>
|
||||
<td>${stat.rx_sec}</td>
|
||||
<td>${stat.tx_sec}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
statsHTML += '</table>';
|
||||
document.getElementById('network-stats').innerHTML = statsHTML;
|
||||
|
||||
// UI anzeigen
|
||||
loader.style.display = 'none';
|
||||
container.style.display = 'grid';
|
||||
}
|
||||
|
||||
// Dienst-Informationen laden
|
||||
async function loadServicesInfo() {
|
||||
const loader = document.getElementById('services-loader');
|
||||
const container = document.getElementById('services-container');
|
||||
|
||||
loader.style.display = 'block';
|
||||
container.style.display = 'none';
|
||||
|
||||
const data = await fetchData('/api/services');
|
||||
if (!data) {
|
||||
loader.textContent = 'Fehler beim Laden der Dienstdaten';
|
||||
return;
|
||||
}
|
||||
|
||||
// Frontend-Status
|
||||
document.getElementById('frontend-status').innerHTML = `
|
||||
<p>Status: <span class="status ${data.frontend.status === 'online' ? 'status-online' : 'status-offline'}">${data.frontend.status}</span></p>
|
||||
<p><strong>Name:</strong> ${data.frontend.name}</p>
|
||||
<p><strong>Host:</strong> ${data.frontend.host}</p>
|
||||
<p><strong>Port:</strong> ${data.frontend.port}</p>
|
||||
`;
|
||||
|
||||
// Backend-Status
|
||||
document.getElementById('backend-status').innerHTML = `
|
||||
<p>Status: <span class="status ${data.backend.status === 'online' ? 'status-online' : 'status-offline'}">${data.backend.status}</span></p>
|
||||
<p><strong>Name:</strong> ${data.backend.name}</p>
|
||||
<p><strong>Host:</strong> ${data.backend.host}</p>
|
||||
<p><strong>Port:</strong> ${data.backend.port}</p>
|
||||
`;
|
||||
|
||||
// Docker-Container
|
||||
if (data.docker.containers && data.docker.containers.length > 0) {
|
||||
let containersHTML = '<table><tr><th>ID</th><th>Name</th><th>Image</th><th>Status</th><th>Ports</th></tr>';
|
||||
|
||||
data.docker.containers.forEach(container => {
|
||||
containersHTML += `
|
||||
<tr>
|
||||
<td>${container.id}</td>
|
||||
<td>${container.name}</td>
|
||||
<td>${container.image}</td>
|
||||
<td>${container.status}</td>
|
||||
<td>${container.ports}</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
containersHTML += '</table>';
|
||||
document.getElementById('docker-container-list').innerHTML = containersHTML;
|
||||
} else {
|
||||
document.getElementById('docker-container-list').innerHTML = '<p>Keine Docker-Container gefunden</p>';
|
||||
}
|
||||
|
||||
// UI anzeigen
|
||||
loader.style.display = 'none';
|
||||
container.style.display = 'grid';
|
||||
}
|
||||
|
||||
// Netzwerk-Tools
|
||||
document.getElementById('ping-button').addEventListener('click', async () => {
|
||||
const hostInput = document.getElementById('ping-host');
|
||||
const resultBox = document.getElementById('ping-result');
|
||||
const host = hostInput.value.trim();
|
||||
|
||||
if (!host) {
|
||||
resultBox.textContent = 'Bitte geben Sie einen Hostnamen oder eine IP-Adresse ein';
|
||||
return;
|
||||
}
|
||||
|
||||
resultBox.textContent = 'Ping wird ausgeführt...';
|
||||
|
||||
const data = await fetchData(`/api/ping/${encodeURIComponent(host)}`);
|
||||
if (!data) {
|
||||
resultBox.textContent = 'Fehler beim Ausführen des Ping-Befehls';
|
||||
return;
|
||||
}
|
||||
|
||||
resultBox.textContent = data.output || data.error || 'Keine Ausgabe';
|
||||
});
|
||||
|
||||
document.getElementById('traceroute-button').addEventListener('click', async () => {
|
||||
const hostInput = document.getElementById('traceroute-host');
|
||||
const resultBox = document.getElementById('traceroute-result');
|
||||
const host = hostInput.value.trim();
|
||||
|
||||
if (!host) {
|
||||
resultBox.textContent = 'Bitte geben Sie einen Hostnamen oder eine IP-Adresse ein';
|
||||
return;
|
||||
}
|
||||
|
||||
resultBox.textContent = 'Traceroute wird ausgeführt...';
|
||||
|
||||
const data = await fetchData(`/api/traceroute/${encodeURIComponent(host)}`);
|
||||
if (!data) {
|
||||
resultBox.textContent = 'Fehler beim Ausführen des Traceroute-Befehls';
|
||||
return;
|
||||
}
|
||||
|
||||
resultBox.textContent = data.output || data.error || 'Keine Ausgabe';
|
||||
});
|
||||
|
||||
document.getElementById('nslookup-button').addEventListener('click', async () => {
|
||||
const hostInput = document.getElementById('nslookup-host');
|
||||
const resultBox = document.getElementById('nslookup-result');
|
||||
const host = hostInput.value.trim();
|
||||
|
||||
if (!host) {
|
||||
resultBox.textContent = 'Bitte geben Sie einen Hostnamen oder eine IP-Adresse ein';
|
||||
return;
|
||||
}
|
||||
|
||||
resultBox.textContent = 'DNS-Abfrage wird ausgeführt...';
|
||||
|
||||
const data = await fetchData(`/api/nslookup/${encodeURIComponent(host)}`);
|
||||
if (!data) {
|
||||
resultBox.textContent = 'Fehler beim Ausführen des NSLookup-Befehls';
|
||||
return;
|
||||
}
|
||||
|
||||
resultBox.textContent = data.output || data.error || 'Keine Ausgabe';
|
||||
});
|
||||
|
||||
// Echtzeit-Monitoring mit WebSockets
|
||||
const socket = io();
|
||||
|
||||
// CPU- und RAM-Statistiken
|
||||
socket.on('system-stats', data => {
|
||||
// CPU-Anzeige aktualisieren
|
||||
const cpuPercentage = data.cpu.load;
|
||||
document.getElementById('cpu-percentage').textContent = `${cpuPercentage}%`;
|
||||
document.getElementById('cpu-gauge').style.height = `${cpuPercentage}%`;
|
||||
document.getElementById('cpu-gauge').style.backgroundColor = getColorByPercentage(cpuPercentage);
|
||||
|
||||
// CPU-Kerne anzeigen
|
||||
const cpuCoresContainer = document.getElementById('cpu-cores-container');
|
||||
|
||||
if (cpuCoresContainer.childElementCount === 0) {
|
||||
// Erstelle Kern-Anzeigen, falls sie noch nicht existieren
|
||||
data.cpu.cores.forEach((load, index) => {
|
||||
const coreElement = document.createElement('div');
|
||||
coreElement.className = 'cpu-core';
|
||||
coreElement.innerHTML = `
|
||||
<div class="cpu-core-label">
|
||||
<span>Kern ${index}</span>
|
||||
<span id="cpu-core-${index}-value">${load}%</span>
|
||||
</div>
|
||||
<div class="cpu-core-bar">
|
||||
<div id="cpu-core-${index}-fill" class="cpu-core-fill" style="width: ${load}%; background-color: ${getColorByPercentage(load)}"></div>
|
||||
</div>
|
||||
`;
|
||||
cpuCoresContainer.appendChild(coreElement);
|
||||
});
|
||||
} else {
|
||||
// Aktualisiere bestehende Kern-Anzeigen
|
||||
data.cpu.cores.forEach((load, index) => {
|
||||
const valueElement = document.getElementById(`cpu-core-${index}-value`);
|
||||
const fillElement = document.getElementById(`cpu-core-${index}-fill`);
|
||||
|
||||
if (valueElement && fillElement) {
|
||||
valueElement.textContent = `${load}%`;
|
||||
fillElement.style.width = `${load}%`;
|
||||
fillElement.style.backgroundColor = getColorByPercentage(load);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// RAM-Anzeige aktualisieren
|
||||
const memPercentage = data.memory.usedPercent;
|
||||
document.getElementById('memory-percentage').textContent = `${memPercentage}%`;
|
||||
document.getElementById('memory-gauge').style.height = `${memPercentage}%`;
|
||||
document.getElementById('memory-gauge').style.backgroundColor = getColorByPercentage(memPercentage);
|
||||
|
||||
document.getElementById('memory-details').innerHTML = `
|
||||
<p><strong>Gesamt:</strong> ${formatBytes(data.memory.total)}</p>
|
||||
<p><strong>Verwendet:</strong> ${formatBytes(data.memory.used)}</p>
|
||||
<p><strong>Frei:</strong> ${formatBytes(data.memory.free)}</p>
|
||||
`;
|
||||
});
|
||||
|
||||
// Netzwerkstatistiken
|
||||
let networkChart;
|
||||
socket.on('network-stats', data => {
|
||||
const networkThroughput = document.getElementById('network-throughput');
|
||||
let throughputHTML = '';
|
||||
|
||||
data.stats.forEach(stat => {
|
||||
throughputHTML += `
|
||||
<div class="network-stat">
|
||||
<strong>${stat.iface}:</strong> ↓ ${formatBytes(stat.rx_sec)}/s | ↑ ${formatBytes(stat.tx_sec)}/s
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
|
||||
networkThroughput.innerHTML = throughputHTML;
|
||||
|
||||
// Aktualisiere oder erstelle Netzwerk-Chart
|
||||
updateNetworkChart(data.stats);
|
||||
});
|
||||
|
||||
// Netzwerk-Chart initialisieren oder aktualisieren
|
||||
function updateNetworkChart(stats) {
|
||||
const ctx = document.getElementById('network-chart').getContext('2d');
|
||||
|
||||
if (!networkChart) {
|
||||
// Chart initialisieren, wenn er noch nicht existiert
|
||||
const labels = [];
|
||||
const rxData = [];
|
||||
const txData = [];
|
||||
|
||||
// Fülle anfängliche Daten
|
||||
for (let i = 0; i < 20; i++) {
|
||||
labels.push('');
|
||||
rxData.push(0);
|
||||
txData.push(0);
|
||||
}
|
||||
|
||||
networkChart = new Chart(ctx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [
|
||||
{
|
||||
label: 'Empfangen (Bytes/s)',
|
||||
data: rxData,
|
||||
borderColor: '#3f51b5',
|
||||
backgroundColor: 'rgba(63, 81, 181, 0.1)',
|
||||
borderWidth: 2,
|
||||
tension: 0.2,
|
||||
fill: true
|
||||
},
|
||||
{
|
||||
label: 'Gesendet (Bytes/s)',
|
||||
data: txData,
|
||||
borderColor: '#f44336',
|
||||
backgroundColor: 'rgba(244, 67, 54, 0.1)',
|
||||
borderWidth: 2,
|
||||
tension: 0.2,
|
||||
fill: true
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
callback: function(value) {
|
||||
return formatBytes(value, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
animation: {
|
||||
duration: 300
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Chart aktualisieren
|
||||
let rxTotal = 0;
|
||||
let txTotal = 0;
|
||||
|
||||
stats.forEach(stat => {
|
||||
rxTotal += stat.rx_sec || 0;
|
||||
txTotal += stat.tx_sec || 0;
|
||||
});
|
||||
|
||||
// Füge neue Daten hinzu und entferne alte
|
||||
networkChart.data.labels.push('');
|
||||
networkChart.data.labels.shift();
|
||||
|
||||
networkChart.data.datasets[0].data.push(rxTotal);
|
||||
networkChart.data.datasets[0].data.shift();
|
||||
|
||||
networkChart.data.datasets[1].data.push(txTotal);
|
||||
networkChart.data.datasets[1].data.shift();
|
||||
|
||||
networkChart.update();
|
||||
}
|
||||
}
|
||||
|
||||
// Hilfsfunktionen
|
||||
function getColorByPercentage(percent) {
|
||||
// Farbverlauf von Grün über Gelb nach Rot
|
||||
if (percent < 70) {
|
||||
return 'var(--success-color)';
|
||||
} else if (percent < 90) {
|
||||
return 'var(--warning-color)';
|
||||
} else {
|
||||
return 'var(--danger-color)';
|
||||
}
|
||||
}
|
||||
|
||||
function formatBytes(bytes, decimals = 2) {
|
||||
if (bytes === 0) return '0 B';
|
||||
|
||||
const k = 1024;
|
||||
const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(decimals)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
// Initialisierung
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Zeit aktualisieren
|
||||
setInterval(() => {
|
||||
document.getElementById('current-time').innerHTML = `<strong>Zeitstempel:</strong> ${new Date().toLocaleString('de-DE')}`;
|
||||
}, 1000);
|
||||
|
||||
// Lade Systemdaten, wenn das System-Panel aktiv ist
|
||||
if (document.getElementById('system').classList.contains('active')) {
|
||||
loadSystemInfo();
|
||||
}
|
||||
|
||||
// Lade Script für Netzwerk-Chart, falls noch nicht geladen
|
||||
if (typeof Chart === 'undefined') {
|
||||
const script = document.createElement('script');
|
||||
script.src = 'https://cdn.jsdelivr.net/npm/chart.js';
|
||||
script.onload = () => {
|
||||
console.log('Chart.js geladen');
|
||||
};
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
});
|
Reference in New Issue
Block a user