can('panel.access') ?? false; } /** * @return array */ protected function getStats(): array { $findings = app(HealthReport::class) ->runFor(Auth::user()) ->filter(fn (Finding $f) => $f->severity->isProblem()); // The one stat here that is about the reader rather than the site. // It goes first, and it goes before "all clear", because a colleague // waiting on you is more urgent than anything a check could find — // and unlike the bell that announced it, this does not disappear the // moment somebody clicks it. $reviews = $this->reviewStats(); if ($findings->isEmpty()) { return $reviews !== [] ? $reviews : [ Stat::make(__('panel.today.all_clear'), '✓') ->description(__('panel.today.all_clear_hint')) ->descriptionIcon('heroicon-m-check-circle') ->color('success'), ]; } // Worst first, and only a few: a dashboard listing fourteen things is // a dashboard nobody acts on. return [ ...$reviews, ...$findings ->take($reviews === [] ? 4 : 3) ->map(fn (Finding $finding) => Stat::make($finding->title(), (string) $finding->count) ->description($finding->samples[0] ?? $finding->description()) ->descriptionIcon($finding->severity === Severity::Error ? 'heroicon-m-x-circle' : 'heroicon-m-exclamation-triangle') ->color($finding->severity->getColor()) ->url($finding->url ?? SiteHealth::getUrl())) ->values() ->all(), ]; } /** * Work handed to this person and not yet answered, across the three things * that can be handed over. One number rather than three: what a reviewer * needs to know is whether anybody is waiting, not the breakdown. * * @return array */ protected function reviewStats(): array { $user = Auth::user(); $waiting = collect([Page::class, Project::class, Service::class]) ->sum(fn (string $model) => ReviewTarget::waitingFor($model, $user) ?? 0); if ($waiting < 1) { return []; } return [ Stat::make(__('panel.reviews.waiting_for_you'), (string) $waiting) ->description(__('panel.reviews.waiting_for_you_hint')) ->descriptionIcon('heroicon-m-hand-raised') ->color('warning'), ]; } }