169 lines
12 KiB
PHP
169 lines
12 KiB
PHP
<x-layout title="Respaldos - Lauck">
|
|
|
|
<x-section-header subtitle="Respaldos" title="Administración de " highlight="Copias de Seguridad" />
|
|
|
|
<!-- Estadísticas de Disco y Resumen -->
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 w-full mb-8">
|
|
|
|
<!-- Tarjeta Espacio Total Utilizado -->
|
|
<div class="bg-gray-100 dark:bg-panel-bg p-6 rounded-xl border border-gray-300 dark:border-neutral-800 shadow-md">
|
|
<span class="text-xs font-bold text-gray-500 uppercase tracking-widest block mb-1">Espacio en Copias</span>
|
|
<div class="text-3xl font-black text-gray-900 dark:text-white font-mono">
|
|
{{ $diskStats['total_backups_size'] }}
|
|
</div>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400 mt-2">Total acumulado de archivos .zip</p>
|
|
</div>
|
|
|
|
<!-- Tarjeta Espacio Libre en Disco -->
|
|
<div class="bg-gray-100 dark:bg-panel-bg p-6 rounded-xl border border-gray-300 dark:border-neutral-800 shadow-md">
|
|
<span class="text-xs font-bold text-gray-500 uppercase tracking-widest block mb-1">Espacio Libre del Servidor</span>
|
|
<div class="text-3xl font-black text-green-600 dark:text-neon-lime font-mono">
|
|
{{ $diskStats['free_space'] }}
|
|
</div>
|
|
<p class="text-xs text-gray-600 dark:text-gray-400 mt-2">De un total de {{ $diskStats['total_space'] }}</p>
|
|
</div>
|
|
|
|
<!-- Tarjeta Estado del Disco -->
|
|
<div class="bg-gray-100 dark:bg-panel-bg p-6 rounded-xl border border-gray-300 dark:border-neutral-800 shadow-md flex flex-col justify-between">
|
|
<div>
|
|
<span class="text-xs font-bold text-gray-500 uppercase tracking-widest block mb-1">Capacidad de Almacenamiento</span>
|
|
<div class="flex justify-between text-xs text-gray-700 dark:text-gray-300 font-mono mt-1">
|
|
<span>Libre: {{ $diskStats['free_percentage'] }}%</span>
|
|
<span>Usado: {{ 100 - $diskStats['free_percentage'] }}%</span>
|
|
</div>
|
|
</div>
|
|
<div class="w-full bg-gray-300 dark:bg-neutral-800 rounded-full h-2.5 mt-2 overflow-hidden">
|
|
<div class="bg-green-500 dark:bg-neon-lime h-2.5 rounded-full" style="width: {{ $diskStats['free_percentage'] }}%"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Acciones (Subir / Generar) -->
|
|
<div class="w-full flex flex-col md:flex-row justify-between items-center gap-4 mb-6 bg-gray-100 dark:bg-panel-bg p-4 rounded-xl border border-gray-300 dark:border-neutral-800 shadow-md">
|
|
|
|
<!-- Formulario de Subida -->
|
|
<div class="w-full md:w-auto">
|
|
<form action="{{ route('admin.backups.upload') }}" method="POST" enctype="multipart/form-data" class="flex flex-col sm:flex-row gap-2 items-center">
|
|
@csrf
|
|
<div class="flex flex-col">
|
|
<label class="block text-[10px] font-bold text-gray-500 uppercase mb-1">Subir Copia de Seguridad (.zip)</label>
|
|
<input type="file" name="backup_file" accept=".zip" required class="block w-full text-xs text-gray-900 dark:text-gray-300 border border-gray-300 dark:border-neutral-700 rounded-lg bg-white dark:bg-neutral-800 focus:outline-none file:mr-4 file:py-2 file:px-4 file:border-0 file:text-xs file:font-bold file:bg-neutral-950 dark:file:bg-neon-lime file:text-neon-lime dark:file:text-neutral-900 hover:file:bg-neutral-900 hover:dark:file:bg-[#b3e600] cursor-pointer" />
|
|
</div>
|
|
<button type="submit" class="w-full sm:w-auto px-5 py-2 text-xs font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] uppercase tracking-wide transition-colors self-end mt-4 sm:mt-0">
|
|
Subir Respaldo
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Botón Generar Copia -->
|
|
<div class="w-full md:w-auto flex justify-end">
|
|
<form action="{{ route('admin.backups.create') }}" method="POST">
|
|
@csrf
|
|
<button type="submit" class="w-full sm:w-auto text-center px-6 py-3 text-sm font-bold text-neon-lime dark:text-neutral-900 bg-neutral-950 dark:bg-neon-lime rounded-lg hover:bg-neutral-900/80 hover:dark:bg-[#b3e600] transition-colors uppercase tracking-wide flex items-center gap-2 shadow-lg dark:shadow-neon-lime/10">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" stroke-width="2.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M20.25 6.375c0 2.278-3.694 4.125-8.25 4.125S3.75 8.653 3.75 6.375m16.5 0c0-2.278-3.694-4.125-8.25-4.125S3.75 4.097 3.75 6.375m16.5 0v11.25c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125V6.375m16.5 0v3.75m-16.5-3.75v3.75m16.5 0v3.75C20.25 16.153 16.556 18 12 18s-8.25-1.847-8.25-4.125v-3.75m16.5 0c0 2.278-3.694 4.125-8.25 4.125s-8.25-1.847-8.25-4.125" />
|
|
</svg>
|
|
Generar Nueva Copia
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Listado de Archivos -->
|
|
<div class="relative overflow-x-auto shadow-md sm:rounded-lg border border-gray-400 dark:border-neutral-800 w-full">
|
|
<table class="w-full text-sm text-left rtl:text-right text-neutral-900 dark:text-white">
|
|
<thead class="text-xs text-neutral-800 dark:text-gray-300 uppercase bg-gray-400 dark:bg-neutral-800 border-b border-gray-300 dark:border-neutral-700">
|
|
<tr>
|
|
<th scope="col" class="px-6 py-3">Nombre del Archivo</th>
|
|
<th scope="col" class="px-6 py-3">Fecha de Creación</th>
|
|
<th scope="col" class="px-6 py-3 font-mono">Tamaño</th>
|
|
<th scope="col" class="px-6 py-3 text-right">Acciones</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse($backups as $backup)
|
|
<tr class="bg-gray-200/50 dark:bg-neutral-900/50 border-b border-gray-400 dark:border-neutral-800 hover:bg-gray-400 hover:dark:bg-neutral-800 transition-colors group">
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<div class="flex items-center gap-3">
|
|
<!-- Icono archivo zip -->
|
|
<svg class="size-6 text-gray-500 group-hover:text-gray-900 dark:group-hover:text-neon-lime transition-colors" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z"></path>
|
|
</svg>
|
|
<span class="font-semibold font-mono text-sm tracking-tight text-gray-900 dark:text-white">
|
|
{{ $backup['filename'] }}
|
|
</span>
|
|
</div>
|
|
</td>
|
|
<td class="px-6 py-4">
|
|
<span class="text-xs text-gray-700 dark:text-gray-300">
|
|
{{ $backup['created_at'] }}
|
|
</span>
|
|
</td>
|
|
<td class="px-6 py-4 font-mono text-xs font-semibold text-gray-700 dark:text-gray-300">
|
|
{{ $backup['size'] }}
|
|
</td>
|
|
<td class="px-6 py-4 text-right flex items-center justify-end gap-2">
|
|
<!-- Restaurar -->
|
|
<form action="{{ route('admin.backups.restore', $backup['filename']) }}" method="POST" class="restore-form inline">
|
|
@csrf
|
|
<button title="Restaurar Base de Datos" type="submit" class="p-2 font-bold dark:font-medium text-amber-600 dark:text-amber-400 border-2 border-amber-600 rounded-lg hover:bg-amber-600 hover:text-white dark:hover:text-white transition-colors">
|
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8m0 0H15.5M21 8V2m0 10a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16m0 0h5.5M3 16v6"/>
|
|
</svg>
|
|
</button>
|
|
</form>
|
|
|
|
<!-- Descargar -->
|
|
<a href="{{ route('admin.backups.download', $backup['filename']) }}" title="Descargar" class="font-semibold p-2 text-blue-700 dark:text-blue-400 border-2 border-blue-700 rounded-lg hover:bg-blue-700 hover:text-white dark:hover:text-white transition-colors">
|
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M4 16v1a3 3 0 0 0 3 3h10a3 3 0 0 0 3-3v-1m-4-4-4 4m0 0-4-4m4 4V4"/>
|
|
</svg>
|
|
</a>
|
|
|
|
<!-- Eliminar -->
|
|
<form action="{{ route('admin.backups.destroy', $backup['filename']) }}" method="POST" class="delete-form inline">
|
|
@csrf
|
|
@method('DELETE')
|
|
<button title="Eliminar" type="submit" class="p-2 font-bold dark:font-medium text-red-600 dark:text-red-400 border-2 border-red-600 rounded-lg hover:bg-red-600 hover:text-white dark:hover:text-white transition-colors">
|
|
<svg class="size-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24">
|
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M5 7h14m-9 3v8m4-8v8M10 3h4a1 1 0 0 1 1 1v3H9V4a1 1 0 0 1 1-1ZM6 7h12v13a1 1 0 0 1-1 1H7a1 1 0 0 1-1-1V7Z"/>
|
|
</svg>
|
|
</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="4" class="px-6 py-10 text-center text-gray-500">
|
|
<div class="flex flex-col items-center justify-center">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-12 w-12 mb-3 text-gray-400 opacity-60" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="M20.25 7.5l-.625 10.632a2.25 2.25 0 01-2.247 2.118H6.622a2.25 2.25 0 01-2.247-2.118L3.75 7.5M10 11.25h4M3.375 7.5h17.25c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125H3.375c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125z" />
|
|
</svg>
|
|
<p class="text-sm font-medium">No se han generado copias de seguridad de la base de datos todavía.</p>
|
|
<p class="text-xs text-gray-400 mt-1">Haga clic en "Generar Nueva Copia" para iniciar una.</p>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Script para confirmation modal -->
|
|
@push('scripts')
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const restoreForms = document.querySelectorAll('.restore-form');
|
|
restoreForms.forEach(form => {
|
|
form.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
if (confirm('¡ATENCIÓN! Está a punto de restaurar la base de datos. Esta acción SOBREESCRIBIRÁ todos los datos actuales con los del archivo de respaldo. ¿Desea continuar?')); else return;
|
|
this.submit();
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
@endpush
|
|
|
|
</x-layout>
|