Initial commit: Pireon Admin — headless admin panel and public API
Laravel 13 + Filament 5 admin panel and REST API for a non-profit developer collective, backed by the Pireon OAuth identity server. The public site is a separate, server-rendered application consuming /api/public/v1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
106
app/Filament/Widgets/WhatNeedsYou.php
Normal file
106
app/Filament/Widgets/WhatNeedsYou.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Filament\Widgets;
|
||||
|
||||
use App\Filament\Pages\SiteHealth;
|
||||
use App\Models\Page;
|
||||
use App\Models\Project;
|
||||
use App\Models\Service;
|
||||
use App\Support\Health\Finding;
|
||||
use App\Support\Health\HealthReport;
|
||||
use App\Support\Health\Severity;
|
||||
use App\Support\ReviewTarget;
|
||||
use Filament\Widgets\StatsOverviewWidget;
|
||||
use Filament\Widgets\StatsOverviewWidget\Stat;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
/**
|
||||
* What is waiting for somebody, at the top of the dashboard.
|
||||
*
|
||||
* The counters it replaces said "7 projects, 10 members" — numbers that never
|
||||
* change and that nobody reads twice. What does get looked at every morning is
|
||||
* whether anything needs doing, and the health checks already know: this is
|
||||
* the same answers, in the first place anybody lands.
|
||||
*/
|
||||
class WhatNeedsYou extends StatsOverviewWidget
|
||||
{
|
||||
protected static ?int $sort = -10;
|
||||
|
||||
protected int|string|array $columnSpan = 'full';
|
||||
|
||||
public static function canView(): bool
|
||||
{
|
||||
return Auth::user()?->can('panel.access') ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, Stat>
|
||||
*/
|
||||
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<int, Stat>
|
||||
*/
|
||||
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'),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user