label('Acknowledge all matching') ->icon('heroicon-o-check') ->color('gray') ->requiresConfirmation() ->authorize(function (): bool { $tenant = Tenant::current(); $user = auth()->user(); if (! $tenant || ! $user instanceof User) { return false; } $probe = new Finding(['tenant_id' => $tenant->getKey()]); return $user->can('update', $probe); }) ->visible(fn (): bool => $this->getStatusFilterValue() === Finding::STATUS_NEW) ->modalDescription(function (): string { $count = $this->getAllMatchingCount(); return "You are about to acknowledge {$count} finding".($count === 1 ? '' : 's').' matching the current filters.'; }) ->form(function (): array { $count = $this->getAllMatchingCount(); if ($count <= 100) { return []; } return [ TextInput::make('confirmation') ->label('Type ACKNOWLEDGE to confirm') ->required() ->in(['ACKNOWLEDGE']) ->validationMessages([ 'in' => 'Please type ACKNOWLEDGE to confirm.', ]), ]; }) ->action(function (array $data): void { $tenant = Tenant::current(); $user = auth()->user(); if (! $tenant || ! $user instanceof User) { return; } $query = $this->buildAllMatchingQuery(); $count = (clone $query)->count(); if ($count === 0) { Notification::make() ->title('No matching findings') ->body('There are no new findings matching the current filters.') ->warning() ->send(); return; } $firstRecord = (clone $query)->first(); if ($firstRecord instanceof Finding) { Gate::authorize('update', $firstRecord); } $updated = $query->update([ 'status' => Finding::STATUS_ACKNOWLEDGED, 'acknowledged_at' => now(), 'acknowledged_by_user_id' => $user->getKey(), ]); $this->deselectAllTableRecords(); $this->resetPage(); Notification::make() ->title('Bulk acknowledge completed') ->body("Acknowledged {$updated} finding".($updated === 1 ? '' : 's').'.') ->success() ->send(); }), ]; } protected function buildAllMatchingQuery(): Builder { $tenant = Tenant::current(); $query = Finding::query(); if (! $tenant) { return $query->whereRaw('1 = 0'); } $query->where('tenant_id', $tenant->getKey()); $query->where('status', Finding::STATUS_NEW); $findingType = $this->getFindingTypeFilterValue(); if (is_string($findingType) && $findingType !== '') { $query->where('finding_type', $findingType); } $scopeKeyState = $this->getTableFilterState('scope_key') ?? []; $scopeKey = Arr::get($scopeKeyState, 'scope_key'); if (is_string($scopeKey) && $scopeKey !== '') { $query->where('scope_key', $scopeKey); } $runIdsState = $this->getTableFilterState('run_ids') ?? []; $baselineRunId = Arr::get($runIdsState, 'baseline_run_id'); if (is_numeric($baselineRunId)) { $query->where('baseline_run_id', (int) $baselineRunId); } $currentRunId = Arr::get($runIdsState, 'current_run_id'); if (is_numeric($currentRunId)) { $query->where('current_run_id', (int) $currentRunId); } return $query; } protected function getAllMatchingCount(): int { return (int) $this->buildAllMatchingQuery()->count(); } protected function getStatusFilterValue(): string { $state = $this->getTableFilterState('status') ?? []; $value = Arr::get($state, 'value'); return is_string($value) && $value !== '' ? $value : Finding::STATUS_NEW; } protected function getFindingTypeFilterValue(): string { $state = $this->getTableFilterState('finding_type') ?? []; $value = Arr::get($state, 'value'); return is_string($value) && $value !== '' ? $value : Finding::FINDING_TYPE_DRIFT; } }