label(fn (): string => app(RelatedNavigationResolver::class) ->primaryListAction(CrossResourceNavigationMatrix::SOURCE_BACKUP_SET, $this->getRecord())?->actionLabel ?? 'Open related record') ->url(fn (): ?string => app(RelatedNavigationResolver::class) ->primaryListAction(CrossResourceNavigationMatrix::SOURCE_BACKUP_SET, $this->getRecord())?->targetUrl) ->hidden(fn (): bool => ! (app(RelatedNavigationResolver::class) ->primaryListAction(CrossResourceNavigationMatrix::SOURCE_BACKUP_SET, $this->getRecord())?->isAvailable() ?? false)) ->color('gray'), ]; $mutationActions = [ $this->restoreAction(), $this->archiveAction(), $this->forceDeleteAction(), ]; $actions[] = ActionGroup::make($mutationActions) ->label('More') ->icon('heroicon-o-ellipsis-vertical') ->color('gray'); return $actions; } private function restoreAction(): Action { $action = Action::make('restore') ->label('Restore') ->color('success') ->icon('heroicon-o-arrow-uturn-left') ->requiresConfirmation() ->visible(fn (): bool => $this->getRecord() instanceof BackupSet && $this->getRecord()->trashed()) ->action(function (AuditLogger $auditLogger): void { /** @var BackupSet $record */ $record = $this->getRecord(); $record->restore(); $record->items()->withTrashed()->restore(); if ($record->tenant instanceof Tenant) { $auditLogger->log( tenant: $record->tenant, action: 'backup.restored', resourceType: 'backup_set', resourceId: (string) $record->getKey(), status: 'success', context: ['metadata' => ['name' => $record->name]], ); } Notification::make() ->title('Backup set restored') ->success() ->send(); $this->redirect(BackupSetResource::getUrl('view', ['record' => $record], tenant: Tenant::current()), navigate: true); }); UiEnforcement::forAction($action) ->preserveVisibility() ->requireCapability(Capabilities::TENANT_MANAGE) ->apply(); return $action; } private function archiveAction(): Action { $action = Action::make('archive') ->label('Archive') ->color('danger') ->icon('heroicon-o-archive-box-x-mark') ->requiresConfirmation() ->visible(fn (): bool => $this->getRecord() instanceof BackupSet && ! $this->getRecord()->trashed()) ->action(function (AuditLogger $auditLogger): void { /** @var BackupSet $record */ $record = $this->getRecord(); $record->delete(); if ($record->tenant instanceof Tenant) { $auditLogger->log( tenant: $record->tenant, action: 'backup.deleted', resourceType: 'backup_set', resourceId: (string) $record->getKey(), status: 'success', context: ['metadata' => ['name' => $record->name]], ); } Notification::make() ->title('Backup set archived') ->success() ->send(); $this->redirect(BackupSetResource::getUrl('index', tenant: Tenant::current()), navigate: true); }); UiEnforcement::forAction($action) ->preserveVisibility() ->requireCapability(Capabilities::TENANT_MANAGE) ->apply(); return $action; } private function forceDeleteAction(): Action { $action = Action::make('forceDelete') ->label('Force delete') ->color('danger') ->icon('heroicon-o-trash') ->requiresConfirmation() ->visible(fn (): bool => $this->getRecord() instanceof BackupSet && $this->getRecord()->trashed()) ->action(function (AuditLogger $auditLogger): void { /** @var BackupSet $record */ $record = $this->getRecord(); if ($record->restoreRuns()->withTrashed()->exists()) { Notification::make() ->title('Cannot force delete backup set') ->body('Backup sets referenced by restore runs cannot be removed.') ->danger() ->send(); return; } if ($record->tenant instanceof Tenant) { $auditLogger->log( tenant: $record->tenant, action: 'backup.force_deleted', resourceType: 'backup_set', resourceId: (string) $record->getKey(), status: 'success', context: ['metadata' => ['name' => $record->name]], ); } $record->items()->withTrashed()->forceDelete(); $record->forceDelete(); Notification::make() ->title('Backup set permanently deleted') ->success() ->send(); $this->redirect(BackupSetResource::getUrl('index', tenant: Tenant::current()), navigate: true); }); UiEnforcement::forAction($action) ->preserveVisibility() ->requireCapability(Capabilities::TENANT_DELETE) ->apply(); return $action; } }