mirror of
https://github.com/StarFleetCPTN/GoMFT.git
synced 2026-09-08 23:50:48 +02:00
feat: Add admin database template component
This commit is contained in:
committed by
StarFleetCPTN (aider)
parent
faef3c2df9
commit
aa2149e2cf
@@ -0,0 +1,342 @@
|
|||||||
|
package components
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// BackupFile represents a database backup file
|
||||||
|
type BackupFile struct {
|
||||||
|
Name string
|
||||||
|
Size string
|
||||||
|
Created time.Time
|
||||||
|
FullPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdminDatabaseTools renders the database tools page with backup and restore functionality
|
||||||
|
templ AdminDatabaseTools(ctx context.Context, backups []BackupFile) {
|
||||||
|
@LayoutWithContext("Database Tools", ctx) {
|
||||||
|
<div class="flex flex-col md:flex-row bg-gray-50 dark:bg-gray-900 min-h-screen">
|
||||||
|
<!-- Sidebar Navigation -->
|
||||||
|
<nav class="md:w-64 md:min-h-screen bg-white border-r border-gray-200 dark:bg-gray-800 dark:border-gray-700">
|
||||||
|
<div class="p-4 overflow-y-auto">
|
||||||
|
<h2 class="text-lg font-semibold text-gray-900 dark:text-white mb-4">Admin Console</h2>
|
||||||
|
<ul class="space-y-2">
|
||||||
|
<li>
|
||||||
|
<a href="/admin" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||||
|
<i class="fas fa-tachometer-alt w-5 h-5 text-gray-500 dark:text-gray-400 mr-3"></i>
|
||||||
|
Dashboard
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/admin/users" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||||
|
<i class="fas fa-users w-5 h-5 text-gray-500 dark:text-gray-400 mr-3"></i>
|
||||||
|
User Management
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/admin/roles" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||||
|
<i class="fas fa-user-shield w-5 h-5 text-gray-500 dark:text-gray-400 mr-3"></i>
|
||||||
|
Role Management
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/admin/audit" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||||
|
<i class="fas fa-clipboard-list w-5 h-5 text-gray-500 dark:text-gray-400 mr-3"></i>
|
||||||
|
Audit Logs
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/admin/database" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white bg-gray-100 dark:bg-gray-700 group">
|
||||||
|
<i class="fas fa-database w-5 h-5 text-gray-500 dark:text-gray-400 mr-3"></i>
|
||||||
|
Database Tools
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/admin/settings" class="flex items-center p-2 text-gray-900 rounded-lg dark:text-white hover:bg-gray-100 dark:hover:bg-gray-700 group">
|
||||||
|
<i class="fas fa-cog w-5 h-5 text-gray-500 dark:text-gray-400 mr-3"></i>
|
||||||
|
System Settings
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- Main Content -->
|
||||||
|
<div class="flex-1 p-8">
|
||||||
|
<!-- Header -->
|
||||||
|
<div class="mb-6">
|
||||||
|
<h1 class="text-2xl font-bold text-gray-900 dark:text-white flex items-center">
|
||||||
|
<i class="fas fa-database w-6 h-6 mr-2 text-blue-500 dark:text-blue-400"></i>
|
||||||
|
Database Management
|
||||||
|
</h1>
|
||||||
|
<p class="mt-2 text-gray-600 dark:text-gray-400">Manage database backups, restoration and maintenance</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Database Actions Cards -->
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-8">
|
||||||
|
<!-- Backup Database Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg shadow-sm dark:bg-gray-800">
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<div class="bg-blue-100 p-3 rounded-full dark:bg-blue-900 mr-4">
|
||||||
|
<i class="fas fa-save text-blue-500 w-6 h-6 dark:text-blue-300"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Backup Database</h3>
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 mb-4">Create a backup of the current database state.</p>
|
||||||
|
<form method="POST" action="/admin/backup-database">
|
||||||
|
<button type="submit" class="w-full px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-blue-700 dark:hover:bg-blue-800">
|
||||||
|
<i class="fas fa-download mr-2"></i>
|
||||||
|
Create Backup
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Vacuum Database Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg shadow-sm dark:bg-gray-800">
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<div class="bg-purple-100 p-3 rounded-full dark:bg-purple-900 mr-4">
|
||||||
|
<i class="fas fa-broom text-purple-500 w-6 h-6 dark:text-purple-300"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Optimize Database</h3>
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 mb-4">Vacuum the database to reclaim space and optimize performance.</p>
|
||||||
|
<form method="POST" action="/admin/vacuum-database">
|
||||||
|
<button type="submit" class="w-full px-4 py-2 bg-purple-600 text-white rounded-lg hover:bg-purple-700 focus:outline-none focus:ring-2 focus:ring-purple-500 dark:bg-purple-700 dark:hover:bg-purple-800">
|
||||||
|
<i class="fas fa-magic mr-2"></i>
|
||||||
|
Optimize Database
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Clear Job History Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg shadow-sm dark:bg-gray-800">
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<div class="bg-orange-100 p-3 rounded-full dark:bg-orange-900 mr-4">
|
||||||
|
<i class="fas fa-eraser text-orange-500 w-6 h-6 dark:text-orange-300"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Clear Job History</h3>
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 mb-4">Remove old job history records to free up database space.</p>
|
||||||
|
<form method="POST" action="/admin/clear-job-history">
|
||||||
|
<button type="submit" class="w-full px-4 py-2 bg-orange-600 text-white rounded-lg hover:bg-orange-700 focus:outline-none focus:ring-2 focus:ring-orange-500 dark:bg-orange-700 dark:hover:bg-orange-800">
|
||||||
|
<i class="fas fa-trash-alt mr-2"></i>
|
||||||
|
Clear Job History
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Export Configuration Card -->
|
||||||
|
<div class="bg-white p-6 rounded-lg shadow-sm dark:bg-gray-800">
|
||||||
|
<div class="flex items-center mb-4">
|
||||||
|
<div class="bg-green-100 p-3 rounded-full dark:bg-green-900 mr-4">
|
||||||
|
<i class="fas fa-file-export text-green-500 w-6 h-6 dark:text-green-300"></i>
|
||||||
|
</div>
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Export Configuration</h3>
|
||||||
|
</div>
|
||||||
|
<p class="text-gray-600 dark:text-gray-400 mb-4">Export system configurations and jobs for backup or migration.</p>
|
||||||
|
<div class="flex space-x-2">
|
||||||
|
<a href="/admin/export-configs" class="flex-1 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 dark:bg-green-700 dark:hover:bg-green-800 text-center">
|
||||||
|
<i class="fas fa-cogs mr-2"></i>
|
||||||
|
Export Configs
|
||||||
|
</a>
|
||||||
|
<a href="/admin/export-jobs" class="flex-1 px-4 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 dark:bg-green-700 dark:hover:bg-green-800 text-center">
|
||||||
|
<i class="fas fa-tasks mr-2"></i>
|
||||||
|
Export Jobs
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Database Backup List -->
|
||||||
|
<div class="bg-white rounded-lg shadow-sm dark:bg-gray-800 mt-8">
|
||||||
|
<div class="p-6 border-b border-gray-200 dark:border-gray-700 flex justify-between items-center">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Database Backups</h3>
|
||||||
|
<a href="/admin/refresh-backups" class="text-blue-600 hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300">
|
||||||
|
<i class="fas fa-sync-alt mr-1"></i>
|
||||||
|
Refresh
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="w-full">
|
||||||
|
<thead class="bg-gray-50 dark:bg-gray-700">
|
||||||
|
<tr>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase">Backup Name</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase">Size</th>
|
||||||
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase">Created</th>
|
||||||
|
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 dark:text-gray-300 uppercase">Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
|
if len(backups) == 0 {
|
||||||
|
<tr>
|
||||||
|
<td colspan="4" class="px-6 py-4 text-center text-gray-500 dark:text-gray-400">
|
||||||
|
No backups found. Create your first backup to get started.
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
} else {
|
||||||
|
for _, backup := range backups {
|
||||||
|
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
|
||||||
|
<td class="px-6 py-4 text-sm text-gray-900 dark:text-white">{ backup.Name }</td>
|
||||||
|
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">{ backup.Size }</td>
|
||||||
|
<td class="px-6 py-4 text-sm text-gray-500 dark:text-gray-400">{ backup.Created.Format("2006-01-02 15:04:05") }</td>
|
||||||
|
<td class="px-6 py-4 text-sm text-right">
|
||||||
|
<div class="flex items-center justify-end space-x-2">
|
||||||
|
<!-- Restore Button -->
|
||||||
|
<button type="button"
|
||||||
|
data-modal-target="confirm-restore-modal"
|
||||||
|
data-modal-toggle="confirm-restore-modal"
|
||||||
|
data-backup-name={ backup.Name }
|
||||||
|
class="text-green-600 hover:text-green-900 dark:text-green-400 dark:hover:text-green-300">
|
||||||
|
<i class="fas fa-undo-alt"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Download Button -->
|
||||||
|
<a href={ templ.SafeURL("/admin/download-backup/" + backup.Name) }
|
||||||
|
class="text-blue-600 hover:text-blue-900 dark:text-blue-400 dark:hover:text-blue-300">
|
||||||
|
<i class="fas fa-download"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Delete Button -->
|
||||||
|
<button type="button"
|
||||||
|
data-modal-target="confirm-delete-modal"
|
||||||
|
data-modal-toggle="confirm-delete-modal"
|
||||||
|
data-backup-name={ backup.Name }
|
||||||
|
class="text-red-600 hover:text-red-900 dark:text-red-400 dark:hover:text-red-300">
|
||||||
|
<i class="fas fa-trash"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Upload Backup File -->
|
||||||
|
<div class="bg-white rounded-lg shadow-sm dark:bg-gray-800 mt-8">
|
||||||
|
<div class="p-6 border-b border-gray-200 dark:border-gray-700">
|
||||||
|
<h3 class="text-lg font-semibold text-gray-900 dark:text-white">Restore from Backup File</h3>
|
||||||
|
</div>
|
||||||
|
<div class="p-6">
|
||||||
|
<form method="POST" action="/admin/restore-database" enctype="multipart/form-data">
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Upload Backup File</label>
|
||||||
|
<div class="flex items-center justify-center w-full">
|
||||||
|
<label class="flex flex-col w-full h-32 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg cursor-pointer hover:bg-gray-50 dark:hover:bg-gray-700">
|
||||||
|
<div class="flex flex-col items-center justify-center pt-5 pb-6">
|
||||||
|
<i class="fas fa-cloud-upload-alt text-3xl text-gray-400 mb-2"></i>
|
||||||
|
<p class="mb-2 text-sm text-gray-500 dark:text-gray-400"><span class="font-semibold">Click to upload</span> or drag and drop</p>
|
||||||
|
<p class="text-xs text-gray-500 dark:text-gray-400">SQLite backup file</p>
|
||||||
|
</div>
|
||||||
|
<input type="file" name="backup_file" class="hidden" accept=".db,.sqlite,.backup" />
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-end">
|
||||||
|
<button type="submit" class="px-4 py-2 bg-yellow-600 text-white rounded-lg hover:bg-yellow-700 focus:outline-none focus:ring-2 focus:ring-yellow-500 dark:bg-yellow-700 dark:hover:bg-yellow-800">
|
||||||
|
<i class="fas fa-undo-alt mr-2"></i>
|
||||||
|
Restore Database
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Warning Section -->
|
||||||
|
<div class="p-4 mt-8 bg-yellow-50 border border-yellow-200 rounded-lg text-yellow-800 dark:bg-yellow-900/30 dark:border-yellow-800 dark:text-yellow-300">
|
||||||
|
<div class="flex">
|
||||||
|
<i class="fas fa-exclamation-triangle flex-shrink-0 w-5 h-5 mr-3"></i>
|
||||||
|
<div>
|
||||||
|
<h3 class="text-sm font-medium mb-2">Important Safety Information</h3>
|
||||||
|
<ul class="text-sm space-y-1 list-disc list-inside">
|
||||||
|
<li>Always create a backup before making significant changes</li>
|
||||||
|
<li>Restoring a backup will overwrite all current data</li>
|
||||||
|
<li>Database optimization may take time for large databases</li>
|
||||||
|
<li>Clear job history operations cannot be undone</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Restore Confirmation Modal -->
|
||||||
|
<div id="confirm-restore-modal" tabindex="-1" aria-hidden="true" class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
|
||||||
|
<div class="relative p-4 w-full max-w-md max-h-full">
|
||||||
|
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
|
||||||
|
<div class="p-4 md:p-5 text-center">
|
||||||
|
<i class="fas fa-exclamation-triangle mx-auto mb-4 text-yellow-400 text-3xl"></i>
|
||||||
|
<h3 class="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">Are you sure you want to restore this backup? This will overwrite your current database.</h3>
|
||||||
|
<form method="POST" id="restore-form" action="/admin/restore-database">
|
||||||
|
<input type="hidden" name="filename" id="restore-filename" value="" />
|
||||||
|
<button type="submit" class="text-white bg-yellow-600 hover:bg-yellow-800 focus:ring-4 focus:outline-none focus:ring-yellow-300 dark:focus:ring-yellow-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center mr-2">
|
||||||
|
Yes, restore it
|
||||||
|
</button>
|
||||||
|
<button type="button" data-modal-hide="confirm-restore-modal" class="text-gray-500 bg-white hover:bg-gray-100 focus:ring-4 focus:outline-none focus:ring-gray-200 rounded-lg border border-gray-200 text-sm font-medium px-5 py-2.5 hover:text-gray-900 focus:z-10 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-500 dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-gray-600">
|
||||||
|
No, cancel
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Delete Confirmation Modal -->
|
||||||
|
<div id="confirm-delete-modal" tabindex="-1" aria-hidden="true" class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full">
|
||||||
|
<div class="relative p-4 w-full max-w-md max-h-full">
|
||||||
|
<div class="relative bg-white rounded-lg shadow dark:bg-gray-700">
|
||||||
|
<div class="p-4 md:p-5 text-center">
|
||||||
|
<i class="fas fa-trash-alt mx-auto mb-4 text-red-400 text-3xl"></i>
|
||||||
|
<h3 class="mb-5 text-lg font-normal text-gray-500 dark:text-gray-400">Are you sure you want to delete this backup file?</h3>
|
||||||
|
<form method="POST" id="delete-form" action="">
|
||||||
|
<button type="submit" class="text-white bg-red-600 hover:bg-red-800 focus:ring-4 focus:outline-none focus:ring-red-300 dark:focus:ring-red-800 font-medium rounded-lg text-sm inline-flex items-center px-5 py-2.5 text-center mr-2">
|
||||||
|
Yes, delete it
|
||||||
|
</button>
|
||||||
|
<button type="button" data-modal-hide="confirm-delete-modal" class="text-gray-500 bg-white hover:bg-gray-100 focus:ring-4 focus:outline-none focus:ring-gray-200 rounded-lg border border-gray-200 text-sm font-medium px-5 py-2.5 hover:text-gray-900 focus:z-10 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-500 dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-gray-600">
|
||||||
|
No, cancel
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Handle restore modal
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
const restoreButtons = document.querySelectorAll('[data-modal-target="confirm-restore-modal"]');
|
||||||
|
restoreButtons.forEach(button => {
|
||||||
|
button.addEventListener('click', function() {
|
||||||
|
const backupName = this.getAttribute('data-backup-name');
|
||||||
|
document.getElementById('restore-filename').value = backupName;
|
||||||
|
document.getElementById('restore-form').action = `/admin/restore-database/${backupName}`;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle delete modal
|
||||||
|
const deleteButtons = document.querySelectorAll('[data-modal-target="confirm-delete-modal"]');
|
||||||
|
deleteButtons.forEach(button => {
|
||||||
|
button.addEventListener('click', function() {
|
||||||
|
const backupName = this.getAttribute('data-backup-name');
|
||||||
|
document.getElementById('delete-form').action = `/admin/delete-backup/${backupName}`;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// File upload preview
|
||||||
|
const fileInput = document.querySelector('input[type="file"]');
|
||||||
|
if (fileInput) {
|
||||||
|
fileInput.addEventListener('change', function(e) {
|
||||||
|
const fileName = e.target.files[0]?.name || 'No file selected';
|
||||||
|
const fileLabel = this.parentElement.querySelector('p.mb-2');
|
||||||
|
if (fileLabel) {
|
||||||
|
fileLabel.textContent = fileName;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user