Files
GuacPanel/webgui/templates/updates.html
T
njomac 50c125e0db Initial commit — GuacPanel v1.0
All-in-one installer za Apache Guacamole s Nginx reverse proxy,
fail2ban, SSL (Let's Encrypt / Self-signed), GeoIP blokiranjem
i Flask web GUI za upravljanje.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-26 11:21:44 +02:00

208 lines
6.7 KiB
HTML

{% extends 'base.html' %}
{% block title %}Ažuriranja{% endblock %}
{% block content %}
<h4 class="mb-4"><i class="bi bi-arrow-up-circle me-2"></i>Ažuriranja</h4>
<!-- Trenutne verzije -->
<div class="card mb-4">
<div class="card-header fw-semibold"><i class="bi bi-info-circle me-1"></i> Trenutne verzije</div>
<div class="card-body">
<div class="row g-3">
{% for name, ver in versions.items() %}
<div class="col-md-4">
<div class="p-3 rounded" style="background:#0d1117; border:1px solid #30363d">
<div class="small text-muted text-uppercase mb-1">{{ name }}</div>
<div class="fw-semibold font-monospace">{{ ver }}</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Akcije ažuriranja -->
<div class="row g-4">
<!-- Guacamole -->
<div class="col-md-6">
<div class="card h-100">
<div class="card-header fw-semibold">
<i class="bi bi-display me-1"></i> Guacamole
</div>
<div class="card-body">
<p class="text-muted small">
Preuzima najnovije Docker image-e za Guacamole, guacd i PostgreSQL
te restarta kontejnere. Konfiguracija i podaci se čuvaju.
</p>
<button class="btn btn-primary" onclick="startUpdate('guacamole', this)">
<i class="bi bi-cloud-download"></i> Ažuriraj Guacamole
</button>
</div>
</div>
</div>
<!-- Nginx -->
<div class="col-md-6">
<div class="card h-100">
<div class="card-header fw-semibold">
<i class="bi bi-server me-1"></i> Nginx
</div>
<div class="card-body">
<p class="text-muted small">
Ažurira nginx paket putem sistemskog package managera
({{ pkg }}) i automatski reloada konfiguraciju.
</p>
<button class="btn btn-primary" onclick="startUpdate('nginx', this)">
<i class="bi bi-arrow-up-circle"></i> Ažuriraj Nginx
</button>
</div>
</div>
</div>
<!-- fail2ban -->
<div class="col-md-6">
<div class="card h-100">
<div class="card-header fw-semibold">
<i class="bi bi-shield me-1"></i> fail2ban
</div>
<div class="card-body">
<p class="text-muted small">
Ažurira fail2ban paket i restarta servis.
Jail konfiguracije ostaju netaknute.
</p>
<button class="btn btn-primary" onclick="updateFail2ban(this)">
<i class="bi bi-arrow-up-circle"></i> Ažuriraj fail2ban
</button>
</div>
</div>
</div>
<!-- Sistem -->
<div class="col-md-6">
<div class="card h-100">
<div class="card-header fw-semibold">
<i class="bi bi-hdd me-1"></i> Sistemske nadogradnje
</div>
<div class="card-body">
<p class="text-muted small">
Ažurira sve instalirane sistemske pakete putem <code>{{ pkg }}</code>.
Može potrajati nekoliko minuta.
</p>
<div class="alert alert-warning py-2 small mb-3">
<i class="bi bi-exclamation-triangle me-1"></i>
Nakon sistemske nadogradnje može biti potreban restart servera.
</div>
<button class="btn btn-warning" onclick="startUpdate('system', this)">
<i class="bi bi-hdd-rack"></i> Ažuriraj sistem
</button>
</div>
</div>
</div>
</div>
<!-- Output konzola -->
<div id="output-panel" class="card mt-4 d-none">
<div class="card-header d-flex justify-content-between align-items-center">
<span class="fw-semibold">
<i class="bi bi-terminal me-1"></i>
Output: <span id="output-title"></span>
</span>
<div>
<span id="output-status" class="badge bg-warning me-2">U tijeku...</span>
<button class="btn btn-sm btn-outline-secondary" onclick="clearOutput()">
<i class="bi bi-trash"></i>
</button>
</div>
</div>
<div id="log-output"></div>
</div>
{% endblock %}
{% block scripts %}
<script>
let activeSource = null;
function startUpdate(type, btn) {
const titles = {
guacamole: 'Guacamole',
nginx: 'Nginx',
system: 'Sistemske nadogradnje'
};
if (activeSource) {
activeSource.close();
activeSource = null;
}
document.getElementById('output-panel').classList.remove('d-none');
document.getElementById('output-title').textContent = titles[type] || type;
document.getElementById('output-status').textContent = 'U tijeku...';
document.getElementById('output-status').className = 'badge bg-warning me-2';
const out = document.getElementById('log-output');
out.innerHTML = '';
const origHtml = btn.innerHTML;
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Ažuriranje...';
activeSource = new EventSource(`/api/update/${type}`);
activeSource.onmessage = e => {
const data = JSON.parse(e.data);
if (data === '__DONE__') {
activeSource.close();
activeSource = null;
btn.disabled = false;
btn.innerHTML = origHtml;
document.getElementById('output-status').textContent = 'Završeno';
document.getElementById('output-status').className = 'badge bg-success me-2';
return;
}
const line = document.createElement('div');
line.textContent = data;
if (data.startsWith('✓')) line.style.color = '#3fb950';
out.appendChild(line);
out.scrollTop = out.scrollHeight;
};
activeSource.onerror = () => {
activeSource.close();
activeSource = null;
btn.disabled = false;
btn.innerHTML = origHtml;
document.getElementById('output-status').textContent = 'Greška';
document.getElementById('output-status').className = 'badge bg-danger me-2';
};
}
async function updateFail2ban(btn) {
const orig = btn.innerHTML;
btn.disabled = true;
btn.innerHTML = '<span class="spinner-border spinner-border-sm"></span> Ažuriranje...';
document.getElementById('output-panel').classList.remove('d-none');
document.getElementById('output-title').textContent = 'fail2ban';
document.getElementById('output-status').textContent = 'U tijeku...';
document.getElementById('output-status').className = 'badge bg-warning me-2';
const r = await api('/api/update/fail2ban');
const out = document.getElementById('log-output');
out.innerHTML = '';
const line = document.createElement('div');
line.textContent = r.msg;
out.appendChild(line);
btn.disabled = false;
btn.innerHTML = orig;
document.getElementById('output-status').textContent = r.ok ? 'Završeno' : 'Greška';
document.getElementById('output-status').className = `badge ${r.ok ? 'bg-success' : 'bg-danger'} me-2`;
showToast(r.ok ? 'fail2ban ažuriran' : r.msg, r.ok);
}
function clearOutput() {
document.getElementById('log-output').innerHTML = '';
document.getElementById('output-panel').classList.add('d-none');
}
</script>
{% endblock %}