modifyQueryUsing(fn (Builder $query) => $query->with('policyVersion')) ->columns([ Tables\Columns\TextColumn::make('policy.display_name') ->label('Item') ->sortable() ->searchable() ->getStateUsing(fn (BackupItem $record) => $record->resolvedDisplayName()), Tables\Columns\TextColumn::make('policyVersion.version_number') ->label('Version') ->badge() ->default('—') ->getStateUsing(fn (BackupItem $record): ?int => $record->policyVersion?->version_number), Tables\Columns\TextColumn::make('policy_type') ->label('Type') ->badge() ->formatStateUsing(fn (?string $state) => static::typeMeta($state)['label'] ?? $state), Tables\Columns\TextColumn::make('restore_mode') ->label('Restore') ->badge() ->state(fn (BackupItem $record) => static::typeMeta($record->policy_type)['restore'] ?? 'enabled') ->color(fn (?string $state) => $state === 'preview-only' ? 'warning' : 'success'), Tables\Columns\TextColumn::make('risk') ->label('Risk') ->badge() ->state(fn (BackupItem $record) => static::typeMeta($record->policy_type)['risk'] ?? 'n/a') ->color(fn (?string $state) => str_contains((string) $state, 'high') ? 'danger' : 'gray'), Tables\Columns\TextColumn::make('policy_identifier') ->label('Policy ID') ->copyable(), Tables\Columns\TextColumn::make('platform')->badge(), Tables\Columns\TextColumn::make('assignments') ->label('Assignments') ->badge() ->color('info') ->getStateUsing(function (BackupItem $record): string { $assignments = $record->policyVersion?->assignments ?? $record->assignments; if (is_array($assignments)) { return (string) count($assignments); } $assignmentsFetched = $record->policyVersion?->metadata['assignments_fetched'] ?? $record->metadata['assignments_fetched'] ?? false; return $assignmentsFetched ? '0' : '—'; }), Tables\Columns\TextColumn::make('scope_tags') ->label('Scope Tags') ->default('—') ->getStateUsing(function (BackupItem $record): array { $tags = $record->policyVersion?->scope_tags['names'] ?? $record->metadata['scope_tag_names'] ?? []; return is_array($tags) ? $tags : []; }) ->formatStateUsing(function ($state): string { if (is_array($state)) { return $state === [] ? '—' : implode(', ', $state); } if (is_string($state) && $state !== '') { return $state; } return '—'; }), Tables\Columns\TextColumn::make('captured_at')->dateTime(), Tables\Columns\TextColumn::make('created_at')->since(), ]) ->filters([]) ->headerActions([ Actions\Action::make('addPolicies') ->label('Add Policies') ->icon('heroicon-o-plus') ->modalHeading('Add Policies') ->modalSubmitAction(false) ->modalCancelActionLabel('Close') ->modalContent(function (): View { $backupSet = $this->getOwnerRecord(); return view('filament.modals.backup-set-policy-picker', [ 'backupSetId' => $backupSet->getKey(), ]); }), ]) ->actions([ Actions\ActionGroup::make([ Actions\ViewAction::make() ->label('View policy') ->url(function (BackupItem $record): ?string { if (! $record->policy_id) { return null; } $tenant = $this->getOwnerRecord()->tenant ?? \App\Models\Tenant::current(); return PolicyResource::getUrl('view', ['record' => $record->policy_id], tenant: $tenant); }) ->hidden(fn (BackupItem $record) => ! $record->policy_id) ->openUrlInNewTab(true), Actions\Action::make('remove') ->label('Remove') ->color('danger') ->icon('heroicon-o-x-mark') ->requiresConfirmation() ->action(function (BackupItem $record, AuditLogger $auditLogger) { $record->delete(); if ($record->backupSet) { $record->backupSet->update([ 'item_count' => $record->backupSet->items()->count(), ]); } if ($record->tenant) { $auditLogger->log( tenant: $record->tenant, action: 'backup.item_removed', resourceType: 'backup_set', resourceId: (string) $record->backup_set_id, status: 'success', context: ['metadata' => ['policy_id' => $record->policy_id]] ); } Notification::make() ->title('Policy removed from backup') ->success() ->send(); }), ])->icon('heroicon-o-ellipsis-vertical'), ]) ->bulkActions([ Actions\BulkActionGroup::make([ Actions\BulkAction::make('bulk_remove') ->label('Remove selected') ->icon('heroicon-o-x-mark') ->color('danger') ->requiresConfirmation() ->action(function (Collection $records, AuditLogger $auditLogger) { if ($records->isEmpty()) { return; } $backupSet = $this->getOwnerRecord(); $records->each(fn (BackupItem $record) => $record->delete()); $backupSet->update([ 'item_count' => $backupSet->items()->count(), ]); $tenant = $records->first()?->tenant; if ($tenant) { $auditLogger->log( tenant: $tenant, action: 'backup.items_removed', resourceType: 'backup_set', resourceId: (string) $backupSet->id, status: 'success', context: [ 'metadata' => [ 'removed_count' => $records->count(), 'policy_ids' => $records->pluck('policy_id')->filter()->values()->all(), 'policy_identifiers' => $records->pluck('policy_identifier')->filter()->values()->all(), ], ] ); } Notification::make() ->title('Policies removed from backup') ->success() ->send(); }), ]), ]); } /** * @return array{label:?string,category:?string,restore:?string,risk:?string}|array */ private static function typeMeta(?string $type): array { if ($type === null) { return []; } $types = array_merge( config('tenantpilot.supported_policy_types', []), config('tenantpilot.foundation_types', []) ); return collect($types) ->firstWhere('type', $type) ?? []; } }