## Summary - add the Spec 181 restore-safety layer with scope fingerprinting, preview/check integrity states, execution safety snapshots, result attention, and operator-facing copy across the wizard, restore detail, and canonical operation detail - add focused unit and feature coverage for restore-safety assessment, result attention, and restore-linked operation detail - switch the finding exceptions queue `Inspect exception` action to a native Filament slide-over while preserving query-param-backed inline summary behavior ## Testing - `vendor/bin/sail artisan test --compact tests/Feature/Monitoring/FindingExceptionsQueueTest.php tests/Feature/Filament/RestoreSafetyIntegrityWizardTest.php tests/Feature/Filament/RestoreResultAttentionSurfaceTest.php tests/Feature/Operations/RestoreLinkedOperationDetailTest.php tests/Unit/Support/RestoreSafety` ## Notes - Spec 181 checklist is complete (`specs/181-restore-safety-integrity/checklists/requirements.md`) - the branch still has unchecked follow-up tasks in `specs/181-restore-safety-integrity/tasks.md`: `T012`, `T018`, `T019`, `T023`, `T025`, `T029`, `T032`, `T033`, `T041`, `T042`, `T043`, `T044` - Filament v5 / Livewire v4 compliance is preserved, no panel provider registration changes were made, no global-search behavior was added, destructive actions remain confirmation-gated, and no new Filament assets were introduced Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #210
110 lines
5.4 KiB
PHP
110 lines
5.4 KiB
PHP
<div data-testid="finding-exception-slide-over" class="grid gap-4">
|
|
<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 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> |