fix: refine monitoring drilldowns and review filters

This commit is contained in:
Ahmed Darrazi 2026-04-12 12:44:16 +02:00
parent 8475d85bc8
commit 67081b0c6e
4 changed files with 117 additions and 5 deletions

View File

@ -584,9 +584,16 @@ private function relatedLinks(bool $fresh = false): array
$resolver = app(RelatedNavigationResolver::class); $resolver = app(RelatedNavigationResolver::class);
return $fresh $links = $fresh
? $resolver->operationLinksFresh($this->run, $this->relatedLinksTenant()) ? $resolver->operationLinksFresh($this->run, $this->relatedLinksTenant())
: $resolver->operationLinks($this->run, $this->relatedLinksTenant()); : $resolver->operationLinks($this->run, $this->relatedLinksTenant());
unset(
$links[OperationRunLinks::collectionLabel()],
$links[OperationRunLinks::openCollectionLabel()],
);
return $links;
} }
private function lifecycleAttentionSummary(bool $fresh = false): ?string private function lifecycleAttentionSummary(bool $fresh = false): ?string

View File

@ -94,7 +94,7 @@ protected function getHeaderActions(): array
->color('gray') ->color('gray')
->visible(fn (): bool => $this->hasActiveFilters()) ->visible(fn (): bool => $this->hasActiveFilters())
->action(function (): void { ->action(function (): void {
$this->resetTable(); $this->clearRegisterFilters();
}), }),
]; ];
} }
@ -209,7 +209,7 @@ public function table(Table $table): Table
->label('Clear filters') ->label('Clear filters')
->icon('heroicon-o-x-mark') ->icon('heroicon-o-x-mark')
->color('gray') ->color('gray')
->action(fn (): mixed => $this->resetTable()), ->action(fn (): mixed => $this->clearRegisterFilters()),
]); ]);
} }
@ -311,9 +311,29 @@ private function applyRequestedTenantPrefilter(): void
private function hasActiveFilters(): bool private function hasActiveFilters(): bool
{ {
$filters = array_filter((array) $this->tableFilters); return $this->currentTenantFilterId() !== null
|| is_string(data_get($this->tableFilters, 'status.value'))
|| is_string(data_get($this->tableFilters, 'completeness_state.value'))
|| is_string(data_get($this->tableFilters, 'published_state.value'))
|| filled(data_get($this->tableFilters, 'review_date.from'))
|| filled(data_get($this->tableFilters, 'review_date.until'));
}
return $filters !== []; private function clearRegisterFilters(): void
{
app(WorkspaceContext::class)->clearLastTenantId(request());
$this->removeTableFilters();
}
private function currentTenantFilterId(): ?int
{
$tenantFilter = data_get($this->tableFilters, 'tenant_id.value');
if (! is_numeric($tenantFilter)) {
$tenantFilter = data_get(session()->get($this->getTableFiltersSessionKey(), []), 'tenant_id.value');
}
return is_numeric($tenantFilter) ? (int) $tenantFilter : null;
} }
private function workspace(): ?Workspace private function workspace(): ?Workspace

View File

@ -2,6 +2,9 @@
declare(strict_types=1); declare(strict_types=1);
use App\Filament\Pages\Operations\TenantlessOperationRunViewer;
use App\Models\BaselineProfile;
use App\Models\BaselineSnapshot;
use App\Models\OperationRun; use App\Models\OperationRun;
use App\Models\Tenant; use App\Models\Tenant;
use App\Models\User; use App\Models\User;
@ -624,6 +627,52 @@
->assertSee('Related drilldown'); ->assertSee('Related drilldown');
}); });
it('keeps operations-list navigation out of the related drilldown lane', function (): void {
$tenant = Tenant::factory()->create();
[$user, $tenant] = createUserWithTenant(tenant: $tenant, role: 'owner');
$profile = BaselineProfile::factory()->active()->create([
'workspace_id' => (int) $tenant->workspace_id,
]);
$snapshot = BaselineSnapshot::factory()->complete()->create([
'workspace_id' => (int) $tenant->workspace_id,
'baseline_profile_id' => (int) $profile->getKey(),
]);
$run = OperationRun::factory()->create([
'tenant_id' => (int) $tenant->getKey(),
'workspace_id' => (int) $tenant->workspace_id,
'type' => 'baseline_compare',
'status' => OperationRunStatus::Completed->value,
'outcome' => OperationRunOutcome::Succeeded->value,
'context' => [
'baseline_profile_id' => (int) $profile->getKey(),
'baseline_snapshot_id' => (int) $snapshot->getKey(),
],
]);
Filament::setTenant($tenant, true);
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id);
$this->actingAs($user);
Livewire::test(TenantlessOperationRunViewer::class, ['run' => $run])
->assertActionVisible('view_baseline_profile')
->assertActionVisible('view_snapshot')
->assertActionDoesNotExist('operations')
->assertActionDoesNotExist('open_operations');
$this
->withSession([
WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id,
])
->get(route('admin.operations.view', ['run' => (int) $run->getKey()]))
->assertSuccessful()
->assertSee('Monitoring detail')
->assertSee('Open keeps secondary drilldowns grouped under one control: View baseline profile, View snapshot.');
});
it('renders shared polling markup for active tenantless runs', function (string $status, int $ageSeconds): void { it('renders shared polling markup for active tenantless runs', function (string $status, int $ageSeconds): void {
$workspace = Workspace::factory()->create(); $workspace = Workspace::factory()->create();
$user = User::factory()->create(); $user = User::factory()->create();

View File

@ -67,6 +67,42 @@
->assertSee('Clear filters'); ->assertSee('Clear filters');
}); });
it('clears the remembered tenant prefilter from the review register', function (): void {
$tenantA = Tenant::factory()->create(['name' => 'Alpha Tenant']);
[$user, $tenantA] = createUserWithTenant(tenant: $tenantA, role: 'owner');
$tenantB = Tenant::factory()->create([
'workspace_id' => (int) $tenantA->workspace_id,
'name' => 'Beta Tenant',
]);
createUserWithTenant(tenant: $tenantB, user: $user, role: 'owner');
$reviewA = composeTenantReviewForTest($tenantA, $user);
$reviewB = composeTenantReviewForTest($tenantB, $user);
$this->actingAs($user);
setAdminPanelContext();
session()->put(WorkspaceContext::SESSION_KEY, (int) $tenantA->workspace_id);
session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [
(string) $tenantA->workspace_id => (int) $tenantA->getKey(),
]);
$component = Livewire::actingAs($user)
->test(ReviewRegister::class)
->assertActionVisible('clear_filters')
->assertCanSeeTableRecords([$reviewA])
->assertCanNotSeeTableRecords([$reviewB]);
expect(app(WorkspaceContext::class)->lastTenantId())->toBe((int) $tenantA->getKey());
$component
->callAction('clear_filters')
->assertActionHidden('clear_filters')
->assertCanSeeTableRecords([$reviewA, $reviewB]);
expect(app(WorkspaceContext::class)->lastTenantId())->toBeNull();
});
it('keeps stale and partial review rows aligned with tenant review detail trust', function (): void { it('keeps stale and partial review rows aligned with tenant review detail trust', function (): void {
$staleTenant = Tenant::factory()->create(['name' => 'Stale Tenant']); $staleTenant = Tenant::factory()->create(['name' => 'Stale Tenant']);
[$user, $staleTenant] = createUserWithTenant(tenant: $staleTenant, role: 'owner'); [$user, $staleTenant] = createUserWithTenant(tenant: $staleTenant, role: 'owner');