new file: app.py new file: config.example.json new file: config.json new file: docker_diagnose.py new file: requirements.txt new file: start.bat new file: templates/available_projects.html new file: templates/base.html new file: templates/config.html new file: templates/docker_status.html new file: templates/index.html new file: templates/project_details.html new file: templates/project_details_fixed.html new file: templates/project_details_new.html new file: templates/project_details_old.html .gitignore
426 lines
16 KiB
HTML
426 lines
16 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Docker Status - {{ super() }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h2><i class="fas fa-docker me-2"></i>Docker Status & Diagnose</h2>
|
|
<button class="btn btn-primary" onclick="runDiagnose()">
|
|
<i class="fas fa-stethoscope"></i> Diagnose ausführen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Docker Status Cards -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card">
|
|
<div class="card-body text-center">
|
|
<div class="stat-item">
|
|
<i class="fas fa-docker fa-2x mb-2" id="dockerIcon"></i>
|
|
<div class="stat-number" id="dockerStatus">Prüfung...</div>
|
|
<div class="text-muted">Docker Status</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card">
|
|
<div class="card-body text-center">
|
|
<div class="stat-item">
|
|
<i class="fas fa-server fa-2x mb-2" id="daemonIcon"></i>
|
|
<div class="stat-number" id="daemonStatus">Prüfung...</div>
|
|
<div class="text-muted">Daemon Status</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card">
|
|
<div class="card-body text-center">
|
|
<div class="stat-item">
|
|
<i class="fas fa-box fa-2x mb-2" id="containerIcon"></i>
|
|
<div class="stat-number" id="containerCount">-</div>
|
|
<div class="text-muted">Container</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card">
|
|
<div class="card-body text-center">
|
|
<div class="stat-item">
|
|
<i class="fas fa-layer-group fa-2x mb-2" id="imageIcon"></i>
|
|
<div class="stat-number" id="imageCount">-</div>
|
|
<div class="text-muted">Images</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Diagnose Ergebnisse -->
|
|
<div class="row">
|
|
<div class="col-lg-8">
|
|
<div class="card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-clipboard-list me-2"></i>Diagnose Ergebnisse
|
|
</h5>
|
|
<span class="badge bg-secondary" id="lastUpdate">Noch nicht ausgeführt</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="diagnoseResults">
|
|
<div class="text-center text-muted py-4">
|
|
<i class="fas fa-info-circle fa-2x mb-3"></i>
|
|
<p>Klicken Sie auf "Diagnose ausführen" um Docker zu überprüfen.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Docker Logs -->
|
|
<div class="card mt-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-terminal me-2"></i>Docker System Logs
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div id="dockerLogs" class="bg-dark text-light p-3 rounded font-monospace small" style="height: 300px; overflow-y: auto;">
|
|
<div class="text-center text-muted">
|
|
Docker Logs werden geladen...
|
|
</div>
|
|
</div>
|
|
<div class="mt-2">
|
|
<button class="btn btn-outline-info btn-sm" onclick="refreshDockerLogs()">
|
|
<i class="fas fa-sync-alt"></i> Logs aktualisieren
|
|
</button>
|
|
<button class="btn btn-outline-warning btn-sm" onclick="clearDockerLogs()">
|
|
<i class="fas fa-broom"></i> Logs leeren
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-4">
|
|
<!-- Schnellaktionen -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-bolt me-2"></i>Docker Aktionen
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-grid gap-2">
|
|
<button class="btn btn-success" onclick="startDockerDesktop()">
|
|
<i class="fas fa-play"></i> Docker Desktop starten
|
|
</button>
|
|
<button class="btn btn-warning" onclick="restartDockerDesktop()">
|
|
<i class="fas fa-redo"></i> Docker Desktop neustarten
|
|
</button>
|
|
<button class="btn btn-info" onclick="pullHelloWorld()">
|
|
<i class="fas fa-download"></i> Test Image herunterladen
|
|
</button>
|
|
<button class="btn btn-outline-secondary" onclick="openDockerDesktop()">
|
|
<i class="fas fa-external-link-alt"></i> Docker Desktop öffnen
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Systemanforderungen -->
|
|
<div class="card mb-4">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-clipboard-check me-2"></i>Systemanforderungen
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="requirements-list">
|
|
<div class="requirement-item mb-2">
|
|
<i class="fas fa-check text-success me-2"></i>
|
|
<span>Windows 10/11 (64-bit)</span>
|
|
</div>
|
|
<div class="requirement-item mb-2">
|
|
<i class="fas fa-check text-success me-2"></i>
|
|
<span>Hyper-V oder WSL2</span>
|
|
</div>
|
|
<div class="requirement-item mb-2">
|
|
<i class="fas fa-question text-warning me-2" id="ramCheck"></i>
|
|
<span>4GB+ RAM empfohlen</span>
|
|
</div>
|
|
<div class="requirement-item mb-2">
|
|
<i class="fas fa-question text-warning me-2" id="diskCheck"></i>
|
|
<span>20GB+ freier Speicher</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Hilfe & Ressourcen -->
|
|
<div class="card">
|
|
<div class="card-header">
|
|
<h5 class="card-title mb-0">
|
|
<i class="fas fa-question-circle me-2"></i>Hilfe & Ressourcen
|
|
</h5>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="d-grid gap-2">
|
|
<a href="https://docs.docker.com/desktop/windows/" target="_blank" class="btn btn-outline-primary btn-sm">
|
|
<i class="fas fa-book"></i> Docker Desktop Docs
|
|
</a>
|
|
<a href="https://docs.docker.com/desktop/troubleshoot/" target="_blank" class="btn btn-outline-info btn-sm">
|
|
<i class="fas fa-wrench"></i> Troubleshooting Guide
|
|
</a>
|
|
<a href="https://www.docker.com/products/docker-desktop/" target="_blank" class="btn btn-outline-success btn-sm">
|
|
<i class="fas fa-download"></i> Docker Desktop Download
|
|
</a>
|
|
<button class="btn btn-outline-warning btn-sm" onclick="exportDiagnose()">
|
|
<i class="fas fa-file-export"></i> Diagnose exportieren
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Installation Modal -->
|
|
<div class="modal fade" id="installModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Docker Desktop Installation</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<h6>Installationsschritte:</h6>
|
|
<ol>
|
|
<li>Laden Sie Docker Desktop von <a href="https://www.docker.com/products/docker-desktop/" target="_blank">docker.com</a> herunter</li>
|
|
<li>Führen Sie die Installationsdatei als Administrator aus</li>
|
|
<li>Folgen Sie dem Installationsassistenten</li>
|
|
<li>Starten Sie Ihren Computer neu</li>
|
|
<li>Starten Sie Docker Desktop</li>
|
|
<li>Warten Sie bis Docker vollständig geladen ist</li>
|
|
</ol>
|
|
|
|
<div class="alert alert-info">
|
|
<i class="fas fa-info-circle me-2"></i>
|
|
<strong>Hinweis:</strong> Docker Desktop erfordert Hyper-V oder WSL2.
|
|
Diese werden automatisch aktiviert falls nötig.
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Schließen</button>
|
|
<a href="https://www.docker.com/products/docker-desktop/" target="_blank" class="btn btn-primary">
|
|
<i class="fas fa-download"></i> Docker Desktop herunterladen
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
let lastDiagnoseData = null;
|
|
|
|
// Führe Diagnose aus
|
|
function runDiagnose() {
|
|
const button = event.target;
|
|
const originalText = button.innerHTML;
|
|
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Läuft...';
|
|
button.disabled = true;
|
|
|
|
fetch('/api/docker_diagnose')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
lastDiagnoseData = data;
|
|
displayDiagnoseResults(data);
|
|
updateStatusCards(data);
|
|
document.getElementById('lastUpdate').textContent = new Date(data.timestamp).toLocaleString();
|
|
})
|
|
.catch(error => {
|
|
console.error('Diagnose-Fehler:', error);
|
|
document.getElementById('diagnoseResults').innerHTML = `
|
|
<div class="alert alert-danger">
|
|
<i class="fas fa-exclamation-triangle me-2"></i>
|
|
Fehler bei der Diagnose: ${error}
|
|
</div>
|
|
`;
|
|
})
|
|
.finally(() => {
|
|
button.innerHTML = originalText;
|
|
button.disabled = false;
|
|
});
|
|
}
|
|
|
|
// Zeige Diagnose-Ergebnisse
|
|
function displayDiagnoseResults(data) {
|
|
const container = document.getElementById('diagnoseResults');
|
|
let html = '';
|
|
|
|
for (const [checkName, result] of Object.entries(data.checks)) {
|
|
const icon = result.success ? 'fa-check text-success' : 'fa-times text-danger';
|
|
const title = formatCheckName(checkName);
|
|
|
|
html += `
|
|
<div class="d-flex align-items-start mb-3">
|
|
<i class="fas ${icon} me-3 mt-1"></i>
|
|
<div class="flex-grow-1">
|
|
<h6 class="mb-1">${title}</h6>
|
|
<p class="mb-0 text-muted small">${result.output}</p>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
if (!html) {
|
|
html = '<div class="text-center text-muted">Keine Diagnose-Daten verfügbar.</div>';
|
|
}
|
|
|
|
container.innerHTML = html;
|
|
}
|
|
|
|
// Formatiere Check-Namen
|
|
function formatCheckName(name) {
|
|
const names = {
|
|
'docker_version': 'Docker Version',
|
|
'docker_daemon': 'Docker Daemon',
|
|
'containers': 'Container Status',
|
|
'images': 'Docker Images'
|
|
};
|
|
return names[name] || name;
|
|
}
|
|
|
|
// Update Status-Cards
|
|
function updateStatusCards(data) {
|
|
// Docker Status
|
|
if (data.checks.docker_version) {
|
|
const dockerIcon = document.getElementById('dockerIcon');
|
|
const dockerStatus = document.getElementById('dockerStatus');
|
|
|
|
if (data.checks.docker_version.success) {
|
|
dockerIcon.className = 'fas fa-docker fa-2x mb-2 text-success';
|
|
dockerStatus.textContent = 'Installiert';
|
|
dockerStatus.className = 'stat-number text-success';
|
|
} else {
|
|
dockerIcon.className = 'fas fa-docker fa-2x mb-2 text-danger';
|
|
dockerStatus.textContent = 'Nicht verfügbar';
|
|
dockerStatus.className = 'stat-number text-danger';
|
|
}
|
|
}
|
|
|
|
// Daemon Status
|
|
if (data.checks.docker_daemon) {
|
|
const daemonIcon = document.getElementById('daemonIcon');
|
|
const daemonStatus = document.getElementById('daemonStatus');
|
|
|
|
if (data.checks.docker_daemon.success) {
|
|
daemonIcon.className = 'fas fa-server fa-2x mb-2 text-success';
|
|
daemonStatus.textContent = 'Läuft';
|
|
daemonStatus.className = 'stat-number text-success';
|
|
} else {
|
|
daemonIcon.className = 'fas fa-server fa-2x mb-2 text-danger';
|
|
daemonStatus.textContent = 'Gestoppt';
|
|
daemonStatus.className = 'stat-number text-danger';
|
|
}
|
|
}
|
|
|
|
// Container Count
|
|
if (data.checks.containers && data.checks.containers.containers) {
|
|
const containerCount = document.getElementById('containerCount');
|
|
const count = data.checks.containers.containers.length;
|
|
containerCount.textContent = count;
|
|
|
|
const running = data.checks.containers.containers.filter(c => c.State === 'running').length;
|
|
containerCount.title = `${running} laufend, ${count - running} gestoppt`;
|
|
}
|
|
}
|
|
|
|
// Docker Desktop Aktionen
|
|
function startDockerDesktop() {
|
|
alert('Bitte starten Sie Docker Desktop manuell über das Startmenü.');
|
|
}
|
|
|
|
function restartDockerDesktop() {
|
|
if (confirm('Docker Desktop neustarten? Dies kann einige Minuten dauern.')) {
|
|
alert('Bitte starten Sie Docker Desktop manuell neu:\n1. Docker Desktop schließen\n2. Docker Desktop wieder öffnen\n3. Warten bis vollständig geladen');
|
|
}
|
|
}
|
|
|
|
function pullHelloWorld() {
|
|
const button = event.target;
|
|
const originalText = button.innerHTML;
|
|
button.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Lädt...';
|
|
button.disabled = true;
|
|
|
|
// Simuliere Docker Pull (in echter Implementation würde hier eine API-Call erfolgen)
|
|
setTimeout(() => {
|
|
alert('Test abgeschlossen. Prüfen Sie die Diagnose für Details.');
|
|
button.innerHTML = originalText;
|
|
button.disabled = false;
|
|
runDiagnose();
|
|
}, 3000);
|
|
}
|
|
|
|
function openDockerDesktop() {
|
|
// Versuche Docker Desktop zu öffnen
|
|
alert('Suchen Sie nach "Docker Desktop" im Startmenü oder klicken Sie auf das Docker-Symbol in der Taskleiste.');
|
|
}
|
|
|
|
// Docker Logs
|
|
function refreshDockerLogs() {
|
|
const logsContainer = document.getElementById('dockerLogs');
|
|
logsContainer.innerHTML = '<div class="text-center text-muted">Docker Logs werden geladen...</div>';
|
|
|
|
// Simuliere Log-Abruf
|
|
setTimeout(() => {
|
|
const logs = `[${new Date().toISOString()}] Docker Desktop starting...
|
|
[${new Date().toISOString()}] Hyper-V backend initialized
|
|
[${new Date().toISOString()}] WSL2 engine started
|
|
[${new Date().toISOString()}] Docker daemon started
|
|
[${new Date().toISOString()}] Ready for connections`;
|
|
|
|
logsContainer.innerHTML = `<pre class="mb-0">${logs}</pre>`;
|
|
logsContainer.scrollTop = logsContainer.scrollHeight;
|
|
}, 1000);
|
|
}
|
|
|
|
function clearDockerLogs() {
|
|
if (confirm('Docker Logs leeren?')) {
|
|
document.getElementById('dockerLogs').innerHTML = '<div class="text-center text-muted">Logs geleert</div>';
|
|
}
|
|
}
|
|
|
|
// Export Diagnose
|
|
function exportDiagnose() {
|
|
if (!lastDiagnoseData) {
|
|
alert('Bitte führen Sie zuerst eine Diagnose aus.');
|
|
return;
|
|
}
|
|
|
|
const dataStr = JSON.stringify(lastDiagnoseData, null, 2);
|
|
const blob = new Blob([dataStr], {type: 'application/json'});
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = `docker_diagnose_${new Date().toISOString().split('T')[0]}.json`;
|
|
a.click();
|
|
|
|
URL.revokeObjectURL(url);
|
|
}
|
|
|
|
// Auto-Diagnose beim Laden
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
runDiagnose();
|
|
refreshDockerLogs();
|
|
});
|
|
</script>
|
|
{% endblock %}
|