"feat: Implement new debug server components for reservation platform"
This commit is contained in:
291
backend/debug-server/static/css/style.css
Normal file
291
backend/debug-server/static/css/style.css
Normal file
@@ -0,0 +1,291 @@
|
||||
/* Allgemeine Stile */
|
||||
:root {
|
||||
--primary-color: #3498db;
|
||||
--secondary-color: #2c3e50;
|
||||
--background-color: #f5f7fa;
|
||||
--card-color: #ffffff;
|
||||
--text-color: #333333;
|
||||
--border-color: #e0e0e0;
|
||||
--success-color: #2ecc71;
|
||||
--warning-color: #f39c12;
|
||||
--danger-color: #e74c3c;
|
||||
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: var(--text-color);
|
||||
background-color: var(--background-color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
header {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
padding: 1rem 2rem;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.header-content {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.8rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.server-info {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 1rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Navigation */
|
||||
nav {
|
||||
background-color: var(--secondary-color);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 0.5rem 1rem;
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-button {
|
||||
background: none;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0.75rem 1.25rem;
|
||||
margin: 0 0.25rem;
|
||||
cursor: pointer;
|
||||
font-size: 1rem;
|
||||
border-radius: 4px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.nav-button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
.nav-button.active {
|
||||
background-color: var(--primary-color);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Hauptbereich */
|
||||
main {
|
||||
flex: 1;
|
||||
padding: 2rem;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.panel {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.panel.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-bottom: 1.5rem;
|
||||
color: var(--secondary-color);
|
||||
border-bottom: 2px solid var(--primary-color);
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.card-container {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: var(--card-color);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
box-shadow: var(--shadow);
|
||||
}
|
||||
|
||||
.card.full-width {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 1rem;
|
||||
color: var(--secondary-color);
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
/* Fortschrittsbalken */
|
||||
.progress-container {
|
||||
margin-top: 1rem;
|
||||
background-color: #f0f0f0;
|
||||
border-radius: 4px;
|
||||
height: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 100%;
|
||||
background-color: var(--primary-color);
|
||||
width: 0%;
|
||||
transition: width 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
/* Tool-Karten */
|
||||
.tool-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.tool-input {
|
||||
display: flex;
|
||||
margin-bottom: 1rem;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.tool-input input {
|
||||
flex: 1;
|
||||
padding: 0.5rem;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.tool-input button {
|
||||
background-color: var(--primary-color);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 0.5rem 1rem;
|
||||
cursor: pointer;
|
||||
border-radius: 4px;
|
||||
font-size: 1rem;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.tool-input button:hover {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
|
||||
.result-box {
|
||||
background-color: #f8f9fa;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 4px;
|
||||
padding: 1rem;
|
||||
overflow: auto;
|
||||
min-height: 150px;
|
||||
max-height: 300px;
|
||||
font-family: 'Consolas', 'Courier New', monospace;
|
||||
font-size: 0.9rem;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Tabellen */
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 0.75rem;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f0f0f0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
/* Status-Anzeigen */
|
||||
.status {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.9rem;
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.status-online {
|
||||
background-color: var(--success-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.status-offline {
|
||||
background-color: var(--danger-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.status-warning {
|
||||
background-color: var(--warning-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
footer {
|
||||
background-color: var(--secondary-color);
|
||||
color: white;
|
||||
text-align: center;
|
||||
padding: 1rem;
|
||||
margin-top: auto;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
footer p {
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
header {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.header-content {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.server-info {
|
||||
margin-top: 1rem;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
main {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.card-container {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.nav-button {
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
306
backend/debug-server/static/js/script.js
Normal file
306
backend/debug-server/static/js/script.js
Normal file
@@ -0,0 +1,306 @@
|
||||
// DOM-Element-Referenzen
|
||||
const navButtons = document.querySelectorAll('.nav-button');
|
||||
const panels = document.querySelectorAll('.panel');
|
||||
|
||||
// Panel-Navigation
|
||||
navButtons.forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const targetPanel = button.dataset.target;
|
||||
|
||||
// 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(targetPanel).classList.add('active');
|
||||
});
|
||||
});
|
||||
|
||||
// Automatische Aktualisierung der Daten
|
||||
const updateInterval = 10000; // 10 Sekunden
|
||||
|
||||
// Initialisierung und erste Datenladung
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
// Systemdaten laden
|
||||
loadSystemInfo();
|
||||
|
||||
// Netzwerkdaten laden
|
||||
loadNetworkInfo();
|
||||
|
||||
// Docker-Daten laden
|
||||
loadDockerInfo();
|
||||
|
||||
// Backend-Status laden
|
||||
loadBackendStatus();
|
||||
|
||||
// Event-Listener für die Netzwerk-Tools
|
||||
document.getElementById('ping-button').addEventListener('click', performPing);
|
||||
document.getElementById('traceroute-button').addEventListener('click', performTraceroute);
|
||||
document.getElementById('nslookup-button').addEventListener('click', performNSLookup);
|
||||
|
||||
// Automatische Aktualisierung einrichten
|
||||
setInterval(() => {
|
||||
if (document.getElementById('system-panel').classList.contains('active')) {
|
||||
loadSystemInfo();
|
||||
} else if (document.getElementById('network-panel').classList.contains('active')) {
|
||||
loadNetworkInfo();
|
||||
} else if (document.getElementById('docker-panel').classList.contains('active')) {
|
||||
loadDockerInfo();
|
||||
} else if (document.getElementById('backend-panel').classList.contains('active')) {
|
||||
loadBackendStatus();
|
||||
}
|
||||
}, updateInterval);
|
||||
});
|
||||
|
||||
// API-Anfragen
|
||||
async function fetchData(endpoint) {
|
||||
try {
|
||||
const response = await fetch(endpoint);
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP-Fehler! Status: ${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 data = await fetchData('/systeminfo');
|
||||
if (!data) return;
|
||||
|
||||
// Betriebssystem-Info aktualisieren
|
||||
document.getElementById('platform-info').innerHTML = `
|
||||
<p><strong>Plattform:</strong> ${data.platform}</p>
|
||||
<p><strong>Python Version:</strong> ${data.python_version}</p>
|
||||
<p><strong>Betriebszeit:</strong> ${data.uptime}</p>
|
||||
`;
|
||||
|
||||
// Hardware-Info aktualisieren
|
||||
document.getElementById('hardware-info').innerHTML = `
|
||||
<p><strong>Prozessor:</strong> ${data.processor}</p>
|
||||
<p><strong>Architektur:</strong> ${data.architecture}</p>
|
||||
`;
|
||||
|
||||
// Speicher-Info aktualisieren
|
||||
document.getElementById('memory-info').innerHTML = `
|
||||
<p><strong>Gesamt:</strong> ${data.memory.total}</p>
|
||||
<p><strong>Verwendet:</strong> ${data.memory.used} (${data.memory.percent}%)</p>
|
||||
<p><strong>Frei:</strong> ${data.memory.free}</p>
|
||||
`;
|
||||
document.getElementById('memory-bar').style.width = `${data.memory.percent}%`;
|
||||
document.getElementById('memory-bar').style.backgroundColor = getColorByPercentage(data.memory.percent);
|
||||
|
||||
// Festplatten-Info aktualisieren
|
||||
document.getElementById('disk-info').innerHTML = `
|
||||
<p><strong>Gesamt:</strong> ${data.disk.total}</p>
|
||||
<p><strong>Verwendet:</strong> ${data.disk.used} (${data.disk.percent}%)</p>
|
||||
<p><strong>Frei:</strong> ${data.disk.free}</p>
|
||||
`;
|
||||
document.getElementById('disk-bar').style.width = `${data.disk.percent}%`;
|
||||
document.getElementById('disk-bar').style.backgroundColor = getColorByPercentage(data.disk.percent);
|
||||
}
|
||||
|
||||
// Netzwerk-Informationen laden
|
||||
async function loadNetworkInfo() {
|
||||
const data = await fetchData('/network');
|
||||
if (!data) return;
|
||||
|
||||
// Netzwerkschnittstellen aktualisieren
|
||||
let interfacesHTML = '<table><tr><th>Schnittstelle</th><th>IP-Adresse</th><th>Netzmaske</th><th>Broadcast</th></tr>';
|
||||
for (const [name, info] of Object.entries(data.interfaces)) {
|
||||
interfacesHTML += `
|
||||
<tr>
|
||||
<td>${name}</td>
|
||||
<td>${info.ip}</td>
|
||||
<td>${info.netmask}</td>
|
||||
<td>${info.broadcast}</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
interfacesHTML += '</table>';
|
||||
document.getElementById('network-interfaces').innerHTML = interfacesHTML;
|
||||
|
||||
// DNS-Server aktualisieren
|
||||
let dnsHTML = '<ul>';
|
||||
for (const server of data.dns_servers) {
|
||||
dnsHTML += `<li>${server}</li>`;
|
||||
}
|
||||
dnsHTML += '</ul>';
|
||||
document.getElementById('dns-servers').innerHTML = dnsHTML;
|
||||
|
||||
// Gateway aktualisieren
|
||||
document.getElementById('default-gateway').innerHTML = `<p>${data.gateway}</p>`;
|
||||
|
||||
// Aktive Verbindungen aktualisieren
|
||||
if (data.connections && data.connections.length > 0) {
|
||||
let connectionsHTML = '<table><tr><th>Lokale Adresse</th><th>Remote-Adresse</th><th>Status</th><th>PID</th></tr>';
|
||||
for (const conn of data.connections) {
|
||||
connectionsHTML += `
|
||||
<tr>
|
||||
<td>${conn.local_address}</td>
|
||||
<td>${conn.remote_address}</td>
|
||||
<td>${conn.status}</td>
|
||||
<td>${conn.pid}</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
connectionsHTML += '</table>';
|
||||
document.getElementById('active-connections').innerHTML = connectionsHTML;
|
||||
} else {
|
||||
document.getElementById('active-connections').innerHTML = '<p>Keine aktiven Verbindungen gefunden.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
// Docker-Informationen laden
|
||||
async function loadDockerInfo() {
|
||||
const data = await fetchData('/docker');
|
||||
if (!data) return;
|
||||
|
||||
// Docker-Status aktualisieren
|
||||
if (data.installed) {
|
||||
document.getElementById('docker-status').innerHTML = `
|
||||
<p><span class="status status-online">Installiert</span></p>
|
||||
<p><strong>Version:</strong> ${data.version}</p>
|
||||
`;
|
||||
|
||||
// Container aktualisieren
|
||||
if (data.containers && data.containers.length > 0) {
|
||||
let containersHTML = '<table><tr><th>ID</th><th>Name</th><th>Image</th><th>Status</th><th>Ports</th></tr>';
|
||||
for (const container of data.containers) {
|
||||
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-containers').innerHTML = containersHTML;
|
||||
} else {
|
||||
document.getElementById('docker-containers').innerHTML = '<p>Keine laufenden Container gefunden.</p>';
|
||||
}
|
||||
} else {
|
||||
document.getElementById('docker-status').innerHTML = '<p><span class="status status-offline">Nicht installiert</span></p>';
|
||||
document.getElementById('docker-containers').innerHTML = '<p>Docker ist nicht installiert oder nicht zugänglich.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
// Backend-Status laden
|
||||
async function loadBackendStatus() {
|
||||
const data = await fetchData('/backend-status');
|
||||
if (!data) return;
|
||||
|
||||
let statusHTML = '';
|
||||
if (data.status === 'online') {
|
||||
statusHTML = `
|
||||
<p>Status: <span class="status status-online">Online</span></p>
|
||||
<p><strong>Port:</strong> ${data.port}</p>
|
||||
`;
|
||||
} else if (data.status === 'offline') {
|
||||
statusHTML = `
|
||||
<p>Status: <span class="status status-offline">Offline</span></p>
|
||||
<p><strong>Port:</strong> ${data.port}</p>
|
||||
<p><strong>Fehlercode:</strong> ${data.error_code}</p>
|
||||
`;
|
||||
} else {
|
||||
statusHTML = `
|
||||
<p>Status: <span class="status status-warning">Fehler</span></p>
|
||||
<p><strong>Nachricht:</strong> ${data.message}</p>
|
||||
`;
|
||||
}
|
||||
document.getElementById('main-backend-status').innerHTML = statusHTML;
|
||||
}
|
||||
|
||||
// Netzwerk-Tools
|
||||
async function performPing() {
|
||||
const hostInput = document.getElementById('ping-host');
|
||||
const resultElement = document.getElementById('ping-result');
|
||||
const host = hostInput.value.trim();
|
||||
|
||||
if (!host) {
|
||||
resultElement.textContent = 'Bitte geben Sie einen Hostnamen oder eine IP-Adresse ein.';
|
||||
return;
|
||||
}
|
||||
|
||||
resultElement.textContent = 'Ping wird ausgeführt...';
|
||||
|
||||
const data = await fetchData(`/ping/${encodeURIComponent(host)}`);
|
||||
if (!data) {
|
||||
resultElement.textContent = 'Fehler beim Ausführen des Ping-Befehls.';
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.success) {
|
||||
resultElement.textContent = data.output;
|
||||
} else {
|
||||
resultElement.textContent = `Fehler: ${data.error || 'Unbekannter Fehler'}`;
|
||||
}
|
||||
}
|
||||
|
||||
async function performTraceroute() {
|
||||
const hostInput = document.getElementById('traceroute-host');
|
||||
const resultElement = document.getElementById('traceroute-result');
|
||||
const host = hostInput.value.trim();
|
||||
|
||||
if (!host) {
|
||||
resultElement.textContent = 'Bitte geben Sie einen Hostnamen oder eine IP-Adresse ein.';
|
||||
return;
|
||||
}
|
||||
|
||||
resultElement.textContent = 'Traceroute wird ausgeführt...';
|
||||
|
||||
const data = await fetchData(`/traceroute/${encodeURIComponent(host)}`);
|
||||
if (!data) {
|
||||
resultElement.textContent = 'Fehler beim Ausführen des Traceroute-Befehls.';
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.success) {
|
||||
resultElement.textContent = data.output;
|
||||
} else {
|
||||
resultElement.textContent = `Fehler: ${data.error || 'Unbekannter Fehler'}`;
|
||||
}
|
||||
}
|
||||
|
||||
async function performNSLookup() {
|
||||
const hostInput = document.getElementById('nslookup-host');
|
||||
const resultElement = document.getElementById('nslookup-result');
|
||||
const host = hostInput.value.trim();
|
||||
|
||||
if (!host) {
|
||||
resultElement.textContent = 'Bitte geben Sie einen Hostnamen oder eine IP-Adresse ein.';
|
||||
return;
|
||||
}
|
||||
|
||||
resultElement.textContent = 'DNS-Abfrage wird ausgeführt...';
|
||||
|
||||
const data = await fetchData(`/nslookup/${encodeURIComponent(host)}`);
|
||||
if (!data) {
|
||||
resultElement.textContent = 'Fehler beim Ausführen des NSLookup-Befehls.';
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.success) {
|
||||
resultElement.textContent = data.output;
|
||||
} else {
|
||||
resultElement.textContent = `Fehler: ${data.error || 'Unbekannter Fehler'}`;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)';
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user