loadMissing(['baselineProfile', 'items']); $summary = is_array($snapshot->summary_jsonb) ? $snapshot->summary_jsonb : []; $items = $snapshot->items instanceof EloquentCollection ? $snapshot->items->sortBy([ ['policy_type', 'asc'], ['id', 'asc'], ])->values() : collect(); $groups = $items ->groupBy(static fn (BaselineSnapshotItem $item): string => (string) $item->policy_type) ->map(fn (Collection $groupItems, string $policyType): RenderedSnapshotGroup => $this->presentGroup($policyType, $groupItems)) ->sortBy(static fn (RenderedSnapshotGroup $group): string => mb_strtolower($group->label)) ->values() ->all(); $summaryRows = array_map( static fn (RenderedSnapshotGroup $group): array => [ 'policyType' => $group->policyType, 'label' => $group->label, 'itemCount' => $group->itemCount, 'fidelity' => $group->fidelity->value, 'gapCount' => $group->gapSummary->count, 'capturedAt' => $group->capturedAt, 'coverageHint' => $group->coverageHint, ], $groups, ); $overallGapCount = $this->summaryGapCount($summary); $overallFidelity = FidelityState::fromSummary($summary, $items->isNotEmpty()); return new RenderedSnapshot( snapshotId: (int) $snapshot->getKey(), baselineProfileName: $snapshot->baselineProfile?->name, capturedAt: $snapshot->captured_at?->toIso8601String(), snapshotIdentityHash: is_string($snapshot->snapshot_identity_hash) && trim($snapshot->snapshot_identity_hash) !== '' ? trim($snapshot->snapshot_identity_hash) : null, stateLabel: $overallGapCount > 0 ? 'Captured with gaps' : 'Complete', fidelitySummary: $this->fidelitySummary($summary), overallFidelity: $overallFidelity, overallGapCount: $overallGapCount, summaryRows: $summaryRows, groups: $groups, technicalDetail: [ 'defaultCollapsed' => true, 'summaryPayload' => $summary, 'groupPayloads' => array_map( static fn (RenderedSnapshotGroup $group): array => [ 'label' => $group->label, 'renderingError' => $group->renderingError, 'payload' => $group->technicalPayload, ], $groups, ), ], hasItems: $items->isNotEmpty(), ); } /** * @param list> $relatedContext */ public function presentEnterpriseDetail(BaselineSnapshot $snapshot, array $relatedContext = []): EnterpriseDetailPageData { $rendered = $this->present($snapshot); $factory = new EnterpriseDetailSectionFactory; $stateBadge = $factory->statusBadge( $rendered->stateLabel, $rendered->overallGapCount > 0 ? 'warning' : 'success', ); $fidelitySpec = BadgeRenderer::spec(BadgeDomain::BaselineSnapshotFidelity, $rendered->overallFidelity->value); $fidelityBadge = $factory->statusBadge( $fidelitySpec->label, $fidelitySpec->color, $fidelitySpec->icon, $fidelitySpec->iconColor, ); $capturedItemCount = array_sum(array_map( static fn (array $row): int => (int) ($row['itemCount'] ?? 0), $rendered->summaryRows, )); return EnterpriseDetailBuilder::make('baseline_snapshot', 'workspace') ->header(new SummaryHeaderData( title: $rendered->baselineProfileName ?? 'Baseline snapshot', subtitle: 'Snapshot #'.$rendered->snapshotId, statusBadges: [$stateBadge, $fidelityBadge], keyFacts: [ $factory->keyFact('Captured', $this->formatTimestamp($rendered->capturedAt)), $factory->keyFact('Evidence mix', $rendered->fidelitySummary), $factory->keyFact('Evidence gaps', $rendered->overallGapCount), $factory->keyFact('Captured items', $capturedItemCount), ], descriptionHint: 'Capture context, coverage, and governance links stay ahead of technical payload detail.', )) ->addSection( $factory->viewSection( id: 'coverage_summary', kind: 'current_status', title: 'Coverage summary', view: 'filament.infolists.entries.baseline-snapshot-summary-table', viewData: ['rows' => $rendered->summaryRows], emptyState: $factory->emptyState('No captured policy types are available in this snapshot.'), ), $factory->viewSection( id: 'related_context', kind: 'related_context', title: 'Related context', view: 'filament.infolists.entries.related-context', viewData: ['entries' => $relatedContext], emptyState: $factory->emptyState('No related context is available for this record.'), ), $factory->viewSection( id: 'captured_policy_types', kind: 'domain_detail', title: 'Captured policy types', view: 'filament.infolists.entries.baseline-snapshot-groups', viewData: ['groups' => array_map( static fn (RenderedSnapshotGroup $group): array => $group->toArray(), $rendered->groups, )], emptyState: $factory->emptyState('No snapshot items were captured for this baseline snapshot.'), ), ) ->addSupportingCard( $factory->supportingFactsCard( kind: 'status', title: 'Snapshot status', items: [ $factory->keyFact('State', $rendered->stateLabel, badge: $stateBadge), $factory->keyFact('Overall fidelity', $fidelitySpec->label, badge: $fidelityBadge), $factory->keyFact('Evidence gaps', $rendered->overallGapCount), ], ), $factory->supportingFactsCard( kind: 'timestamps', title: 'Capture timing', items: [ $factory->keyFact('Captured', $this->formatTimestamp($rendered->capturedAt)), $factory->keyFact('Identity hash', $rendered->snapshotIdentityHash), ], ), ) ->addTechnicalSection( $factory->technicalDetail( title: 'Technical detail', entries: [ $factory->keyFact('Identity hash', $rendered->snapshotIdentityHash), ], description: 'Technical payloads are secondary on purpose. Use them for debugging capture fidelity and renderer fallbacks.', view: 'filament.infolists.entries.baseline-snapshot-technical-detail', viewData: ['technical' => $rendered->technicalDetail], ), ) ->build(); } /** * @param Collection $items */ private function presentGroup(string $policyType, Collection $items): RenderedSnapshotGroup { $renderer = $this->registry->rendererFor($policyType); $fallbackRenderer = $this->registry->fallbackRenderer(); $renderingError = null; $technicalPayload = $this->technicalPayload($items); try { $renderedItems = $items ->map(fn (BaselineSnapshotItem $item): RenderedSnapshotItem => $renderer->render($item)) ->all(); } catch (Throwable) { $renderedItems = $items ->map(fn (BaselineSnapshotItem $item): RenderedSnapshotItem => $fallbackRenderer->render($item)) ->all(); $renderingError = 'Structured rendering failed for this policy type. Fallback metadata is shown instead.'; } /** @var array $renderedItems */ $groupFidelity = FidelityState::aggregate(array_map( static fn (RenderedSnapshotItem $item): FidelityState => $item->fidelity, $renderedItems, )); $gapSummary = GapSummary::merge(array_map( static fn (RenderedSnapshotItem $item): GapSummary => $item->gapSummary, $renderedItems, )); if ($renderingError !== null) { $gapSummary = $gapSummary->withMessage($renderingError); } $capturedAt = collect($renderedItems) ->pluck('observedAt') ->filter(static fn (mixed $value): bool => is_string($value) && trim($value) !== '') ->sortDesc() ->first(); $coverageHint = $groupFidelity->coverageHint(); if ($coverageHint === null && $gapSummary->messages !== []) { $coverageHint = $gapSummary->messages[0]; } return new RenderedSnapshotGroup( policyType: $policyType, label: $this->typeLabel($policyType), itemCount: $items->count(), fidelity: $groupFidelity, gapSummary: $gapSummary, initiallyCollapsed: true, items: $renderedItems, renderingError: $renderingError, coverageHint: $coverageHint, capturedAt: is_string($capturedAt) ? $capturedAt : null, technicalPayload: $technicalPayload, ); } /** * @param Collection $items * @return array */ private function technicalPayload(Collection $items): array { return [ 'items' => $items ->map(static fn (BaselineSnapshotItem $item): array => [ 'snapshot_item_id' => (int) $item->getKey(), 'policy_type' => (string) $item->policy_type, 'meta_jsonb' => is_array($item->meta_jsonb) ? $item->meta_jsonb : [], ]) ->all(), ]; } /** * @param array $summary */ private function summaryGapCount(array $summary): int { $gaps = is_array($summary['gaps'] ?? null) ? $summary['gaps'] : []; $count = $gaps['count'] ?? 0; return is_numeric($count) ? (int) $count : 0; } /** * @param array $summary */ private function fidelitySummary(array $summary): string { $counts = is_array($summary['fidelity_counts'] ?? null) ? $summary['fidelity_counts'] : []; $content = is_numeric($counts['content'] ?? null) ? (int) $counts['content'] : 0; $meta = is_numeric($counts['meta'] ?? null) ? (int) $counts['meta'] : 0; return sprintf('Content %d, Meta %d', $content, $meta); } private function typeLabel(string $policyType): string { return InventoryPolicyTypeMeta::baselineCompareLabel($policyType) ?? InventoryPolicyTypeMeta::label($policyType) ?? Str::headline($policyType); } private function formatTimestamp(?string $value): string { if ($value === null || trim($value) === '') { return '—'; } try { return Carbon::parse($value)->toDayDateTimeString(); } catch (Throwable) { return $value; } } }