130 lines
8.2 KiB
Plaintext
130 lines
8.2 KiB
Plaintext
<!DOCTYPE html>
|
||
<html lang="nl">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||
<title>Backup & Herstel — Mek-Tech</title>
|
||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700;800&display=swap" rel="stylesheet">
|
||
<link rel="stylesheet" href="/css/style.css">
|
||
<link rel="stylesheet" href="/css/neon.css">
|
||
<link rel="stylesheet" href="/css/dynamic.css">
|
||
<script src="https://unpkg.com/lucide@latest"></script>
|
||
<style>
|
||
.bk-wrap{max-width:900px;margin:2rem auto;padding:0 1.5rem 3rem}
|
||
.bk-wrap h1{font-size:1.4rem;font-weight:800;margin:0 0 .2rem;display:flex;align-items:center;gap:.45rem}
|
||
.bk-wrap .sub{color:var(--text-muted);font-size:.78rem;margin-bottom:1.25rem}
|
||
.section{background:var(--bg-card);border:1px solid var(--border);border-radius:10px;padding:1.1rem 1.2rem;margin-bottom:1rem}
|
||
.section h2{font-size:.72rem;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--text-muted);margin:0 0 .75rem;display:flex;align-items:center;gap:.35rem}
|
||
.stat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:.45rem;margin-bottom:.5rem}
|
||
.stat-card{background:var(--bg);border:1px solid var(--border-light);border-radius:8px;padding:.55rem .65rem;text-align:center}
|
||
.stat-card .num{font-size:1.25rem;font-weight:800;color:var(--accent)}
|
||
.stat-card .lbl{font-size:.58rem;color:var(--text-muted);text-transform:uppercase;margin-top:.1rem}
|
||
.bk-actions{display:flex;gap:.45rem;flex-wrap:wrap;margin-top:.75rem}
|
||
.bk-table{width:100%;border-collapse:collapse;font-size:.75rem}
|
||
.bk-table th{text-align:left;padding:.45rem .5rem;font-size:.62rem;color:var(--text-muted);text-transform:uppercase;border-bottom:1px solid var(--border)}
|
||
.bk-table td{padding:.45rem .5rem;border-bottom:1px solid var(--border-light)}
|
||
.bk-table tr:hover td{background:var(--border-light)}
|
||
.alert{background:var(--green-bg);border:1px solid var(--green);color:var(--green);padding:.55rem .75rem;border-radius:8px;font-size:.76rem;margin-bottom:1rem}
|
||
.alert-warn{background:var(--orange-bg);border-color:var(--orange);color:var(--orange)}
|
||
.alert-err{background:var(--red-bg);border-color:var(--red);color:var(--red)}
|
||
.restore-box{border:1px dashed var(--border);border-radius:8px;padding:1rem;margin-top:.5rem}
|
||
.restore-box p{font-size:.72rem;color:var(--text-muted);margin:0 0 .65rem;line-height:1.45}
|
||
.restore-box input[type=file]{font-size:.72rem;margin-bottom:.5rem;width:100%}
|
||
.info-list{font-size:.72rem;color:var(--text-muted);margin:.35rem 0 0;padding-left:1.1rem;line-height:1.5}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<nav class="navbar"><div class="nav-inner">
|
||
<a href="/" class="nav-brand"><img src="/img/logo.svg" class="nav-logo" alt="Mek-Tech"></a>
|
||
<div style="display:flex;gap:.4rem;align-items:center">
|
||
<a href="/settings" class="nav-icon-btn"><i data-lucide="settings" style="width:15px;height:15px"></i> Instellingen</a>
|
||
<a href="/" class="nav-icon-btn"><i data-lucide="layout-dashboard" style="width:15px;height:15px"></i></a>
|
||
<a href="/auth/logout" class="nav-icon-btn" style="color:var(--red)"><i data-lucide="log-out" style="width:15px;height:15px"></i></a>
|
||
</div></div></nav>
|
||
|
||
<div class="bk-wrap">
|
||
<a href="/settings" class="back-link"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="15 18 9 12 15 6"/></svg> Terug naar instellingen</a>
|
||
<h1><i data-lucide="database-backup" style="width:22px;height:22px;color:var(--accent)"></i> Backup & Herstel</h1>
|
||
<p class="sub">Volledige backup van database, sessies, uploads en alle cliëntdata.</p>
|
||
|
||
<% if (created) { %><div class="alert"><i data-lucide="check-circle" style="width:14px;height:14px"></i> Backup succesvol aangemaakt op de server.</div><% } %>
|
||
<% if (restored) { %><div class="alert"><i data-lucide="check-circle" style="width:14px;height:14px"></i> Herstel voltooid. Vernieuw het dashboard — bij problemen herstart de container.</div><% } %>
|
||
<% if (deleted) { %><div class="alert">Backup verwijderd.</div><% } %>
|
||
<% if (error) { %><div class="alert alert-err"><%= error %></div><% } %>
|
||
|
||
<div class="section">
|
||
<h2><i data-lucide="bar-chart-2" style="width:14px;height:14px"></i> Huidige data</h2>
|
||
<div class="stat-grid">
|
||
<div class="stat-card"><div class="num"><%= stats.counts.clients || 0 %></div><div class="lbl">Cliënten</div></div>
|
||
<div class="stat-card"><div class="num"><%= stats.counts.engagements || 0 %></div><div class="lbl">Engagements</div></div>
|
||
<div class="stat-card"><div class="num"><%= stats.counts.racks || 0 %></div><div class="lbl">Racks</div></div>
|
||
<div class="stat-card"><div class="num"><%= stats.counts.data_diagrams || 0 %></div><div class="lbl">Diagrammen</div></div>
|
||
<div class="stat-card"><div class="num"><%= stats.counts.projects || 0 %></div><div class="lbl">Projecten</div></div>
|
||
<div class="stat-card"><div class="num"><%= stats.counts.invoices || 0 %></div><div class="lbl">Facturen</div></div>
|
||
</div>
|
||
<p style="font-size:.68rem;color:var(--text-dim);margin:0">
|
||
Database: <%= formatBytes(stats.dbSizeBytes) %>
|
||
<% if (stats.uploadFiles) { %> · Uploads: <%= stats.uploadFiles %> bestanden (<%= formatBytes(stats.uploadsBytes) %>)<% } %>
|
||
<% if (diskFree) { %> · Schijf vrij: <%= diskFree %><% } %>
|
||
</p>
|
||
</div>
|
||
|
||
<div class="section">
|
||
<h2><i data-lucide="download" style="width:14px;height:14px"></i> Nieuwe backup maken</h2>
|
||
<p style="font-size:.74rem;color:var(--text-muted);margin:0 0 .5rem">Maakt een .tar.gz archief met:</p>
|
||
<ul class="info-list">
|
||
<li><strong>consulting.db</strong> — alle cliënten, racks, diagrammen, facturen, instellingen</li>
|
||
<li><strong>sessions.db</strong> — actieve sessies</li>
|
||
<li><strong>uploads/</strong> — geüploade data quality bestanden</li>
|
||
</ul>
|
||
<div class="bk-actions">
|
||
<form method="POST" action="/backup/create?download=1" style="display:inline"><button type="submit" class="btn btn-accent btn-small"><i data-lucide="download" style="width:14px;height:14px"></i> Backup maken & downloaden</button></form>
|
||
<form method="POST" action="/backup/create" style="display:inline"><button type="submit" class="btn btn-secondary btn-small"><i data-lucide="save" style="width:14px;height:14px"></i> Opslaan op server</button></form>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section">
|
||
<h2><i data-lucide="archive" style="width:14px;height:14px"></i> Backups op server (<%= backups.length %>)</h2>
|
||
<% if (backups.length === 0) { %>
|
||
<p style="font-size:.74rem;color:var(--text-muted)">Nog geen backups opgeslagen op de server.</p>
|
||
<% } else { %>
|
||
<table class="bk-table">
|
||
<thead><tr><th>Bestand</th><th>Grootte</th><th>Datum</th><th></th></tr></thead>
|
||
<tbody>
|
||
<% backups.forEach(function(b) { %>
|
||
<tr>
|
||
<td><strong><%= b.filename %></strong></td>
|
||
<td><%= b.sizeLabel %></td>
|
||
<td><%= new Date(b.created_at).toLocaleString('nl-NL') %></td>
|
||
<td style="white-space:nowrap">
|
||
<a href="/backup/download/<%= b.filename %>" class="btn btn-secondary btn-small">Download</a>
|
||
<form method="POST" action="/backup/restore/<%= b.filename %>" style="display:inline" onsubmit="return confirm('WAARSCHUWING: Alle huidige data wordt overschreven. Er wordt eerst automatisch een veiligheidsbackup gemaakt. Doorgaan?')">
|
||
<button type="submit" class="btn btn-secondary btn-small">Herstellen</button>
|
||
</form>
|
||
<form method="POST" action="/backup/delete/<%= b.filename %>" style="display:inline" onsubmit="return confirm('Backup verwijderen?')">
|
||
<button type="submit" class="btn btn-secondary btn-small" style="color:var(--red)">×</button>
|
||
</form>
|
||
</td>
|
||
</tr>
|
||
<% }) %>
|
||
</tbody>
|
||
</table>
|
||
<% } %>
|
||
</div>
|
||
|
||
<div class="section">
|
||
<h2><i data-lucide="upload" style="width:14px;height:14px"></i> Herstellen vanaf bestand</h2>
|
||
<div class="restore-box">
|
||
<p><strong>Let op:</strong> Herstellen overschrijft alle huidige data. Vóór herstel wordt automatisch een veiligheidsbackup gemaakt op de server.</p>
|
||
<form method="POST" action="/backup/restore" enctype="multipart/form-data" onsubmit="return confirm('Weet je zeker dat je wilt herstellen? Huidige data wordt overschreven.')">
|
||
<input type="file" name="backup_file" accept=".tar.gz,.tgz,application/gzip" required>
|
||
<button type="submit" class="btn btn-accent btn-small"><i data-lucide="upload" style="width:14px;height:14px"></i> Backup uploaden & herstellen</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script>lucide.createIcons();</script>
|
||
<script src="/js/theme.js"></script>
|
||
</body>
|
||
</html>
|