TenantAtlas/apps/platform/resources/views/filament/widgets/dashboard/needs-attention.blade.php
ahmido f1a73490e4 feat: finalize dashboard recovery honesty (#215)
## Summary
- add a dedicated Recovery Readiness dashboard widget for backup posture and recovery evidence
- group Needs Attention items by domain and elevate the recovery call-to-action
- align restore-run and recovery posture tests with the extracted widget and continuity flows
- include the related spec artifacts for 184-dashboard-recovery-honesty

## Verification
- `cd /Users/ahmeddarrazi/Documents/projects/TenantAtlas/apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
- `cd /Users/ahmeddarrazi/Documents/projects/TenantAtlas/apps/platform && ./vendor/bin/sail artisan test --compact --filter="DashboardKpisWidget|DashboardRecoveryPosture|TenantDashboardDbOnly|TenantpilotSeedBackupHealthBrowserFixtureCommand|NeedsAttentionWidget"`
- browser smoke verified on the calm, unvalidated, and weakened dashboard states

## Notes
- Livewire v4.0+ compliant with Filament v5
- no panel provider changes; Laravel 11+ provider registration remains in `bootstrap/providers.php`
- Recovery Readiness stays within the existing tenant dashboard asset strategy; no new Filament asset registration required

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #215
2026-04-08 23:21:36 +00:00

98 lines
5.4 KiB
PHP

<div
@if ($pollingInterval)
wire:poll.{{ $pollingInterval }}
@endif
>
<x-filament::section heading="Needs Attention">
@if (count($items) === 0)
<div class="flex flex-col gap-3">
<div class="text-sm text-gray-600 dark:text-gray-300">
Current governance and findings signals look trustworthy.
</div>
<div class="flex flex-col gap-3">
@foreach ($healthyChecks as $check)
<div class="flex items-start gap-3 rounded-lg bg-gray-50 p-4 dark:bg-white/5">
<x-filament::icon
icon="heroicon-m-check-circle"
class="mt-0.5 h-5 w-5 text-success-600 dark:text-success-400"
/>
<div class="flex-1">
<div class="text-sm font-medium text-gray-950 dark:text-white">{{ $check['title'] }}</div>
<div class="mt-0.5 text-sm text-gray-600 dark:text-gray-300">{{ $check['body'] }}</div>
</div>
</div>
@endforeach
</div>
</div>
@else
@php
$domainOrder = ['Recovery', 'Backups', 'Governance', 'Findings', 'Baseline', 'Operations'];
$grouped = collect($items)->groupBy('badge')->sortBy(fn ($group, $badge) => array_search($badge, $domainOrder, true) !== false ? array_search($badge, $domainOrder, true) : 999);
@endphp
<div class="flex flex-col gap-5">
@foreach ($grouped as $domain => $domainItems)
<div class="flex flex-col gap-3">
<div class="text-xs font-semibold uppercase tracking-wider text-gray-500 dark:text-gray-400">
{{ $domain }}
</div>
@foreach ($domainItems as $item)
<div class="rounded-lg bg-gray-50 p-4 dark:bg-white/5">
<div class="flex items-start justify-between gap-3">
<div class="min-w-0 flex-1">
<div class="text-sm font-semibold text-gray-950 dark:text-white">{{ $item['title'] }}</div>
<div class="mt-1 text-sm text-gray-600 dark:text-gray-300">{{ $item['body'] }}</div>
@if (filled($item['supportingMessage'] ?? null))
<div class="mt-1 text-sm text-gray-600 dark:text-gray-300">
{{ $item['supportingMessage'] }}
</div>
@endif
@if (filled($item['actionLabel'] ?? null))
<div class="mt-3">
@if (($item['actionElevated'] ?? false) && filled($item['actionUrl'] ?? null))
<x-filament::button
tag="a"
:href="$item['actionUrl']"
size="sm"
:color="$item['badgeColor'] ?? 'primary'"
outlined
>
{{ $item['actionLabel'] }}
</x-filament::button>
@elseif (filled($item['actionUrl'] ?? null))
<x-filament::link :href="$item['actionUrl']" size="sm" class="font-medium">
{{ $item['actionLabel'] }}
</x-filament::link>
@else
<div class="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">
{{ $item['actionLabel'] }}
</div>
@endif
</div>
@endif
@if (filled($item['helperText'] ?? null))
<div class="mt-1 text-xs text-gray-500 dark:text-gray-400">
{{ $item['helperText'] }}
</div>
@endif
</div>
<x-filament::badge :color="$item['badgeColor']" size="sm">
{{ $item['badge'] }}
</x-filament::badge>
</div>
</div>
@endforeach
</div>
@endforeach
</div>
@endif
</x-filament::section>
</div>