satisfy(ActionSurfaceSlot::ListHeader, 'The page header exposes Go to runbooks while row clicks remain the only inspect model.') ->satisfy(ActionSurfaceSlot::InspectAffordance, ActionSurfaceInspectAffordance::ClickableRow->value) ->exempt(ActionSurfaceSlot::ListBulkMoreGroup, 'System operations remain scan-first and intentionally omit bulk actions.') ->satisfy(ActionSurfaceSlot::ListEmptyState, 'The empty state explains when no operations have been queued yet and repeats the Go to runbooks CTA.') ->exempt(ActionSurfaceSlot::DetailHeader, 'Row navigation opens the canonical system run detail page, which owns header actions.'); } public static function canAccess(): bool { $user = auth('platform')->user(); if (! $user instanceof PlatformUser) { return false; } return $user->hasCapability(PlatformCapabilities::OPERATIONS_VIEW) || ($user->hasCapability(PlatformCapabilities::OPS_VIEW) && $user->hasCapability(PlatformCapabilities::RUNBOOKS_VIEW)); } public function mount(): void { $this->mountInteractsWithTable(); } /** * @return array */ protected function getHeaderActions(): array { return [ Action::make('go_to_runbooks') ->label('Go to runbooks') ->url(Runbooks::getUrl(panel: 'system')), ]; } public function table(Table $table): Table { return $table ->defaultSort('id', 'desc') ->paginated(\App\Support\Filament\TablePaginationProfiles::customPage()) ->query(function (): Builder { return OperationRun::query() ->with(['tenant', 'workspace']); }) ->columns([ TextColumn::make('id') ->label('ID') ->state(fn (OperationRun $record): string => '#'.$record->getKey()), TextColumn::make('status') ->badge() ->formatStateUsing(BadgeRenderer::label(BadgeDomain::OperationRunStatus)) ->color(BadgeRenderer::color(BadgeDomain::OperationRunStatus)) ->icon(BadgeRenderer::icon(BadgeDomain::OperationRunStatus)) ->iconColor(BadgeRenderer::iconColor(BadgeDomain::OperationRunStatus)), TextColumn::make('outcome') ->badge() ->formatStateUsing(BadgeRenderer::label(BadgeDomain::OperationRunOutcome)) ->color(BadgeRenderer::color(BadgeDomain::OperationRunOutcome)) ->icon(BadgeRenderer::icon(BadgeDomain::OperationRunOutcome)) ->iconColor(BadgeRenderer::iconColor(BadgeDomain::OperationRunOutcome)), TextColumn::make('type') ->label('Operation') ->formatStateUsing(fn (?string $state): string => OperationCatalog::label((string) $state)) ->searchable(), TextColumn::make('workspace.name') ->label('Workspace') ->toggleable(), TextColumn::make('tenant.name') ->label('Tenant') ->formatStateUsing(fn (?string $state): string => $state ?: 'Tenantless') ->toggleable(), TextColumn::make('initiator_name')->label('Initiator'), TextColumn::make('created_at')->label('Started')->since(), ]) ->recordUrl(fn (OperationRun $record): string => SystemOperationRunLinks::view($record)) ->actions([]) ->emptyStateHeading('No operations yet') ->emptyStateDescription('Operations from all workspaces will appear here when they are queued.') ->emptyStateActions([ Action::make('go_to_runbooks_empty') ->label('Go to runbooks') ->url(Runbooks::getUrl(panel: 'system')) ->button(), ]) ->bulkActions([]); } }