create(['status' => 'active']); [$user, $tenant] = createUserWithTenant($tenant, role: $role, workspaceRole: $workspaceRole); test()->actingAs($user); setAdminPanelContext(); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id); return [$user, $tenant]; } function findingsIntakePage(?User $user = null, array $query = []) { if ($user instanceof User) { test()->actingAs($user); } setAdminPanelContext(); $factory = $query === [] ? Livewire::actingAs(auth()->user()) : Livewire::withQueryParams($query)->actingAs(auth()->user()); return $factory->test(FindingsIntakeQueue::class); } function makeIntakeFinding(Tenant $tenant, array $attributes = []): Finding { return Finding::factory()->for($tenant)->create(array_merge([ 'workspace_id' => (int) $tenant->workspace_id, 'status' => Finding::STATUS_TRIAGED, 'assignee_user_id' => null, 'owner_user_id' => null, 'subject_external_id' => fake()->uuid(), ], $attributes)); } it('shows only visible unassigned open findings and exposes fixed queue view counts', function (): void { [$user, $tenantA] = findingsIntakeActingUser(); $tenantA->forceFill(['name' => 'Alpha Tenant'])->save(); $tenantB = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'Tenant Bravo', ]); createUserWithTenant($tenantB, $user, role: 'readonly', workspaceRole: 'readonly'); $hiddenTenant = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'Hidden Tenant', ]); $otherAssignee = User::factory()->create(); createUserWithTenant($tenantA, $otherAssignee, role: 'operator', workspaceRole: 'readonly'); $otherOwner = User::factory()->create(); createUserWithTenant($tenantB, $otherOwner, role: 'owner', workspaceRole: 'readonly'); $visibleNew = makeIntakeFinding($tenantA, [ 'subject_external_id' => 'visible-new', 'severity' => Finding::SEVERITY_HIGH, 'status' => Finding::STATUS_NEW, ]); $visibleReopened = makeIntakeFinding($tenantB, [ 'subject_external_id' => 'visible-reopened', 'status' => Finding::STATUS_REOPENED, 'reopened_at' => now()->subHours(6), 'owner_user_id' => (int) $otherOwner->getKey(), ]); $visibleTriaged = makeIntakeFinding($tenantA, [ 'subject_external_id' => 'visible-triaged', 'status' => Finding::STATUS_TRIAGED, ]); $visibleInProgress = makeIntakeFinding($tenantB, [ 'subject_external_id' => 'visible-progress', 'status' => Finding::STATUS_IN_PROGRESS, 'due_at' => now()->subDay(), ]); $assignedOpen = makeIntakeFinding($tenantA, [ 'subject_external_id' => 'assigned-open', 'assignee_user_id' => (int) $otherAssignee->getKey(), ]); $acknowledged = Finding::factory()->for($tenantA)->acknowledged()->create([ 'workspace_id' => (int) $tenantA->workspace_id, 'assignee_user_id' => null, 'subject_external_id' => 'acknowledged', ]); $terminal = Finding::factory()->for($tenantA)->resolved()->create([ 'workspace_id' => (int) $tenantA->workspace_id, 'assignee_user_id' => null, 'subject_external_id' => 'terminal', ]); $hidden = makeIntakeFinding($hiddenTenant, [ 'subject_external_id' => 'hidden-intake', ]); $component = findingsIntakePage($user) ->assertCanSeeTableRecords([$visibleNew, $visibleReopened, $visibleTriaged, $visibleInProgress]) ->assertCanNotSeeTableRecords([$assignedOpen, $acknowledged, $terminal, $hidden]) ->assertSee('Owner: '.$otherOwner->name) ->assertSee('Needs triage') ->assertSee('Unassigned'); expect($component->instance()->summaryCounts())->toBe([ 'visible_unassigned' => 4, 'visible_needs_triage' => 2, 'visible_overdue' => 1, ]); $queueViews = collect($component->instance()->queueViews())->keyBy('key'); expect($queueViews['unassigned']['badge_count'])->toBe(4) ->and($queueViews['unassigned']['active'])->toBeTrue() ->and($queueViews['needs_triage']['badge_count'])->toBe(2) ->and($queueViews['needs_triage']['active'])->toBeFalse(); }); it('defaults to the active tenant prefilter and lets the operator clear it without dropping intake scope', function (): void { [$user, $tenantA] = findingsIntakeActingUser(); $tenantB = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'Beta Tenant', ]); createUserWithTenant($tenantB, $user, role: 'readonly', workspaceRole: 'readonly'); $findingA = makeIntakeFinding($tenantA, [ 'subject_external_id' => 'tenant-a', 'status' => Finding::STATUS_NEW, ]); $findingB = makeIntakeFinding($tenantB, [ 'subject_external_id' => 'tenant-b', 'status' => Finding::STATUS_TRIAGED, ]); session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [ (string) $tenantA->workspace_id => (int) $tenantB->getKey(), ]); $component = findingsIntakePage($user) ->assertSet('tableFilters.tenant_id.value', (string) $tenantB->getKey()) ->assertCanSeeTableRecords([$findingB]) ->assertCanNotSeeTableRecords([$findingA]) ->assertActionVisible('clear_tenant_filter'); expect($component->instance()->appliedScope())->toBe([ 'workspace_scoped' => true, 'fixed_scope' => 'visible_unassigned_open_findings_only', 'queue_view' => 'unassigned', 'queue_view_label' => 'Unassigned', 'tenant_prefilter_source' => 'active_tenant_context', 'tenant_label' => $tenantB->name, ]); $component->callAction('clear_tenant_filter') ->assertCanSeeTableRecords([$findingA, $findingB]); expect($component->instance()->appliedScope())->toBe([ 'workspace_scoped' => true, 'fixed_scope' => 'visible_unassigned_open_findings_only', 'queue_view' => 'unassigned', 'queue_view_label' => 'Unassigned', 'tenant_prefilter_source' => 'none', 'tenant_label' => null, ]); }); it('keeps the needs triage view active when clearing the tenant prefilter', function (): void { [$user, $tenantA] = findingsIntakeActingUser(); $tenantB = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'Beta Tenant', ]); createUserWithTenant($tenantB, $user, role: 'readonly', workspaceRole: 'readonly'); $tenantATriage = makeIntakeFinding($tenantA, [ 'subject_external_id' => 'tenant-a-triage', 'status' => Finding::STATUS_NEW, ]); $tenantBTriage = makeIntakeFinding($tenantB, [ 'subject_external_id' => 'tenant-b-triage', 'status' => Finding::STATUS_REOPENED, 'reopened_at' => now()->subHour(), ]); $tenantBBacklog = makeIntakeFinding($tenantB, [ 'subject_external_id' => 'tenant-b-backlog', 'status' => Finding::STATUS_TRIAGED, ]); session()->put(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY, [ (string) $tenantA->workspace_id => (int) $tenantB->getKey(), ]); $component = findingsIntakePage($user, ['view' => 'needs_triage']) ->assertSet('tableFilters.tenant_id.value', (string) $tenantB->getKey()) ->assertCanSeeTableRecords([$tenantBTriage]) ->assertCanNotSeeTableRecords([$tenantATriage, $tenantBBacklog]); expect($component->instance()->appliedScope())->toBe([ 'workspace_scoped' => true, 'fixed_scope' => 'visible_unassigned_open_findings_only', 'queue_view' => 'needs_triage', 'queue_view_label' => 'Needs triage', 'tenant_prefilter_source' => 'active_tenant_context', 'tenant_label' => $tenantB->name, ]); $component->callAction('clear_tenant_filter') ->assertCanSeeTableRecords([$tenantBTriage, $tenantATriage], inOrder: true) ->assertCanNotSeeTableRecords([$tenantBBacklog]); expect($component->instance()->appliedScope())->toBe([ 'workspace_scoped' => true, 'fixed_scope' => 'visible_unassigned_open_findings_only', 'queue_view' => 'needs_triage', 'queue_view_label' => 'Needs triage', 'tenant_prefilter_source' => 'none', 'tenant_label' => null, ]); $queueViews = collect($component->instance()->queueViews())->keyBy('key'); expect($queueViews['unassigned']['active'])->toBeFalse() ->and($queueViews['needs_triage']['active'])->toBeTrue(); }); it('separates needs triage from the remaining backlog and keeps deterministic urgency ordering', function (): void { [$user, $tenant] = findingsIntakeActingUser(); $overdue = makeIntakeFinding($tenant, [ 'subject_external_id' => 'overdue', 'status' => Finding::STATUS_TRIAGED, 'due_at' => now()->subDay(), ]); $reopened = makeIntakeFinding($tenant, [ 'subject_external_id' => 'reopened', 'status' => Finding::STATUS_REOPENED, 'reopened_at' => now()->subHours(2), 'due_at' => now()->addDay(), ]); $newFinding = makeIntakeFinding($tenant, [ 'subject_external_id' => 'new-finding', 'status' => Finding::STATUS_NEW, 'due_at' => now()->addDays(2), ]); $remainingBacklog = makeIntakeFinding($tenant, [ 'subject_external_id' => 'remaining-backlog', 'status' => Finding::STATUS_TRIAGED, 'due_at' => now()->addHours(12), ]); $undatedBacklog = makeIntakeFinding($tenant, [ 'subject_external_id' => 'undated-backlog', 'status' => Finding::STATUS_IN_PROGRESS, 'due_at' => null, ]); findingsIntakePage($user) ->assertCanSeeTableRecords([$overdue, $reopened, $newFinding, $remainingBacklog, $undatedBacklog], inOrder: true); findingsIntakePage($user, ['view' => 'needs_triage']) ->assertCanSeeTableRecords([$reopened, $newFinding], inOrder: true) ->assertCanNotSeeTableRecords([$overdue, $remainingBacklog, $undatedBacklog]); }); it('builds tenant detail drilldowns with intake continuity', function (): void { [$user, $tenant] = findingsIntakeActingUser(); $finding = makeIntakeFinding($tenant, [ 'subject_external_id' => 'continuity', 'status' => Finding::STATUS_NEW, ]); $component = findingsIntakePage($user, [ 'tenant' => (string) $tenant->external_id, 'view' => 'needs_triage', ]); $detailUrl = $component->instance()->getTable()->getRecordUrl($finding); expect($detailUrl)->toContain(FindingResource::getUrl('view', ['record' => $finding], panel: 'tenant', tenant: $tenant)) ->and($detailUrl)->toContain('nav%5Bback_label%5D=Back+to+findings+intake'); $this->actingAs($user) ->withSession([WorkspaceContext::SESSION_KEY => (int) $tenant->workspace_id]) ->get($detailUrl) ->assertOk() ->assertSee('Back to findings intake'); }); it('renders both intake empty-state branches with the correct single recovery action', function (): void { [$user, $tenantA] = findingsIntakeActingUser(); $tenantB = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $tenantA->workspace_id, 'name' => 'Work Tenant', ]); createUserWithTenant($tenantB, $user, role: 'readonly', workspaceRole: 'readonly'); makeIntakeFinding($tenantB, [ 'subject_external_id' => 'available-elsewhere', ]); findingsIntakePage($user, [ 'tenant' => (string) $tenantA->external_id, ]) ->assertSee('No intake findings match this tenant scope') ->assertTableEmptyStateActionsExistInOrder(['clear_tenant_filter_empty']); Finding::query()->delete(); session()->forget(WorkspaceContext::LAST_TENANT_IDS_SESSION_KEY); Filament::setTenant(null, true); findingsIntakePage($user) ->assertSee('Shared intake is clear') ->assertTableEmptyStateActionsExistInOrder(['open_my_findings_empty']); });