## Summary - codify Spec 193 as an explicit monitoring/workbench surface inventory with validator and guard coverage - refactor the Finding Exceptions Queue, Operations landing, and tenantless operation viewer into clearer context, navigation, utility, drilldown, and focused-work lanes - align Alerts, Audit Log, and Alert Deliveries with quiet origin-context handling while preserving calm reference surfaces and the explicit Tenant Diagnostics exception - add focused feature coverage, guard coverage, browser smoke coverage, and the full spec artifacts for Spec 193 ## Verification - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Guards/ActionSurfaceContractTest.php tests/Feature/Guards/ActionSurfaceValidatorTest.php tests/Feature/Guards/Spec193MonitoringSurfaceHierarchyGuardTest.php tests/Feature/OpsUx/OperateHubShellTest.php tests/Feature/Operations/TenantlessOperationRunViewerTest.php tests/Feature/Monitoring/FindingExceptionsQueueHierarchyTest.php tests/Browser/Spec193MonitoringSurfaceHierarchySmokeTest.php` - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - integrated-browser smoke pass over queue, operations, operation detail, alerts, audit log, and tenant diagnostics ## Notes - Livewire v4 / Filament v5 stack unchanged - no provider-registration changes; Laravel 11+ provider registration remains in `bootstrap/providers.php` - no new global-search behavior was introduced - destructive and governance-changing actions keep their existing confirmation and authorization semantics - no new assets or migrations were added Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #227
122 lines
7.0 KiB
PHP
122 lines
7.0 KiB
PHP
@php
|
|
$contextBanner = $this->canonicalContextBanner();
|
|
$blockedBanner = $this->blockedExecutionBanner();
|
|
$lifecycleBanner = $this->lifecycleBanner();
|
|
$restoreContinuationBanner = $this->restoreContinuationBanner();
|
|
$monitoringDetail = $this->monitoringDetailSummary();
|
|
$pollInterval = $this->pollInterval();
|
|
@endphp
|
|
|
|
<x-filament-panels::page>
|
|
<div
|
|
@if ($pollInterval !== null) wire:poll.{{ $pollInterval }} @endif
|
|
>
|
|
<x-filament::section heading="Monitoring detail" class="mb-6">
|
|
<p class="text-sm text-gray-600 dark:text-gray-400">
|
|
Scope context, return navigation, utility, related drilldowns, and run-specific follow-up stay in separate lanes on this viewer.
|
|
</p>
|
|
|
|
<div class="mt-4 grid gap-4 md:grid-cols-2 xl:grid-cols-5">
|
|
<div class="rounded-xl border border-gray-200 bg-white/80 p-4 dark:border-white/10 dark:bg-white/5">
|
|
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-gray-500 dark:text-gray-400">Scope context</p>
|
|
<p class="mt-2 text-sm font-semibold text-gray-900 dark:text-white">{{ $monitoringDetail['scope_label'] }}</p>
|
|
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">{{ $monitoringDetail['scope_body'] }}</p>
|
|
</div>
|
|
|
|
<div class="rounded-xl border border-gray-200 bg-white/80 p-4 dark:border-white/10 dark:bg-white/5">
|
|
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-gray-500 dark:text-gray-400">Navigation lane</p>
|
|
<p class="mt-2 text-sm font-semibold text-gray-900 dark:text-white">{{ $monitoringDetail['navigation_label'] }}</p>
|
|
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">{{ $monitoringDetail['navigation_body'] }}</p>
|
|
</div>
|
|
|
|
<div class="rounded-xl border border-gray-200 bg-white/80 p-4 dark:border-white/10 dark:bg-white/5">
|
|
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-gray-500 dark:text-gray-400">Utility lane</p>
|
|
<p class="mt-2 text-sm font-semibold text-gray-900 dark:text-white">Refresh</p>
|
|
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">{{ $monitoringDetail['utility_body'] }}</p>
|
|
</div>
|
|
|
|
<div class="rounded-xl border border-gray-200 bg-white/80 p-4 dark:border-white/10 dark:bg-white/5">
|
|
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-gray-500 dark:text-gray-400">Related drilldown</p>
|
|
<p class="mt-2 text-sm font-semibold text-gray-900 dark:text-white">Open</p>
|
|
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">{{ $monitoringDetail['related_body'] }}</p>
|
|
</div>
|
|
|
|
<div class="rounded-xl border border-gray-200 bg-white/80 p-4 dark:border-white/10 dark:bg-white/5">
|
|
<p class="text-xs font-semibold uppercase tracking-[0.2em] text-gray-500 dark:text-gray-400">Follow-up lane</p>
|
|
<p class="mt-2 text-sm font-semibold text-gray-900 dark:text-white">{{ $monitoringDetail['follow_up_label'] ?? 'No follow-up action' }}</p>
|
|
<p class="mt-2 text-sm text-gray-600 dark:text-gray-400">{{ $monitoringDetail['follow_up_body'] }}</p>
|
|
</div>
|
|
</div>
|
|
</x-filament::section>
|
|
|
|
@if ($contextBanner !== null)
|
|
@php
|
|
$bannerClasses = match ($contextBanner['tone']) {
|
|
'amber' => 'border-amber-200 bg-amber-50 text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-100',
|
|
'slate' => 'border-slate-200 bg-slate-50 text-slate-900 dark:border-slate-500/30 dark:bg-slate-500/10 dark:text-slate-100',
|
|
default => 'border-sky-200 bg-sky-50 text-sky-900 dark:border-sky-500/30 dark:bg-sky-500/10 dark:text-sky-100',
|
|
};
|
|
@endphp
|
|
|
|
<div class="mb-6 rounded-lg border px-4 py-3 text-sm {{ $bannerClasses }}">
|
|
<p class="font-semibold">{{ $contextBanner['title'] }}</p>
|
|
<p class="mt-1">{{ $contextBanner['body'] }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
@if ($blockedBanner !== null)
|
|
@php
|
|
$blockedBannerClasses = 'border-amber-200 bg-amber-50 text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-100';
|
|
@endphp
|
|
|
|
<div class="mb-6 rounded-lg border px-4 py-3 text-sm {{ $blockedBannerClasses }}">
|
|
<p class="font-semibold">{{ $blockedBanner['title'] }}</p>
|
|
<p class="mt-1">{{ $blockedBanner['body'] }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
@if ($lifecycleBanner !== null)
|
|
@php
|
|
$lifecycleBannerClasses = match ($lifecycleBanner['tone']) {
|
|
'rose' => 'border-rose-200 bg-rose-50 text-rose-900 dark:border-rose-500/30 dark:bg-rose-500/10 dark:text-rose-100',
|
|
default => 'border-amber-200 bg-amber-50 text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-100',
|
|
};
|
|
@endphp
|
|
|
|
<div class="mb-6 rounded-lg border px-4 py-3 text-sm {{ $lifecycleBannerClasses }}">
|
|
<p class="font-semibold">{{ $lifecycleBanner['title'] }}</p>
|
|
<p class="mt-1">{{ $lifecycleBanner['body'] }}</p>
|
|
</div>
|
|
@endif
|
|
|
|
@if ($restoreContinuationBanner !== null)
|
|
@php
|
|
$restoreContinuationClasses = match ($restoreContinuationBanner['tone']) {
|
|
'amber' => 'border-amber-200 bg-amber-50 text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-100',
|
|
default => 'border-sky-200 bg-sky-50 text-sky-900 dark:border-sky-500/30 dark:bg-sky-500/10 dark:text-sky-100',
|
|
};
|
|
@endphp
|
|
|
|
<div class="mb-6 rounded-lg border px-4 py-3 text-sm {{ $restoreContinuationClasses }}">
|
|
<p class="font-semibold">{{ $restoreContinuationBanner['title'] }}</p>
|
|
<p class="mt-1">{{ $restoreContinuationBanner['body'] }}</p>
|
|
@if ($restoreContinuationBanner['url'] !== null && $restoreContinuationBanner['link_label'] !== null)
|
|
<p class="mt-3">
|
|
<a href="{{ $restoreContinuationBanner['url'] }}" class="font-semibold underline underline-offset-2">
|
|
{{ $restoreContinuationBanner['link_label'] }}
|
|
</a>
|
|
</p>
|
|
@endif
|
|
</div>
|
|
@endif
|
|
|
|
@if ($this->redactionIntegrityNote())
|
|
<div class="mb-6 rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-900 dark:border-amber-500/30 dark:bg-amber-500/10 dark:text-amber-100">
|
|
{{ $this->redactionIntegrityNote() }}
|
|
</div>
|
|
@endif
|
|
|
|
{{ $this->infolist }}
|
|
</div>
|
|
</x-filament-panels::page>
|