## Summary
- implement Spec 179 to make tenant lifecycle, provider consent, and provider verification the primary truth axes on the targeted Filament surfaces
- demote legacy tenant app status and legacy provider status and health to diagnostic-only roles, add centralized badge mappings for provider consent and verification, and keep provider connections excluded from global search
- add the full Spec 179 artifact set under `specs/179-provider-truth-cleanup/` plus focused Pest coverage for tenant truth cleanup, provider truth cleanup, RBAC, discovery safety, and badge semantics
- fix the numeric out-of-scope tenant route regression so inaccessible `/admin/tenants/{id}` paths return `404 Not Found` instead of `500`
## Testing
- `vendor/bin/sail artisan test --compact tests/Feature/Filament/TenantLifecycleStatusDomainSeparationTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Filament/TenantTruthCleanupSpec179Test.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Filament/ProviderConnectionsDbOnlyTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections/ProviderConnectionTruthCleanupSpec179Test.php`
- `vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections/RequiredFiltersTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Tenants/TenantProviderConnectionsCtaTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Rbac/TenantResourceAuthorizationTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections/ProviderConnectionListAuthorizationTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/ProviderConnections/ProviderConnectionAuthorizationTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Rbac/AdminGlobalSearchContextSafetyTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Filament/TenantGlobalSearchLifecycleScopeTest.php`
- `vendor/bin/sail artisan test --compact tests/Feature/Filament/TenantScopingTest.php`
- `vendor/bin/sail artisan test --compact tests/Unit/Badges/TenantBadgesTest.php`
- `vendor/bin/sail artisan test --compact tests/Unit/Badges/ProviderConnectionBadgesTest.php`
## Manual validation
- integrated-browser smoke on `/admin/tenants`, tenant detail, `/admin/provider-connections`, provider detail, and provider edit
- verified out-of-scope tenant and provider URLs return `404 Not Found` with the current session
## Notes
- branch: `179-provider-truth-cleanup`
- commit: `e54c6632`
- target: `dev`
Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de>
Reviewed-on: #207
106 lines
5.5 KiB
PHP
106 lines
5.5 KiB
PHP
@php
|
|
$state = $getState();
|
|
$state = is_array($state) ? $state : [];
|
|
|
|
$connectionState = is_string($state['state'] ?? null) ? (string) $state['state'] : 'missing';
|
|
$ctaUrl = is_string($state['cta_url'] ?? null) ? (string) $state['cta_url'] : '#';
|
|
$needsDefaultConnection = (bool) ($state['needs_default_connection'] ?? false);
|
|
|
|
$displayName = is_string($state['display_name'] ?? null) ? (string) $state['display_name'] : null;
|
|
$provider = is_string($state['provider'] ?? null) ? (string) $state['provider'] : null;
|
|
$consentStatus = is_string($state['consent_status'] ?? null) ? (string) $state['consent_status'] : null;
|
|
$verificationStatus = is_string($state['verification_status'] ?? null) ? (string) $state['verification_status'] : null;
|
|
$status = is_string($state['status'] ?? null) ? (string) $state['status'] : null;
|
|
$healthStatus = is_string($state['health_status'] ?? null) ? (string) $state['health_status'] : null;
|
|
$lastCheck = is_string($state['last_health_check_at'] ?? null) ? (string) $state['last_health_check_at'] : null;
|
|
$lastErrorReason = is_string($state['last_error_reason_code'] ?? null) ? (string) $state['last_error_reason_code'] : null;
|
|
|
|
$isMissing = $connectionState === 'missing';
|
|
$consentSpec = \App\Support\Badges\BadgeRenderer::spec(\App\Support\Badges\BadgeDomain::ProviderConsentStatus, $consentStatus);
|
|
$verificationSpec = \App\Support\Badges\BadgeRenderer::spec(\App\Support\Badges\BadgeDomain::ProviderVerificationStatus, $verificationStatus);
|
|
$legacyStatusSpec = \App\Support\Badges\BadgeRenderer::spec(\App\Support\Badges\BadgeDomain::ProviderConnectionStatus, $status);
|
|
$legacyHealthSpec = \App\Support\Badges\BadgeRenderer::spec(\App\Support\Badges\BadgeDomain::ProviderConnectionHealth, $healthStatus);
|
|
@endphp
|
|
|
|
<div class="space-y-3 rounded-md border border-gray-200 bg-white p-4 shadow-sm">
|
|
<div class="flex items-start justify-between gap-4">
|
|
<div>
|
|
<div class="text-sm font-semibold text-gray-800">Provider connection</div>
|
|
@if ($isMissing)
|
|
<div class="mt-1 text-sm text-amber-700">Needs action: no Microsoft provider connection is configured.</div>
|
|
@elseif ($needsDefaultConnection)
|
|
<div class="mt-1 text-sm text-amber-700">Needs action: set a default Microsoft provider connection.</div>
|
|
@else
|
|
<div class="mt-1 text-sm text-gray-700">{{ $displayName ?? 'Unnamed connection' }}</div>
|
|
@endif
|
|
</div>
|
|
|
|
<a href="{{ $ctaUrl }}" class="inline-flex items-center rounded-md border border-gray-300 px-3 py-1.5 text-xs font-medium text-gray-700 hover:bg-gray-50">
|
|
Open Provider Connections
|
|
</a>
|
|
</div>
|
|
|
|
@unless ($isMissing)
|
|
@if ($needsDefaultConnection && $displayName)
|
|
<div class="text-sm text-gray-700">
|
|
Current connection: <span class="font-medium">{{ $displayName }}</span>
|
|
</div>
|
|
@endif
|
|
|
|
<dl class="grid grid-cols-1 gap-2 text-sm text-gray-700 sm:grid-cols-2">
|
|
<div>
|
|
<dt class="text-xs uppercase tracking-wide text-gray-500">Provider</dt>
|
|
<dd>{{ $provider ?? 'n/a' }}</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="text-xs uppercase tracking-wide text-gray-500">Consent</dt>
|
|
<dd>
|
|
<x-filament::badge :color="$consentSpec->color" :icon="$consentSpec->icon" size="sm">
|
|
{{ $consentSpec->label }}
|
|
</x-filament::badge>
|
|
</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="text-xs uppercase tracking-wide text-gray-500">Verification</dt>
|
|
<dd>
|
|
<x-filament::badge :color="$verificationSpec->color" :icon="$verificationSpec->icon" size="sm">
|
|
{{ $verificationSpec->label }}
|
|
</x-filament::badge>
|
|
</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="text-xs uppercase tracking-wide text-gray-500">Last check</dt>
|
|
<dd>{{ $lastCheck ?? 'n/a' }}</dd>
|
|
</div>
|
|
</dl>
|
|
|
|
<div class="space-y-2 rounded-md border border-gray-200 bg-gray-50 p-3 text-sm text-gray-700">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-gray-500">Diagnostics</div>
|
|
<dl class="grid grid-cols-1 gap-2 sm:grid-cols-2">
|
|
<div>
|
|
<dt class="text-xs uppercase tracking-wide text-gray-500">Legacy status</dt>
|
|
<dd>
|
|
<x-filament::badge :color="$legacyStatusSpec->color" :icon="$legacyStatusSpec->icon" size="sm">
|
|
{{ $legacyStatusSpec->label }}
|
|
</x-filament::badge>
|
|
</dd>
|
|
</div>
|
|
<div>
|
|
<dt class="text-xs uppercase tracking-wide text-gray-500">Legacy health</dt>
|
|
<dd>
|
|
<x-filament::badge :color="$legacyHealthSpec->color" :icon="$legacyHealthSpec->icon" size="sm">
|
|
{{ $legacyHealthSpec->label }}
|
|
</x-filament::badge>
|
|
</dd>
|
|
</div>
|
|
</dl>
|
|
|
|
@if ($lastErrorReason)
|
|
<div class="rounded-md border border-amber-300 bg-amber-50 p-2 text-xs text-amber-800">
|
|
Last error reason: {{ $lastErrorReason }}
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@endunless
|
|
</div>
|