diff --git a/app/Livewire/Project/Service/BackupExecutions.php b/app/Livewire/Project/Service/BackupExecutions.php index d4b63e4766..34be4b11c9 100644 --- a/app/Livewire/Project/Service/BackupExecutions.php +++ b/app/Livewire/Project/Service/BackupExecutions.php @@ -2,6 +2,8 @@ namespace App\Livewire\Project\Service; +use App\Models\LocalFileVolume; +use App\Models\LocalPersistentVolume; use App\Models\ScheduledDatabaseBackup; use App\Models\ScheduledDatabaseBackupExecution; use App\Models\ScheduledVolumeBackup; @@ -14,6 +16,7 @@ use Illuminate\Contracts\View\View; use Illuminate\Database\Query\Builder; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Support\Collection; +use Livewire\Attributes\Locked; use Livewire\Component; use Livewire\WithPagination; @@ -26,8 +29,20 @@ class BackupExecutions extends Component public Service $service; + private const SORT_COLUMNS = [ + 'target' => 'sort_target', + 'type' => 'sort_type', + 'schedule' => 'sort_schedule', + 'status' => 'status', + 'started' => 'created_at', + 'size' => 'sort_size', + ]; + public int $perPage = 10; + #[Locked] + public string $sortBy = 'started_desc'; + public bool $executionModalOpen = false; public ?array $selectedExecution = null; @@ -55,6 +70,16 @@ class BackupExecutions extends Component $this->resetPage('executionsPage'); } + public function sortExecutions(string $sortBy): void + { + [$column, $direction] = array_pad(explode('_', $sortBy, 2), 2, null); + if (! array_key_exists($column, self::SORT_COLUMNS) || ! in_array($direction, ['asc', 'desc'], true)) { + return; + } + $this->sortBy = $sortBy; + $this->resetPage('executionsPage'); + } + public function openExecution(string $executionUuid): void { $this->authorize('view', $this->service); @@ -119,19 +144,33 @@ class BackupExecutions extends Component ->forService($this->service) ->select('id'); + $fileVolumeType = (new LocalFileVolume)->getMorphClass(); + $persistentVolumeType = (new LocalPersistentVolume)->getMorphClass(); + $databaseExecutions = ScheduledDatabaseBackupExecution::query() - ->select('id', 'uuid', 'created_at') + ->select('id', 'uuid', 'created_at', 'status') ->selectRaw("'database' as type") + ->selectRaw("CAST(NULLIF(size, '') AS BIGINT) as sort_size") + ->selectRaw("(SELECT LOWER(COALESCE(NULLIF(service_databases.human_name, ''), service_databases.name)) FROM scheduled_database_backups JOIN service_databases ON service_databases.id = scheduled_database_backups.database_id WHERE scheduled_database_backups.id = scheduled_database_backup_executions.scheduled_database_backup_id) as sort_target") + ->selectRaw("'Database' as sort_type") + ->selectRaw('(SELECT frequency FROM scheduled_database_backups WHERE scheduled_database_backups.id = scheduled_database_backup_executions.scheduled_database_backup_id) as sort_schedule') ->whereIn('scheduled_database_backup_id', $databaseScheduleIds) ->when($uuid !== null, fn ($query) => $query->where('uuid', $uuid)); $volumeExecutions = ScheduledVolumeBackupExecution::query() - ->select('id', 'uuid', 'created_at') + ->select('id', 'uuid', 'created_at', 'status') ->selectRaw("'storage' as type") + ->selectRaw('size as sort_size') + ->selectRaw('(SELECT LOWER(COALESCE((SELECT fs_path FROM local_file_volumes WHERE local_file_volumes.id = scheduled_volume_backups.backupable_id AND scheduled_volume_backups.backupable_type = ?), (SELECT name FROM local_persistent_volumes WHERE local_persistent_volumes.id = scheduled_volume_backups.backupable_id AND scheduled_volume_backups.backupable_type = ?))) FROM scheduled_volume_backups WHERE scheduled_volume_backups.id = scheduled_volume_backup_executions.scheduled_volume_backup_id) as sort_target', [$fileVolumeType, $persistentVolumeType]) + ->selectRaw("(SELECT CASE WHEN backupable_type = ? THEN 'Directory' ELSE 'Volume' END FROM scheduled_volume_backups WHERE scheduled_volume_backups.id = scheduled_volume_backup_executions.scheduled_volume_backup_id) as sort_type", [$fileVolumeType]) + ->selectRaw('(SELECT frequency FROM scheduled_volume_backups WHERE scheduled_volume_backups.id = scheduled_volume_backup_executions.scheduled_volume_backup_id) as sort_schedule') ->whereIn('scheduled_volume_backup_id', $volumeScheduleIds) ->when($uuid !== null, fn ($query) => $query->where('uuid', $uuid)); + [$sortColumn, $sortDirection] = explode('_', $this->sortBy, 2); + return $databaseExecutions->toBase() ->unionAll($volumeExecutions->toBase()) + ->orderBy(self::SORT_COLUMNS[$sortColumn], $sortDirection) ->orderByDesc('created_at') ->orderByDesc('id') ->orderBy('type'); diff --git a/resources/css/app.css b/resources/css/app.css index 4b0fef04e9..d806a603dd 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -3540,8 +3540,9 @@ input[type="search"]::-webkit-search-results-decoration { min-width: 50rem; } +/* Shared by the Schedules and Executions tables of a service, so their columns line up. */ .service-backup-table-grid { - grid-template-columns: minmax(10rem, 1.7fr) 6rem minmax(7rem, 0.8fr) 7.5rem 6.5rem minmax(8rem, 1fr) 4.5rem; + grid-template-columns: minmax(10rem, 1.5fr) 6rem minmax(7rem, 0.8fr) 7.5rem minmax(11rem, 1.2fr) minmax(6rem, 0.8fr) 4.5rem; width: 100%; } @@ -3551,18 +3552,9 @@ input[type="search"]::-webkit-search-results-decoration { /* Rows are reordered with CSS order, so dividers must not depend on DOM position. */ .data-table-row.service-backup-table-grid { - background: var(--coollabs-base); border-top: 1px solid var(--coollabs-fill); } -.data-table-row.service-backup-table-grid:hover { - background: color-mix(in srgb, var(--coollabs-base) 98%, black); -} - -.dark .data-table-row.service-backup-table-grid:hover { - background: color-mix(in srgb, var(--coollabs-base) 98%, white); -} - /* Persistent storage volumes: Name | [Source] | Destination | [PR suffix] | Backup | [Actions] */ .volumes-table-grid-readonly { grid-template-columns: minmax(10rem, 1.4fr) minmax(8rem, 1fr) 5rem; diff --git a/resources/views/livewire/project/service/backup-executions.blade.php b/resources/views/livewire/project/service/backup-executions.blade.php index ff12f2f6e3..f0c7d99ca7 100644 --- a/resources/views/livewire/project/service/backup-executions.blade.php +++ b/resources/views/livewire/project/service/backup-executions.blade.php @@ -40,9 +40,16 @@ description="Execution history appears here after a backup schedule runs." icon-name="browser-terminal" /> @else