## Summary - harden findings and finding-exception Filament surfaces so workflow state, governance validity, overdue urgency, and next action are operator-first - add tenant stats widgets, segmented tabs, richer governance warnings, and baseline/dashboard attention propagation for overdue and lapsed governance states - add Spec 166 artifacts plus regression coverage for findings, badges, baseline summaries, tenantless operation viewer behavior, and critical table standards ## Verification - `vendor/bin/sail bin pint --dirty --format agent` - `vendor/bin/sail artisan test --compact` ## Filament Notes - Livewire v4.0+ compliance: yes, implementation stays on Filament v5 / Livewire v4 APIs only - Provider registration: unchanged, Laravel 12 panel/provider registration remains in `bootstrap/providers.php` - Global search: unchanged in this slice; `FindingExceptionResource` stays not globally searchable, no new globally searchable resource was introduced - Destructive actions: existing revoke/reject/approve/renew/workflow mutations remain capability-gated and confirmation-gated where already defined - Asset strategy: no new assets added; existing deploy process remains unchanged, including `php artisan filament:assets` when registered assets are used - Testing plan delivered: findings list/detail, exception register, dashboard attention, baseline summary, badge semantics, and tenantless operation viewer coverage Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #197
140 lines
7.6 KiB
PHP
140 lines
7.6 KiB
PHP
<x-filament-panels::page>
|
|
<x-filament::section>
|
|
<div class="flex flex-col gap-3">
|
|
<div class="text-lg font-semibold text-gray-900 dark:text-gray-100">
|
|
Canonical risk-acceptance approvals
|
|
</div>
|
|
|
|
<div class="text-sm text-gray-600 dark:text-gray-300">
|
|
Review pending requests, expiring governance, and lapsed exception coverage across entitled tenants without leaving the Monitoring area.
|
|
</div>
|
|
</div>
|
|
</x-filament::section>
|
|
|
|
{{ $this->table }}
|
|
|
|
@php
|
|
$selectedException = $this->selectedFindingException();
|
|
@endphp
|
|
|
|
@if ($selectedException)
|
|
<x-filament::section
|
|
:heading="'Finding exception #'.$selectedException->getKey()"
|
|
:description="$selectedException->requested_at?->toDayDateTimeString()"
|
|
>
|
|
<div class="grid gap-4 lg:grid-cols-3">
|
|
<div class="rounded-2xl border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-800 dark:bg-gray-900">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
|
|
Status
|
|
</div>
|
|
<div class="mt-2 text-sm font-medium text-gray-900 dark:text-gray-100">
|
|
{{ \App\Support\Badges\BadgeRenderer::label(\App\Support\Badges\BadgeDomain::FindingExceptionStatus)($selectedException->status) }}
|
|
</div>
|
|
<div class="mt-1 text-sm text-gray-600 dark:text-gray-300">
|
|
{{ \App\Support\Badges\BadgeRenderer::label(\App\Support\Badges\BadgeDomain::FindingRiskGovernanceValidity)($selectedException->current_validity_state) }}
|
|
</div>
|
|
@php
|
|
$governanceWarning = app(\App\Services\Findings\FindingRiskGovernanceResolver::class)->resolveWarningMessage($selectedException->finding, $selectedException);
|
|
$governanceWarningColor = (string) $selectedException->current_validity_state === \App\Models\FindingException::VALIDITY_EXPIRING
|
|
? 'text-warning-700 dark:text-warning-300'
|
|
: 'text-danger-700 dark:text-danger-300';
|
|
@endphp
|
|
@if (filled($governanceWarning))
|
|
<div class="mt-3 text-sm {{ $governanceWarningColor }}">
|
|
{{ $governanceWarning }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="rounded-2xl border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-800 dark:bg-gray-900">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
|
|
Scope
|
|
</div>
|
|
<div class="mt-2 text-sm font-medium text-gray-900 dark:text-gray-100">
|
|
{{ $selectedException->tenant?->name ?? 'Unknown tenant' }}
|
|
</div>
|
|
<div class="mt-1 text-sm text-gray-600 dark:text-gray-300">
|
|
Finding #{{ $selectedException->finding_id }}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="rounded-2xl border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-800 dark:bg-gray-900">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
|
|
Review timing
|
|
</div>
|
|
<div class="mt-2 text-sm font-medium text-gray-900 dark:text-gray-100">
|
|
Review due {{ $selectedException->review_due_at?->toDayDateTimeString() ?? '—' }}
|
|
</div>
|
|
<div class="mt-1 text-sm text-gray-600 dark:text-gray-300">
|
|
Expires {{ $selectedException->expires_at?->toDayDateTimeString() ?? '—' }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-6 grid gap-4 lg:grid-cols-2">
|
|
<div class="rounded-2xl border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-800 dark:bg-gray-900">
|
|
<div class="text-sm font-semibold text-gray-900 dark:text-gray-100">
|
|
Request
|
|
</div>
|
|
<dl class="mt-3 space-y-3">
|
|
<div>
|
|
<dt class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
|
|
Requested by
|
|
</dt>
|
|
<dd class="mt-1 text-sm text-gray-900 dark:text-gray-100">
|
|
{{ $selectedException->requester?->name ?? 'Unknown requester' }}
|
|
</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
|
|
Owner
|
|
</dt>
|
|
<dd class="mt-1 text-sm text-gray-900 dark:text-gray-100">
|
|
{{ $selectedException->owner?->name ?? 'Unassigned' }}
|
|
</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
|
|
Reason
|
|
</dt>
|
|
<dd class="mt-1 text-sm text-gray-900 dark:text-gray-100">
|
|
{{ $selectedException->request_reason }}
|
|
</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
|
|
<div class="rounded-2xl border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-800 dark:bg-gray-900">
|
|
<div class="text-sm font-semibold text-gray-900 dark:text-gray-100">
|
|
Decision history
|
|
</div>
|
|
|
|
@if ($selectedException->decisions->isEmpty())
|
|
<div class="mt-3 text-sm text-gray-600 dark:text-gray-300">
|
|
No decisions have been recorded yet.
|
|
</div>
|
|
@else
|
|
<div class="mt-3 space-y-3">
|
|
@foreach ($selectedException->decisions as $decision)
|
|
<div class="rounded-xl border border-gray-200 px-3 py-3 dark:border-gray-800">
|
|
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">
|
|
{{ ucfirst(str_replace('_', ' ', $decision->decision_type)) }}
|
|
</div>
|
|
<div class="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
|
{{ $decision->actor?->name ?? 'Unknown actor' }} · {{ $decision->decided_at?->toDayDateTimeString() ?? '—' }}
|
|
</div>
|
|
@if (filled($decision->reason))
|
|
<div class="mt-2 text-sm text-gray-700 dark:text-gray-300">
|
|
{{ $decision->reason }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
</x-filament::section>
|
|
@endif
|
|
</x-filament-panels::page>
|