TenantAtlas/apps/platform/resources/views/filament/pages/workspace-overview.blade.php
ahmido 53e799fea7 Spec 185: workspace recovery posture visibility (#216)
## Summary
- add Spec 185 workspace recovery posture visibility artifacts under `specs/185-workspace-recovery-posture-visibility`
- promote tenant backup health and recovery evidence onto the workspace overview with separate metrics, attention ordering, calmness coverage, and tenant-dashboard drill-throughs
- batch visible-tenant backup/recovery derivation to keep the workspace overview query-bounded
- align follow-up fixes from the authoritative suite rerun, including dashboard truth-alignment fixtures, canonical backup schedule tenant context, guard-path cleanup, smoke-fixture credential removal, and robust theme asset manifest handling

## Testing
- `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent`
- `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Unit/Filament/PanelThemeAssetTest.php tests/Feature/Guards/DerivedStateConsumerAdoptionGuardTest.php`
- focused regression pack for the previously failing cases passed
- full suite JUnit run passed: `3401` tests, `18849` assertions, `0` failures, `0` errors, `8` skips

## Notes
- no new schema or persisted workspace recovery model
- no provider-registration changes; Filament/Livewire stack remains on Filament v5 and Livewire v4
- no new destructive actions or global search changes

Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #216
2026-04-09 12:57:19 +00:00

118 lines
6.8 KiB
PHP

<x-filament-panels::page>
@php
$workspace = $overview['workspace'] ?? ['name' => 'Workspace'];
$quickActions = $overview['quick_actions'] ?? [];
$zeroTenantState = $overview['zero_tenant_state'] ?? null;
@endphp
<div class="space-y-6">
<x-filament::section>
<div class="space-y-2">
<div class="flex flex-wrap items-center gap-2">
<span class="inline-flex items-center gap-1.5 rounded-full border border-primary-200 bg-primary-50 px-3 py-1 text-xs font-medium text-primary-700 dark:border-primary-700/60 dark:bg-primary-950/40 dark:text-primary-300">
<x-filament::icon icon="heroicon-o-home" class="h-3.5 w-3.5" />
Workspace overview
</span>
@if (filled($workspace['slug'] ?? null))
<span class="inline-flex items-center gap-1 rounded-full border border-gray-200 bg-gray-50 px-3 py-1 text-xs font-medium text-gray-600 dark:border-white/10 dark:bg-white/5 dark:text-gray-300">
{{ $workspace['slug'] }}
</span>
@endif
</div>
<h1 class="text-2xl font-semibold tracking-tight text-gray-950 dark:text-white">
{{ $workspace['name'] ?? 'Workspace' }}
</h1>
<p class="max-w-2xl text-sm leading-6 text-gray-600 dark:text-gray-300">
This home stays workspace-scoped even when you were previously working in a tenant. Governance risk is still ranked ahead of execution noise, backup health stays separate from recovery evidence, and calm wording only appears when visible tenants are genuinely quiet across the checked domains.
</p>
</div>
</x-filament::section>
@if ($quickActions !== [])
<div class="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5">
@foreach ($quickActions as $action)
<a
href="{{ $action['url'] }}"
class="rounded-xl border border-gray-200 bg-white px-4 py-3 text-left transition hover:border-primary-300 hover:shadow-sm dark:border-white/10 dark:bg-white/5 dark:hover:border-primary-500/40 dark:hover:bg-white/10"
>
<div class="flex items-start gap-3">
<div class="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg {{ $action['color'] === 'primary' ? 'bg-primary-100 text-primary-700 dark:bg-primary-950/50 dark:text-primary-300' : 'bg-gray-100 text-gray-700 dark:bg-white/10 dark:text-gray-200' }}">
<x-filament::icon :icon="$action['icon']" class="h-5 w-5" />
</div>
<div class="min-w-0">
<div class="text-sm font-semibold text-gray-950 dark:text-white">
{{ $action['label'] }}
</div>
<div class="mt-1 text-xs leading-5 text-gray-600 dark:text-gray-300">
{{ $action['description'] }}
</div>
</div>
</div>
</a>
@endforeach
</div>
@endif
@if (is_array($zeroTenantState))
<section class="rounded-2xl border border-warning-200 bg-warning-50 p-5 shadow-sm dark:border-warning-700/50 dark:bg-warning-950/30">
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
<div class="space-y-1">
<h2 class="text-sm font-semibold text-warning-900 dark:text-warning-100">
{{ $zeroTenantState['title'] }}
</h2>
<p class="text-sm text-warning-800 dark:text-warning-200">
{{ $zeroTenantState['body'] }}
</p>
</div>
<x-filament::button
tag="a"
color="warning"
:href="$zeroTenantState['action_url']"
icon="heroicon-o-arrow-right"
>
{{ $zeroTenantState['action_label'] }}
</x-filament::button>
</div>
</section>
@endif
<div class="space-y-6">
<div class="flex flex-wrap gap-2 text-xs text-gray-600 dark:text-gray-300">
<span class="inline-flex items-center rounded-full border border-danger-200 bg-danger-50 px-3 py-1 font-medium text-danger-700 dark:border-danger-700/50 dark:bg-danger-950/30 dark:text-danger-200">
Governance risk counts affected tenants
</span>
<span class="inline-flex items-center rounded-full border border-warning-200 bg-warning-50 px-3 py-1 font-medium text-warning-700 dark:border-warning-700/50 dark:bg-warning-950/30 dark:text-warning-200">
Backup health stays separate from recovery evidence
</span>
<span class="inline-flex items-center rounded-full border border-gray-200 bg-white px-3 py-1 font-medium text-gray-600 dark:border-white/10 dark:bg-white/5 dark:text-gray-300">
Calm wording stays bounded to visible tenants and checked domains
</span>
<span class="inline-flex items-center rounded-full border border-gray-200 bg-white px-3 py-1 font-medium text-gray-600 dark:border-white/10 dark:bg-white/5 dark:text-gray-300">
Recent operations stay diagnostic
</span>
</div>
@livewire(\App\Filament\Widgets\Workspace\WorkspaceSummaryStats::class, [
'metrics' => $overview['summary_metrics'] ?? [],
], key('workspace-overview-summary-' . ($workspace['id'] ?? 'none')))
<div class="grid grid-cols-1 gap-6 xl:grid-cols-2">
@livewire(\App\Filament\Widgets\Workspace\WorkspaceNeedsAttention::class, [
'items' => $overview['attention_items'] ?? [],
'emptyState' => $overview['attention_empty_state'] ?? [],
], key('workspace-overview-attention-' . ($workspace['id'] ?? 'none')))
@livewire(\App\Filament\Widgets\Workspace\WorkspaceRecentOperations::class, [
'operations' => $overview['recent_operations'] ?? [],
'emptyState' => $overview['recent_operations_empty_state'] ?? [],
], key('workspace-overview-operations-' . ($workspace['id'] ?? 'none')))
</div>
</div>
</div>
</x-filament-panels::page>