Files
landing-api/app/Providers/Filament/AdminPanelProvider.php
Josep Piguillem 3897113313 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>
2026-08-19 17:55:27 +02:00

128 lines
5.0 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Providers\Filament;
use App\Filament\Pages\Auth\PireonLogin;
use App\Filament\Widgets\ContentOverview;
use App\Filament\Widgets\WhatNeedsYou;
use App\Http\Middleware\SetLocale;
use Filament\Http\Middleware\Authenticate;
use Filament\Http\Middleware\AuthenticateSession;
use Filament\Http\Middleware\DisableBladeIconComponents;
use Filament\Http\Middleware\DispatchServingFilamentEvent;
use Filament\Navigation\NavigationItem;
use Filament\Pages\Dashboard;
use Filament\Panel;
use Filament\PanelProvider;
use Filament\Support\Colors\Color;
use Filament\Support\Icons\Heroicon;
use Filament\View\PanelsRenderHook;
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
use Illuminate\Cookie\Middleware\EncryptCookies;
use Illuminate\Foundation\Http\Middleware\PreventRequestForgery;
use Illuminate\Routing\Middleware\SubstituteBindings;
use Illuminate\Session\Middleware\StartSession;
use Illuminate\View\Middleware\ShareErrorsFromSession;
class AdminPanelProvider extends PanelProvider
{
public function panel(Panel $panel): Panel
{
return $panel
->default()
->id('admin')
->path('admin')
->brandName(config('app.name'))
// No password form: this page only offers a button that starts the
// OAuth flow at the identity server.
->login(PireonLogin::class)
->colors([
'primary' => Color::Indigo,
])
->font('Inter')
->sidebarCollapsibleOnDesktop()
// The bell. Submissions from the public site arrive here, because
// an inbox nobody is told about is an inbox nobody reads.
->databaseNotifications()
->databaseNotificationsPolling('60s')
->navigationGroups([
__('panel.groups.collective'),
__('panel.groups.content'),
__('panel.groups.administration'),
])
// The API documentation lives outside the panel — it is a plain
// page, readable without an account — but this is where somebody
// goes looking for it. A new tab, so opening the reference does
// not throw away whatever was half-edited in the panel.
->navigationItems([
// The label is a closure, not a resolved string: the panel is
// configured once per process, so a translation evaluated here
// would freeze in whatever language happened to be active then.
NavigationItem::make(fn (): string => __('docs.title'))
->url(fn (): string => route('docs.api'), shouldOpenInNewTab: true)
->icon(Heroicon::OutlinedCodeBracketSquare)
->group(__('panel.groups.administration'))
->sort(95),
])
->discoverResources(in: app_path('Filament/Resources'), for: 'App\Filament\Resources')
->discoverPages(in: app_path('Filament/Pages'), for: 'App\Filament\Pages')
->pages([
Dashboard::class,
])
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\Filament\Widgets')
->widgets([
// First on the dashboard: what is waiting for somebody, rather
// than counters that never change.
WhatNeedsYou::class,
ContentOverview::class,
])
// Language switcher, rendered next to the user menu.
// First render hook to fire on every page, panel and login alike:
// the one place that has to be true regardless of which screen
// somebody lands on first.
->renderHook(
PanelsRenderHook::BODY_START,
fn (): string => view('filament.partials.environment-banner')->render(),
)
->renderHook(
PanelsRenderHook::USER_MENU_BEFORE,
fn (): string => view('filament.partials.language-switcher')->render(),
)
// And once more under the sign-in form, which is the one screen
// with no user whose preference we could read.
->renderHook(
PanelsRenderHook::AUTH_LOGIN_FORM_AFTER,
fn (): string => view('filament.partials.login-footer')->render(),
)
->middleware([
EncryptCookies::class,
AddQueuedCookiesToResponse::class,
StartSession::class,
AuthenticateSession::class,
ShareErrorsFromSession::class,
PreventRequestForgery::class,
SubstituteBindings::class,
DisableBladeIconComponents::class,
DispatchServingFilamentEvent::class,
// Filament panels do not run the "web" middleware group, so
// locale negotiation has to be listed here explicitly.
SetLocale::class,
])
->authMiddleware([
Authenticate::class,
]);
}
}