Files
app-installer/templates/custom_install.html
SimolZimol d6ae4853d8 modified: app.py
modified:   config.json
	modified:   templates/available_projects.html
	modified:   templates/base.html
	new file:   templates/custom_install.html
2025-07-08 17:53:27 +02:00

397 lines
19 KiB
HTML

{% extends "base.html" %}
{% block title %}{{ project.name }} - Installation - {{ super() }}{% endblock %}
{% block content %}
<div class="container-fluid">
<!-- Header -->
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h2>
<i class="fas fa-download me-2"></i>{{ project.name }} Installation
</h2>
<p class="text-muted mb-0">{{ project.description }}</p>
</div>
<div>
<a href="{{ url_for('available_projects') }}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left"></i> Zurück zur Liste
</a>
</div>
</div>
<div class="row">
<!-- Linke Spalte: Projektinfo -->
<div class="col-lg-4">
<!-- Projekt-Übersicht -->
<div class="card mb-4">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-info-circle me-2"></i>Projekt-Übersicht
</h5>
</div>
<div class="card-body">
{% if project.language %}
<div class="mb-2">
<strong>Sprache:</strong>
<span class="badge bg-primary">{{ project.language }}</span>
</div>
{% endif %}
{% if project.category %}
<div class="mb-2">
<strong>Kategorie:</strong>
<span class="badge bg-info">{{ project.category }}</span>
</div>
{% endif %}
{% if project.tags %}
<div class="mb-2">
<strong>Tags:</strong><br>
{% for tag in project.tags %}
<span class="badge bg-secondary me-1">{{ tag }}</span>
{% endfor %}
</div>
{% endif %}
{% if project.requirements %}
<div class="mb-2">
<strong>Anforderungen:</strong>
<ul class="small mt-1 mb-0">
{% if project.requirements.min_memory %}
<li>RAM: {{ project.requirements.min_memory }}</li>
{% endif %}
{% if project.requirements.min_disk %}
<li>Speicher: {{ project.requirements.min_disk }}</li>
{% endif %}
{% if project.requirements.ports %}
<li>Ports: {{ project.requirements.ports|join(', ') }}</li>
{% endif %}
</ul>
</div>
{% endif %}
</div>
</div>
<!-- Empfohlene Installation -->
{% if preferred_method %}
<div class="card mb-4">
<div class="card-header bg-success text-white">
<h5 class="card-title mb-0">
<i class="fas fa-star me-2"></i>Empfohlene Installation
</h5>
</div>
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<div>
<strong>{{ preferred_method[0]|title }}</strong>
<p class="text-muted small mb-0">{{ preferred_method[1].description }}</p>
</div>
<div>
{% if preferred_method[0] in ['image', 'docker_registry', 'docker_url', 'docker_file'] %}
<i class="fab fa-docker fa-2x text-primary"></i>
{% elif preferred_method[0] in ['docker_build', 'dockerfile'] %}
<i class="fas fa-cog fa-2x text-secondary"></i>
{% else %}
<i class="fab fa-git-alt fa-2x text-success"></i>
{% endif %}
</div>
</div>
<button class="btn btn-success w-100"
onclick="installProject('{{ preferred_method[1].url }}', '{{ project.name }}', '{{ preferred_method[0] }}')">
<i class="fas fa-download me-2"></i>Jetzt installieren
</button>
</div>
</div>
{% endif %}
<!-- Schnellinfo -->
{% if project.metadata %}
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-chart-line me-2"></i>Projekt-Info
</h5>
</div>
<div class="card-body">
{% if project.metadata.author %}
<div class="d-flex justify-content-between mb-2">
<span>Autor:</span>
<span>{{ project.metadata.author }}</span>
</div>
{% endif %}
{% if project.metadata.version %}
<div class="d-flex justify-content-between mb-2">
<span>Version:</span>
<span class="badge bg-primary">{{ project.metadata.version }}</span>
</div>
{% endif %}
{% if project.metadata.last_updated %}
<div class="d-flex justify-content-between mb-2">
<span>Letzte Aktualisierung:</span>
<span>{{ project.metadata.last_updated }}</span>
</div>
{% endif %}
{% if project.metadata.downloads %}
<div class="d-flex justify-content-between mb-2">
<span>Downloads:</span>
<span class="badge bg-info">{{ project.metadata.downloads }}</span>
</div>
{% endif %}
{% if project.metadata.stars %}
<div class="d-flex justify-content-between mb-2">
<span>Stars:</span>
<span class="badge bg-warning">{{ project.metadata.stars }}</span>
</div>
{% endif %}
</div>
</div>
{% endif %}
</div>
<!-- Rechte Spalte: Installationsmethoden -->
<div class="col-lg-8">
<div class="card">
<div class="card-header">
<h5 class="card-title mb-0">
<i class="fas fa-tools me-2"></i>Verfügbare Installationsmethoden
</h5>
</div>
<div class="card-body">
{% if available_methods %}
<div class="row">
{% for method_type, method_info in available_methods %}
<div class="col-md-6 mb-4">
<div class="card h-100 {% if preferred_method and method_type == preferred_method[0] %}border-success{% endif %}">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="d-flex align-items-center">
{% if method_type == 'image' %}
<i class="fab fa-docker fa-lg text-primary me-2"></i>
<strong>Docker Image</strong>
{% elif method_type == 'docker_registry' %}
<i class="fab fa-docker fa-lg text-info me-2"></i>
<strong>Docker Registry</strong>
{% elif method_type == 'docker_url' %}
<i class="fas fa-cloud-download-alt fa-lg text-warning me-2"></i>
<strong>Docker URL</strong>
{% elif method_type == 'docker_file' %}
<i class="fas fa-file-archive fa-lg text-warning me-2"></i>
<strong>Docker File</strong>
{% elif method_type == 'docker_build' or method_type == 'dockerfile' %}
<i class="fas fa-cog fa-lg text-secondary me-2"></i>
<strong>Docker Build</strong>
{% elif method_type == 'clone' %}
<i class="fab fa-git-alt fa-lg text-success me-2"></i>
<strong>Git Clone</strong>
{% elif method_type == 'native_python' %}
<i class="fab fa-python fa-lg text-success me-2"></i>
<strong>Python Native</strong>
{% elif method_type == 'native_nodejs' %}
<i class="fab fa-node-js fa-lg text-success me-2"></i>
<strong>Node.js Native</strong>
{% elif method_type == 'native_batch' %}
<i class="fas fa-terminal fa-lg text-info me-2"></i>
<strong>Windows Batch</strong>
{% elif method_type == 'native_shell' %}
<i class="fas fa-terminal fa-lg text-success me-2"></i>
<strong>Linux/macOS Shell</strong>
{% else %}
<i class="fas fa-download fa-lg me-2"></i>
<strong>{{ method_type|title }}</strong>
{% endif %}
</div>
{% if preferred_method and method_type == preferred_method[0] %}
<span class="badge bg-success">Empfohlen</span>
{% endif %}
</div>
<div class="card-body d-flex flex-column">
<p class="text-muted mb-3">{{ method_info.description }}</p>
<!-- Zusätzliche Infos je nach Typ -->
{% if method_type in ['image', 'docker_registry', 'docker_url', 'docker_file'] %}
<div class="mb-3">
<small class="text-info">
<i class="fas fa-info-circle me-1"></i>
Fertige Container-Installation - Schnell und einfach
</small>
</div>
{% elif method_type in ['docker_build', 'dockerfile'] %}
<div class="mb-3">
<small class="text-warning">
<i class="fas fa-clock me-1"></i>
Erstellt Container aus Quellcode - Dauert länger
</small>
</div>
{% elif method_type == 'clone' %}
<div class="mb-3">
<small class="text-success">
<i class="fas fa-code me-1"></i>
Vollständiger Quellcode - Maximale Kontrolle
</small>
</div>
{% elif method_type.startswith('native_') %}
<div class="mb-3">
<small class="text-primary">
<i class="fas fa-desktop me-1"></i>
Native Ausführung - Ohne Container
</small>
</div>
{% endif %}
{% if method_info.url %}
<div class="mb-3">
<small class="text-muted">
<strong>URL:</strong>
<code class="small">{{ method_info.url|truncate(50) }}</code>
</small>
</div>
{% endif %}
<div class="mt-auto">
<button class="btn {% if preferred_method and method_type == preferred_method[0] %}btn-success{% else %}btn-outline-primary{% endif %} w-100"
onclick="installProject('{{ method_info.url }}', '{{ project.name }}', '{{ method_type }}')">
<i class="fas fa-download me-2"></i>
{% if preferred_method and method_type == preferred_method[0] %}
Empfohlene Installation
{% else %}
Mit dieser Methode installieren
{% endif %}
</button>
</div>
</div>
</div>
</div>
{% endfor %}
</div>
{% else %}
<div class="text-center py-4">
<i class="fas fa-exclamation-triangle fa-3x text-warning mb-3"></i>
<h5 class="text-muted">Keine Installationsmethoden verfügbar</h5>
<p class="text-muted">Für dieses Projekt sind keine Installationsmethoden konfiguriert.</p>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- Progress Modal -->
<div class="modal fade" id="installProgressModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
<i class="fas fa-download me-2"></i>Installation läuft...
</h5>
</div>
<div class="modal-body">
<div class="text-center">
<div class="spinner-border text-primary mb-3" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<h5 id="installStatus">{{ project.name }} wird installiert...</h5>
<p class="text-muted mb-0" id="installMethod">Bitte warten Sie einen Moment.</p>
</div>
<div class="progress mt-3">
<div class="progress-bar progress-bar-striped progress-bar-animated"
role="progressbar" style="width: 100%"></div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
// Installation mit Progress Modal
function installProject(url, name, method) {
const button = event.target;
const originalText = button.innerHTML;
// Show progress modal
const modal = new bootstrap.Modal(document.getElementById('installProgressModal'));
document.getElementById('installStatus').textContent = `${name} wird installiert...`;
document.getElementById('installMethod').textContent = `Methode: ${method}`;
modal.show();
// Disable all install buttons
document.querySelectorAll('.btn').forEach(btn => {
if (btn.textContent.includes('installieren')) {
btn.disabled = true;
}
});
console.log(`🚀 Installiere ${name} via ${method} von ${url}`);
fetch('/install_project', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: `project_url=${encodeURIComponent(url)}&project_name=${encodeURIComponent(name)}&installation_method=${encodeURIComponent(method)}`
})
.then(response => response.json())
.then(data => {
modal.hide();
if (data.success) {
// Success notification
showAlert('success', `${name} wurde erfolgreich installiert!`);
// Redirect to project details or dashboard after 2 seconds
setTimeout(() => {
window.location.href = '/project_details/' + encodeURIComponent(name);
}, 2000);
} else {
showAlert('danger', `Installation fehlgeschlagen: ${data.message}`);
// Re-enable buttons
document.querySelectorAll('.btn').forEach(btn => {
if (btn.textContent.includes('installieren')) {
btn.disabled = false;
}
});
}
})
.catch(error => {
modal.hide();
showAlert('danger', `Netzwerkfehler bei Installation von ${name}: ${error}`);
// Re-enable buttons
document.querySelectorAll('.btn').forEach(btn => {
if (btn.textContent.includes('installieren')) {
btn.disabled = false;
}
});
});
}
function showAlert(type, message) {
const alertHtml = `
<div class="alert alert-${type} alert-dismissible fade show" role="alert">
<i class="fas fa-${type === 'success' ? 'check-circle' : 'exclamation-triangle'} me-2"></i>
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
`;
// Insert alert at top of page
const container = document.querySelector('.container-fluid');
container.insertAdjacentHTML('afterbegin', alertHtml);
// Auto-remove after 5 seconds
setTimeout(() => {
const alert = container.querySelector('.alert');
if (alert) {
alert.remove();
}
}, 5000);
}
</script>
{% endblock %}