## Summary - implement Spec 198 monitoring page-state contracts across Operations, Audit Log, Finding Exceptions Queue, Evidence Overview, Baseline Compare Landing, and Baseline Compare Matrix - align selected-record and draft/apply behavior with query/session restoration semantics, including canonical navigation and tenant-filter normalization helpers - add Spec 198 feature and browser coverage, update closure/spec artifacts, and refresh affected regression tests that asserted pre-contract behavior ## Verification - focused Spec 198 feature pack passed through Sail - Spec 198 browser smoke passed through Sail - existing Spec 190 and Spec 194 browser smokes passed through Sail - targeted fallout tests were updated and rerun during full-suite triage ## Notes - Livewire v4 / Filament v5 compliant only; no legacy API reintroduction - no provider registration changes; Laravel 11+ provider registration remains in `bootstrap/providers.php` - no global-search behavior changed for any resource - destructive queue decision actions remain confirmation-gated and authorization-backed - no new Filament assets were added; existing deploy step for `php artisan filament:assets` remains unchanged Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #238
200 lines
10 KiB
PHP
200 lines
10 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Filament\Pages\BaselineCompareLanding;
|
|
use App\Filament\Pages\BaselineCompareMatrix;
|
|
use App\Filament\Pages\Monitoring\AuditLog;
|
|
use App\Filament\Pages\Monitoring\EvidenceOverview;
|
|
use App\Filament\Pages\Monitoring\FindingExceptionsQueue;
|
|
use App\Filament\Pages\Monitoring\Operations;
|
|
use App\Models\AuditLog as AuditLogModel;
|
|
use App\Models\FindingException;
|
|
|
|
function monitoringPageStateFieldSummary(array $contract): array
|
|
{
|
|
return collect($contract['stateFields'])
|
|
->mapWithKeys(static fn (array $field): array => [
|
|
(string) $field['stateKey'] => [
|
|
'stateClass' => $field['stateClass'],
|
|
'queryRole' => $field['queryRole'],
|
|
'shareable' => $field['shareable'],
|
|
'restorableOnRefresh' => $field['restorableOnRefresh'],
|
|
],
|
|
])
|
|
->all();
|
|
}
|
|
|
|
it('declares the bounded page-state contract for each monitoring surface', function (string $pageClass, array $expected): void {
|
|
$contract = $pageClass::monitoringPageStateContract();
|
|
|
|
expect($contract['surfaceKey'])->toBe($expected['surfaceKey'])
|
|
->and($contract['surfaceType'])->toBe($expected['surfaceType'])
|
|
->and($contract['shareableStateKeys'])->toBe($expected['shareableStateKeys'])
|
|
->and($contract['localOnlyStateKeys'])->toBe($expected['localOnlyStateKeys'])
|
|
->and($contract['inspectContract'])->toMatchArray($expected['inspectContract'])
|
|
->and(monitoringPageStateFieldSummary($contract))->toEqual($expected['stateFields']);
|
|
})->with([
|
|
'operations' => [
|
|
Operations::class,
|
|
[
|
|
'surfaceKey' => 'operations',
|
|
'surfaceType' => 'simple_monitoring',
|
|
'shareableStateKeys' => ['tenant_id', 'tenant_scope', 'problemClass', 'activeTab'],
|
|
'localOnlyStateKeys' => [],
|
|
'inspectContract' => [
|
|
'primaryModel' => 'none',
|
|
'selectedStateKey' => null,
|
|
'presentation' => 'none',
|
|
'shareable' => false,
|
|
],
|
|
'stateFields' => [
|
|
'tenant_id' => ['stateClass' => 'contextual_prefilter', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'tenant_scope' => ['stateClass' => 'contextual_prefilter', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'problemClass' => ['stateClass' => 'contextual_prefilter', 'queryRole' => 'scoped_deeplink', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'activeTab' => ['stateClass' => 'active', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'tableFilters' => ['stateClass' => 'shareable_restorable', 'queryRole' => 'unsupported', 'shareable' => false, 'restorableOnRefresh' => true],
|
|
],
|
|
],
|
|
],
|
|
'audit log' => [
|
|
AuditLog::class,
|
|
[
|
|
'surfaceKey' => 'audit_log',
|
|
'surfaceType' => 'selected_record_monitoring',
|
|
'shareableStateKeys' => ['event'],
|
|
'localOnlyStateKeys' => [],
|
|
'inspectContract' => [
|
|
'primaryModel' => AuditLogModel::class,
|
|
'selectedStateKey' => 'selectedAuditLogId',
|
|
'presentation' => 'inline_detail',
|
|
'shareable' => true,
|
|
],
|
|
'stateFields' => [
|
|
'event' => ['stateClass' => 'inspect', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'tenant_id' => ['stateClass' => 'contextual_prefilter', 'queryRole' => 'durable_restorable', 'shareable' => false, 'restorableOnRefresh' => true],
|
|
'tableSearch' => ['stateClass' => 'shareable_restorable', 'queryRole' => 'unsupported', 'shareable' => false, 'restorableOnRefresh' => true],
|
|
],
|
|
],
|
|
],
|
|
'finding exceptions queue' => [
|
|
FindingExceptionsQueue::class,
|
|
[
|
|
'surfaceKey' => 'finding_exceptions_queue',
|
|
'surfaceType' => 'selected_record_monitoring',
|
|
'shareableStateKeys' => ['tenant', 'exception'],
|
|
'localOnlyStateKeys' => [],
|
|
'inspectContract' => [
|
|
'primaryModel' => FindingException::class,
|
|
'selectedStateKey' => 'selectedFindingExceptionId',
|
|
'presentation' => 'summary_plus_related_actions',
|
|
'shareable' => true,
|
|
],
|
|
'stateFields' => [
|
|
'exception' => ['stateClass' => 'inspect', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'tenant' => ['stateClass' => 'contextual_prefilter', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'tableFilters' => ['stateClass' => 'shareable_restorable', 'queryRole' => 'unsupported', 'shareable' => false, 'restorableOnRefresh' => true],
|
|
'tableSearch' => ['stateClass' => 'shareable_restorable', 'queryRole' => 'unsupported', 'shareable' => false, 'restorableOnRefresh' => true],
|
|
],
|
|
],
|
|
],
|
|
'evidence overview' => [
|
|
EvidenceOverview::class,
|
|
[
|
|
'surfaceKey' => 'evidence_overview',
|
|
'surfaceType' => 'simple_monitoring',
|
|
'shareableStateKeys' => ['tenant_id', 'search'],
|
|
'localOnlyStateKeys' => [],
|
|
'inspectContract' => [
|
|
'primaryModel' => 'none',
|
|
'selectedStateKey' => null,
|
|
'presentation' => 'navigate_to_canonical_detail',
|
|
'shareable' => false,
|
|
],
|
|
'stateFields' => [
|
|
'tenant_id' => ['stateClass' => 'contextual_prefilter', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'search' => ['stateClass' => 'contextual_prefilter', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'tableFilters' => ['stateClass' => 'shareable_restorable', 'queryRole' => 'unsupported', 'shareable' => false, 'restorableOnRefresh' => true],
|
|
'tableSort' => ['stateClass' => 'shareable_restorable', 'queryRole' => 'unsupported', 'shareable' => false, 'restorableOnRefresh' => true],
|
|
],
|
|
],
|
|
],
|
|
'baseline compare landing' => [
|
|
BaselineCompareLanding::class,
|
|
[
|
|
'surfaceKey' => 'baseline_compare_landing',
|
|
'surfaceType' => 'launch_context_support',
|
|
'shareableStateKeys' => ['baseline_profile_id', 'subject_key', 'nav'],
|
|
'localOnlyStateKeys' => [],
|
|
'inspectContract' => [
|
|
'primaryModel' => 'none',
|
|
'selectedStateKey' => null,
|
|
'presentation' => 'none',
|
|
'shareable' => true,
|
|
],
|
|
'stateFields' => [
|
|
'baseline_profile_id' => ['stateClass' => 'contextual_prefilter', 'queryRole' => 'scoped_deeplink', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'subject_key' => ['stateClass' => 'contextual_prefilter', 'queryRole' => 'scoped_deeplink', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'nav' => ['stateClass' => 'contextual_prefilter', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
],
|
|
],
|
|
],
|
|
'baseline compare matrix' => [
|
|
BaselineCompareMatrix::class,
|
|
[
|
|
'surfaceKey' => 'baseline_compare_matrix',
|
|
'surfaceType' => 'draft_apply_analysis',
|
|
'shareableStateKeys' => ['mode', 'policy_type', 'state', 'severity', 'tenant_sort', 'subject_sort', 'subject_key'],
|
|
'localOnlyStateKeys' => [
|
|
'draftSelectedPolicyTypes',
|
|
'draftSelectedStates',
|
|
'draftSelectedSeverities',
|
|
'draftTenantSort',
|
|
'draftSubjectSort',
|
|
],
|
|
'inspectContract' => [
|
|
'primaryModel' => 'baseline_subject',
|
|
'selectedStateKey' => 'focusedSubjectKey',
|
|
'presentation' => 'focused_matrix',
|
|
'shareable' => true,
|
|
],
|
|
'stateFields' => [
|
|
'mode' => ['stateClass' => 'active', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'policy_type' => ['stateClass' => 'active', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'state' => ['stateClass' => 'active', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'severity' => ['stateClass' => 'active', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'tenant_sort' => ['stateClass' => 'active', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'subject_sort' => ['stateClass' => 'active', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
'subject_key' => ['stateClass' => 'inspect', 'queryRole' => 'durable_restorable', 'shareable' => true, 'restorableOnRefresh' => true],
|
|
],
|
|
],
|
|
],
|
|
]);
|
|
|
|
it('keeps the selected-record monitoring surfaces on a single inspect identifier', function (): void {
|
|
$contracts = [
|
|
AuditLog::monitoringPageStateContract(),
|
|
FindingExceptionsQueue::monitoringPageStateContract(),
|
|
];
|
|
|
|
expect(collect($contracts)->pluck('inspectContract.selectedStateKey')->all())
|
|
->toEqual(['selectedAuditLogId', 'selectedFindingExceptionId'])
|
|
->and(collect($contracts)->pluck('inspectContract.shareable')->unique()->all())
|
|
->toEqual([true]);
|
|
});
|
|
|
|
it('keeps compare matrix draft state local while applied filters stay query-driven', function (): void {
|
|
$contract = BaselineCompareMatrix::monitoringPageStateContract();
|
|
|
|
expect($contract['surfaceType'])->toBe('draft_apply_analysis')
|
|
->and($contract['localOnlyStateKeys'])->toEqual([
|
|
'draftSelectedPolicyTypes',
|
|
'draftSelectedStates',
|
|
'draftSelectedSeverities',
|
|
'draftTenantSort',
|
|
'draftSubjectSort',
|
|
])
|
|
->and(collect($contract['shareableStateKeys'])->contains('subject_key'))->toBeTrue()
|
|
->and($contract['inspectContract']['presentation'])->toBe('focused_matrix');
|
|
});
|