create([ 'status' => 'active', 'name' => $tenantName, ]); [$user, $tenant] = createUserWithTenant( tenant: $tenant, role: $role, workspaceRole: $workspaceRole, ); workspaceOverviewSeedQuietTenantTruth($tenant); return [$user, $tenant]; } protected function makePortfolioTriagePeer(User $user, Tenant $workspaceTenant, string $name): Tenant { $tenant = Tenant::factory()->create([ 'status' => 'active', 'workspace_id' => (int) $workspaceTenant->workspace_id, 'name' => $name, ]); createUserWithTenant( tenant: $tenant, user: $user, role: 'owner', workspaceRole: 'readonly', ); workspaceOverviewSeedQuietTenantTruth($tenant); return $tenant; } protected function seedPortfolioBackupConcern(Tenant $tenant, string $state): ?BackupSet { return match ($state) { TenantBackupHealthAssessment::POSTURE_ABSENT => null, TenantBackupHealthAssessment::POSTURE_STALE => BackupSet::factory() ->for($tenant) ->staleCompleted() ->create([ 'name' => 'Portfolio stale backup', ]), TenantBackupHealthAssessment::POSTURE_DEGRADED => BackupSet::factory() ->for($tenant) ->degradedCompleted() ->create([ 'name' => 'Portfolio degraded backup', ]), default => workspaceOverviewSeedHealthyBackup($tenant, [ 'name' => 'Portfolio healthy backup', ]), }; } protected function seedPortfolioRecoveryConcern( Tenant $tenant, string $reason = 'no_history', ?BackupSet $backupSet = null, ): ?RestoreRun { $backupSet ??= workspaceOverviewSeedHealthyBackup($tenant, [ 'name' => 'Portfolio recovery backup', ]); return match ($reason) { 'no_history' => null, RestoreResultAttention::STATE_FAILED => RestoreRun::factory() ->for($tenant) ->for($backupSet) ->failedOutcome() ->create([ 'completed_at' => now()->subMinutes(10), ]), RestoreResultAttention::STATE_PARTIAL => RestoreRun::factory() ->for($tenant) ->for($backupSet) ->partialOutcome() ->create([ 'completed_at' => now()->subMinutes(10), ]), RestoreResultAttention::STATE_COMPLETED_WITH_FOLLOW_UP => RestoreRun::factory() ->for($tenant) ->for($backupSet) ->completedWithFollowUp() ->create([ 'completed_at' => now()->subMinutes(10), ]), default => RestoreRun::factory() ->for($tenant) ->for($backupSet) ->completedOutcome() ->create([ 'completed_at' => now()->subMinutes(10), ]), }; } protected function usePortfolioTriageWorkspace(User $user, Tenant $tenant): void { test()->actingAs($user); session()->put(WorkspaceContext::SESSION_KEY, (int) $tenant->workspace_id); Filament::setTenant(null, true); request()->attributes->remove('tenant_resource.posture_snapshot'); session()->forget('tables.'.md5(ListTenants::class).'_filters'); session()->forget('tables.'.md5(ListTenants::class).'_search'); session()->forget('tables.'.md5(ListTenants::class).'_sort'); } protected function portfolioTriageRegistryList(User $user, Tenant $workspaceTenant, array $query = []): mixed { $this->usePortfolioTriageWorkspace($user, $workspaceTenant); $factory = $query !== [] ? Livewire::withQueryParams($query)->actingAs($user) : Livewire::actingAs($user); return $factory->test(ListTenants::class); } /** * @return array{backup_posture: list, recovery_evidence: list, triage_sort: string|null} */ protected function portfolioReturnFilters( array $backupPosture = [], array $recoveryEvidence = [], ?string $triageSort = TenantRecoveryTriagePresentation::TRIAGE_SORT_WORST_FIRST, ): array { return [ 'backup_posture' => $backupPosture, 'recovery_evidence' => $recoveryEvidence, 'triage_sort' => $triageSort, ]; } }