## Summary - replace the remaining workspace overview tenant-first copy with environment-first wording in the builder, Blade view, and focused feature assertions - add the Spec 299 workspace overview browser smoke and the final cutover audit documenting fixed copy, clean runtime scans, and allowed internal/provider/regression-guard `Tenant` references - add the Spec 299 spec package (`spec.md`, `plan.md`, `tasks.md`, checklist, audit) to close the managed-environment cutover with an explicit final seal decision ## Validation - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/WorkspaceOverviewContentTest.php tests/Feature/Filament/AdminHomeRedirectsToChooseTenantWhenWorkspaceSelectedTest.php tests/Feature/Filament/WorkspaceOverviewEmptyStatesTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards/NoLegacyTenantPanelRuntimeTest.php tests/Feature/Guards/NoActiveTenantResourceRoutesTest.php tests/Feature/Guards/ManagedEnvironmentCanonicalRouteContractTest.php tests/Feature/Filament/PanelNavigationSegregationTest.php tests/Feature/Workspaces/WorkspaceIntendedUrlLegacyRejectionTest.php tests/Feature/ProviderConnections/LegacyRedirectTest.php tests/Feature/ManagedEnvironment/LegacyTenantCoreGuardTest.php tests/Feature/Spec080WorkspaceManagedTenantAdminMigrationTest.php tests/Feature/Filament/ManagedEnvironmentAccessScopeManagementTest.php tests/Feature/Rbac/ProviderConnectionWorkspaceFirstPolicyTest.php` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Workspaces` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/RequiredPermissions` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament` - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Browser/Spec299WorkspaceOverviewCutoverSealSmokeTest.php` - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - `git diff --check` ## Notes - Filament remains on Livewire v4. - Provider registration remains in `apps/platform/bootstrap/providers.php`. - No new panel provider or asset-strategy changes are included. - Remaining technical `Tenant` references are documented in `specs/299-managed-environment-cutover-final-seal/final-cutover-audit.md`. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #354
210 lines
14 KiB
PHP
210 lines
14 KiB
PHP
<x-filament-panels::page>
|
|
@php
|
|
$workspace = $overview['workspace'] ?? ['name' => 'Workspace'];
|
|
$quickActions = $overview['quick_actions'] ?? [];
|
|
$myFindingsSignal = $overview['my_findings_signal'] ?? null;
|
|
$findingsHygieneSignal = $overview['findings_hygiene_signal'] ?? null;
|
|
$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 an environment. Governance risk is still ranked ahead of execution noise, backup health stays separate from recovery evidence, and calm wording only appears when visible environments 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($myFindingsSignal))
|
|
<section class="rounded-2xl border border-gray-200 bg-white p-5 shadow-sm dark:border-white/10 dark:bg-white/5">
|
|
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
|
|
<div class="space-y-3">
|
|
<div class="inline-flex w-fit items-center gap-2 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-clipboard-document-check" class="h-3.5 w-3.5" />
|
|
Assigned to me
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<h2 class="text-base font-semibold text-gray-950 dark:text-white">
|
|
{{ $myFindingsSignal['headline'] }}
|
|
</h2>
|
|
<p class="max-w-2xl text-sm leading-6 text-gray-600 dark:text-gray-300">
|
|
{{ $myFindingsSignal['description'] }}
|
|
</p>
|
|
</div>
|
|
|
|
<div class="flex flex-wrap gap-2 text-xs">
|
|
<span class="inline-flex items-center rounded-full border border-gray-200 bg-gray-50 px-3 py-1 font-medium text-gray-700 dark:border-white/10 dark:bg-white/5 dark:text-gray-300">
|
|
Open assigned: {{ $myFindingsSignal['open_assigned_count'] }}
|
|
</span>
|
|
<span class="inline-flex items-center rounded-full border px-3 py-1 font-medium {{ ($myFindingsSignal['overdue_assigned_count'] ?? 0) > 0 ? 'border-danger-200 bg-danger-50 text-danger-700 dark:border-danger-700/50 dark:bg-danger-950/30 dark:text-danger-200' : 'border-success-200 bg-success-50 text-success-700 dark:border-success-700/50 dark:bg-success-950/30 dark:text-success-200' }}">
|
|
Overdue: {{ $myFindingsSignal['overdue_assigned_count'] }}
|
|
</span>
|
|
<span class="inline-flex items-center rounded-full border px-3 py-1 font-medium {{ ($myFindingsSignal['is_calm'] ?? false) ? 'border-success-200 bg-success-50 text-success-700 dark:border-success-700/50 dark:bg-success-950/30 dark:text-success-200' : 'border-warning-200 bg-warning-50 text-warning-700 dark:border-warning-700/50 dark:bg-warning-950/30 dark:text-warning-200' }}">
|
|
{{ ($myFindingsSignal['is_calm'] ?? false) ? 'Calm' : 'Needs follow-up' }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<x-filament::button
|
|
tag="a"
|
|
color="primary"
|
|
:href="$myFindingsSignal['cta_url']"
|
|
icon="heroicon-o-arrow-right"
|
|
>
|
|
{{ $myFindingsSignal['cta_label'] }}
|
|
</x-filament::button>
|
|
</div>
|
|
</section>
|
|
@endif
|
|
|
|
@if (is_array($findingsHygieneSignal))
|
|
<section class="rounded-2xl border border-gray-200 bg-white p-5 shadow-sm dark:border-white/10 dark:bg-white/5">
|
|
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
|
|
<div class="space-y-3">
|
|
<div class="inline-flex w-fit items-center gap-2 rounded-full border border-danger-200 bg-danger-50 px-3 py-1 text-xs font-medium text-danger-700 dark:border-danger-700/60 dark:bg-danger-950/40 dark:text-danger-200">
|
|
<x-filament::icon icon="heroicon-o-wrench-screwdriver" class="h-3.5 w-3.5" />
|
|
Findings hygiene
|
|
</div>
|
|
|
|
<div class="space-y-1">
|
|
<h2 class="text-base font-semibold text-gray-950 dark:text-white">
|
|
{{ $findingsHygieneSignal['headline'] }}
|
|
</h2>
|
|
<p class="max-w-2xl text-sm leading-6 text-gray-600 dark:text-gray-300">
|
|
{{ $findingsHygieneSignal['description'] }}
|
|
</p>
|
|
</div>
|
|
|
|
<div class="flex flex-wrap gap-2 text-xs">
|
|
<span class="inline-flex items-center rounded-full border border-gray-200 bg-gray-50 px-3 py-1 font-medium text-gray-700 dark:border-white/10 dark:bg-white/5 dark:text-gray-300">
|
|
Unique issues: {{ $findingsHygieneSignal['unique_issue_count'] }}
|
|
</span>
|
|
<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">
|
|
Broken assignments: {{ $findingsHygieneSignal['broken_assignment_count'] }}
|
|
</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">
|
|
Stale in progress: {{ $findingsHygieneSignal['stale_in_progress_count'] }}
|
|
</span>
|
|
<span class="inline-flex items-center rounded-full border px-3 py-1 font-medium {{ ($findingsHygieneSignal['is_calm'] ?? false) ? 'border-success-200 bg-success-50 text-success-700 dark:border-success-700/50 dark:bg-success-950/30 dark:text-success-200' : 'border-warning-200 bg-warning-50 text-warning-700 dark:border-warning-700/50 dark:bg-warning-950/30 dark:text-warning-200' }}">
|
|
{{ ($findingsHygieneSignal['is_calm'] ?? false) ? 'Calm' : 'Needs repair' }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<x-filament::button
|
|
tag="a"
|
|
color="danger"
|
|
:href="$findingsHygieneSignal['cta_url']"
|
|
icon="heroicon-o-arrow-right"
|
|
>
|
|
{{ $findingsHygieneSignal['cta_label'] }}
|
|
</x-filament::button>
|
|
</div>
|
|
</section>
|
|
@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 environments
|
|
</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 environments 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'] ?? [],
|
|
'triageReviewProgress' => $overview['triage_review_progress'] ?? [],
|
|
], 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>
|