TenantAtlas/apps/platform/app/Filament/Pages/Monitoring/Alerts.php
ahmido d879c61204 feat: implement environment filtering for alerts and audit logs (#378)
## Summary
- Implement environment filtering across Filament alerts and audit log pages, widgets, and support builders.
- Add a feature test covering the alerts/audit environment filter contract.
- Add the supporting specification and planning artifacts under `specs/`.

## Testing
- Not run in this step.

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #378
2026-05-17 00:27:27 +00:00

198 lines
6.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Filament\Pages\Monitoring;
use App\Filament\Clusters\Monitoring\AlertsCluster;
use App\Filament\Concerns\ClearsWorkspaceHubEnvironmentFilterState;
use App\Filament\Resources\AlertDeliveryResource;
use App\Filament\Resources\AlertDestinationResource;
use App\Filament\Resources\AlertRuleResource;
use App\Filament\Widgets\Alerts\AlertsKpiHeader;
use App\Models\User;
use App\Models\Workspace;
use App\Services\Auth\WorkspaceCapabilityResolver;
use App\Support\Auth\Capabilities;
use App\Support\Navigation\CanonicalNavigationContext;
use App\Support\Navigation\WorkspaceHubEnvironmentFilter;
use App\Support\OperateHub\OperateHubShell;
use App\Support\Ui\ActionSurface\ActionSurfaceDeclaration;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceProfile;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceSlot;
use App\Support\Ui\ActionSurface\Enums\ActionSurfaceType;
use App\Support\Workspaces\WorkspaceContext;
use BackedEnum;
use Filament\Actions\Action;
use Filament\Facades\Filament;
use Filament\Pages\Page;
use UnitEnum;
class Alerts extends Page
{
use ClearsWorkspaceHubEnvironmentFilterState;
protected static ?string $cluster = AlertsCluster::class;
protected static ?int $navigationSort = 20;
protected static string|UnitEnum|null $navigationGroup = 'Monitoring';
protected static ?string $navigationLabel = 'Overview';
protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-bell-alert';
protected static ?string $slug = 'overview';
protected static ?string $title = 'Alerts';
protected string $view = 'filament.pages.monitoring.alerts';
public function mount(): void
{
$this->resetWorkspaceHubEnvironmentFilterStateForCleanEntry(request());
$this->environmentFilter();
}
public static function actionSurfaceDeclaration(): ActionSurfaceDeclaration
{
return ActionSurfaceDeclaration::forPage(ActionSurfaceProfile::ListOnlyReadOnly, ActionSurfaceType::ReadOnlyRegistryReport)
->satisfy(ActionSurfaceSlot::ListHeader, 'Header keeps alerts scope and origin navigation quiet on the page-level overview.')
->exempt(ActionSurfaceSlot::InspectAffordance, 'The alerts overview is a page-level monitoring summary and does not inspect records inline.')
->exempt(ActionSurfaceSlot::ListRowMoreMenu, 'The alerts overview does not render row-level secondary actions.')
->exempt(ActionSurfaceSlot::ListBulkMoreGroup, 'The alerts overview does not expose bulk actions.')
->exempt(ActionSurfaceSlot::ListEmptyState, 'The overview always renders KPI widgets and downstream drilldown navigation instead of a list-style empty state.');
}
public static function canAccess(): bool
{
if (Filament::getCurrentPanel()?->getId() !== 'admin') {
return false;
}
$user = auth()->user();
if (! $user instanceof User) {
return false;
}
$workspaceId = app(WorkspaceContext::class)->currentWorkspaceId(request());
if (! is_int($workspaceId)) {
return false;
}
$workspace = Workspace::query()->whereKey($workspaceId)->first();
if (! $workspace instanceof Workspace) {
return false;
}
/** @var WorkspaceCapabilityResolver $resolver */
$resolver = app(WorkspaceCapabilityResolver::class);
return $resolver->isMember($user, $workspace)
&& $resolver->can($user, $workspace, Capabilities::ALERTS_VIEW);
}
protected function getHeaderWidgets(): array
{
return [
AlertsKpiHeader::class,
];
}
/**
* @return array{label: string, clear_url: string, description: string}|null
*/
public function environmentFilterChip(): ?array
{
$filter = $this->environmentFilter();
if (! $filter instanceof WorkspaceHubEnvironmentFilter) {
return null;
}
return [
'label' => $filter->displayName(),
'clear_url' => $this->cleanWorkspaceHubUrl(route('filament.admin.alerts')),
'description' => 'Delivery signal is filtered. Rules and targets remain workspace configuration.',
];
}
public function alertDeliveriesUrl(): string
{
return AlertDeliveryResource::getUrl('index', $this->filteredNavigationParameters(), panel: 'admin');
}
public function alertRulesUrl(): string
{
return $this->cleanWorkspaceHubUrl(AlertRuleResource::getUrl(panel: 'admin'));
}
public function alertDestinationsUrl(): string
{
return $this->cleanWorkspaceHubUrl(AlertDestinationResource::getUrl(panel: 'admin'));
}
public function auditLogUrl(): string
{
return route('admin.monitoring.audit-log', $this->filteredNavigationParameters());
}
/**
* @return array<Action>
*/
protected function getHeaderActions(): array
{
$actions = app(OperateHubShell::class)->headerActions(
scopeActionName: 'operate_hub_scope_alerts',
returnActionName: 'operate_hub_return_alerts',
);
$navigationContext = CanonicalNavigationContext::fromRequest(request());
if ($navigationContext?->backLinkLabel !== null && $navigationContext->backLinkUrl !== null) {
array_splice($actions, 1, 0, [
Action::make('operate_hub_back_to_origin_alerts')
->label($navigationContext->backLinkLabel)
->icon('heroicon-o-arrow-left')
->color('gray')
->url($navigationContext->backLinkUrl),
]);
}
return $actions;
}
/**
* @return array<string, mixed>
*/
private function filteredNavigationParameters(): array
{
return array_filter(
array_merge(
$this->navigationContext()?->toQuery() ?? [],
$this->environmentFilter()?->queryParameters() ?? [],
),
static fn (mixed $value): bool => $value !== null && $value !== '' && $value !== [],
);
}
private function navigationContext(): ?CanonicalNavigationContext
{
return CanonicalNavigationContext::fromRequest(request());
}
private function environmentFilter(): ?WorkspaceHubEnvironmentFilter
{
$workspace = app(WorkspaceContext::class)->currentWorkspace(request());
if (! $workspace instanceof Workspace) {
return null;
}
return WorkspaceHubEnvironmentFilter::fromRequest(request(), $workspace);
}
}