feat: add scheduled daily backup, stored backup listing and download
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -126,6 +126,30 @@
|
||||
<tbody id="bodyUsers"></tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Daftar Backup Terjadwal -->
|
||||
<div class="bg-white rounded-2xl shadow-sm border border-base-200 mt-8">
|
||||
<div class="p-4 border-b border-base-200 flex items-center justify-between">
|
||||
<h2 class="font-bold text-base flex items-center gap-2">
|
||||
<i class="fa-solid fa-clock-rotate-left text-success"></i> Backup Tersimpan
|
||||
</h2>
|
||||
<button onclick="loadBackupList()" class="btn btn-xs btn-ghost">
|
||||
<i class="fa-solid fa-rotate-right"></i> Refresh
|
||||
</button>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table table-sm w-full">
|
||||
<thead>
|
||||
<tr class="text-xs uppercase opacity-50">
|
||||
<th>File</th><th>Ukuran</th><th>Waktu</th><th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="bodyBackupList">
|
||||
<tr><td colspan="4" class="text-center py-6 opacity-30 italic">Memuat...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- ═══ MODALS ═══════════════════════════════════════════════════════════ -->
|
||||
@@ -259,7 +283,24 @@
|
||||
return String(s).replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c]));
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', loadUsers);
|
||||
document.addEventListener('DOMContentLoaded', () => { loadUsers(); loadBackupList(); });
|
||||
|
||||
async function loadBackupList() {
|
||||
try {
|
||||
const res = await fetch('{{ url('/api/admin/backup/list') }}', { headers: { 'X-CSRF-TOKEN': csrfToken } });
|
||||
const list = await res.json();
|
||||
document.getElementById('bodyBackupList').innerHTML = list.length
|
||||
? list.map(b => `<tr>
|
||||
<td class="font-mono text-xs">${esc(b.name)}</td>
|
||||
<td class="text-xs opacity-60">${esc(String(b.size_kb))} KB</td>
|
||||
<td class="text-xs opacity-60">${esc(b.created_at)}</td>
|
||||
<td><a href="{{ url('/api/admin/backup/download') }}/${esc(b.name)}" class="btn btn-xs btn-ghost" title="Unduh"><i class="fa-solid fa-download"></i></a></td>
|
||||
</tr>`).join('')
|
||||
: '<tr><td colspan="4" class="text-center py-6 opacity-30 italic">Belum ada backup tersimpan</td></tr>';
|
||||
} catch (e) {
|
||||
showToast('Gagal memuat daftar backup', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async function loadUsers() {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user