## 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
74 lines
3.1 KiB
PHP
74 lines
3.1 KiB
PHP
<div
|
|
@if ($pollingInterval)
|
|
wire:poll.{{ $pollingInterval }}
|
|
@endif
|
|
>
|
|
<x-filament::section>
|
|
<x-slot name="heading">
|
|
<span class="flex items-center gap-2">
|
|
<x-filament::icon
|
|
icon="heroicon-m-shield-check"
|
|
class="h-5 w-5 text-gray-400 dark:text-gray-500"
|
|
/>
|
|
Recovery Readiness
|
|
</span>
|
|
</x-slot>
|
|
|
|
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
@foreach ([$backupPosture, $recoveryEvidence] as $stat)
|
|
@php
|
|
$colorClasses = match ($stat['color']) {
|
|
'danger' => 'border-danger-300 dark:border-danger-700',
|
|
'warning' => 'border-warning-300 dark:border-warning-700',
|
|
'success' => 'border-success-300 dark:border-success-700',
|
|
'info' => 'border-info-300 dark:border-info-700',
|
|
default => 'border-gray-200 dark:border-white/10',
|
|
};
|
|
$valueColorClasses = match ($stat['color']) {
|
|
'danger' => 'text-danger-600 dark:text-danger-400',
|
|
'warning' => 'text-warning-600 dark:text-warning-400',
|
|
'success' => 'text-success-600 dark:text-success-400',
|
|
'info' => 'text-info-600 dark:text-info-400',
|
|
default => 'text-gray-950 dark:text-white',
|
|
};
|
|
$descriptionColorClasses = match ($stat['color']) {
|
|
'danger' => 'text-danger-600 dark:text-danger-400',
|
|
'warning' => 'text-warning-600 dark:text-warning-400',
|
|
'success' => 'text-success-600 dark:text-success-400',
|
|
default => 'text-gray-600 dark:text-gray-300',
|
|
};
|
|
@endphp
|
|
|
|
@if ($stat['url'])
|
|
<a
|
|
href="{{ $stat['url'] }}"
|
|
class="{{ $colorClasses }} block rounded-xl border-l-4 bg-white p-5 shadow-sm transition hover:shadow-md dark:bg-gray-900"
|
|
>
|
|
@else
|
|
<div class="{{ $colorClasses }} rounded-xl border-l-4 bg-white p-5 shadow-sm dark:bg-gray-900">
|
|
@endif
|
|
|
|
<div class="text-sm font-medium text-gray-500 dark:text-gray-400">
|
|
{{ $stat['label'] }}
|
|
</div>
|
|
|
|
<div class="{{ $valueColorClasses }} mt-1 text-2xl font-bold tracking-tight">
|
|
{{ $stat['value'] }}
|
|
</div>
|
|
|
|
@if (filled($stat['description']))
|
|
<div class="{{ $descriptionColorClasses }} mt-2 text-sm leading-relaxed">
|
|
{{ $stat['description'] }}
|
|
</div>
|
|
@endif
|
|
|
|
@if ($stat['url'])
|
|
</a>
|
|
@else
|
|
</div>
|
|
@endif
|
|
@endforeach
|
|
</div>
|
|
</x-filament::section>
|
|
</div>
|