TenantAtlas/resources/views/filament/infolists/entries/baseline-snapshot-groups.blade.php
2026-03-10 09:26:42 +01:00

146 lines
8.5 KiB
PHP

@php
use App\Support\Badges\BadgeDomain;
use App\Support\Badges\BadgeRenderer;
use Illuminate\Support\Carbon;
$groups = $getState() ?? [];
$formatTimestamp = static function (?string $value): string {
if (! is_string($value) || trim($value) === '') {
return '—';
}
try {
return Carbon::parse($value)->toDayDateTimeString();
} catch (\Throwable) {
return $value;
}
};
@endphp
<div class="space-y-4">
@if ($groups === [])
<div class="rounded-lg border border-dashed border-gray-300 px-4 py-6 text-sm text-gray-600 dark:border-gray-700 dark:text-gray-300">
No snapshot items were captured for this baseline snapshot.
</div>
@else
@foreach ($groups as $group)
@php
$fidelitySpec = BadgeRenderer::spec(BadgeDomain::BaselineSnapshotFidelity, $group['fidelity'] ?? null);
$gapSpec = BadgeRenderer::spec(BadgeDomain::BaselineSnapshotGapStatus, data_get($group, 'gapSummary.badge_state'));
$messages = data_get($group, 'gapSummary.messages', []);
@endphp
<x-filament::section
:heading="$group['label'] ?? ($group['policyType'] ?? 'Policy type')"
:description="$group['coverageHint'] ?? null"
collapsible
:collapsed="(bool) ($group['initiallyCollapsed'] ?? true)"
>
<x-slot name="headerEnd">
<div class="flex flex-wrap items-center gap-2">
<span class="text-xs text-gray-500 dark:text-gray-400">
{{ (int) ($group['itemCount'] ?? 0) }} {{ \Illuminate\Support\Str::plural('item', (int) ($group['itemCount'] ?? 0)) }}
</span>
<x-filament::badge :color="$fidelitySpec->color" :icon="$fidelitySpec->icon" size="sm">
{{ $fidelitySpec->label }}
</x-filament::badge>
<x-filament::badge :color="$gapSpec->color" :icon="$gapSpec->icon" size="sm">
{{ $gapSpec->label }}
</x-filament::badge>
</div>
</x-slot>
<div class="space-y-4">
@if (! empty($group['renderingError']))
<div class="rounded-lg border border-amber-200 bg-amber-50 px-4 py-3 text-sm text-amber-900 dark:border-amber-800 dark:bg-amber-950/30 dark:text-amber-200">
{{ $group['renderingError'] }}
</div>
@endif
@if (is_array($messages) && $messages !== [])
<div class="rounded-lg border border-gray-200 bg-gray-50 px-4 py-3 text-sm text-gray-700 dark:border-gray-700 dark:bg-gray-900/40 dark:text-gray-200">
<div class="font-medium">Gap details</div>
<ul class="mt-2 list-disc space-y-1 pl-5">
@foreach ($messages as $message)
<li>{{ $message }}</li>
@endforeach
</ul>
</div>
@endif
<div class="space-y-3">
@foreach (($group['items'] ?? []) as $item)
@php
$itemFidelitySpec = BadgeRenderer::spec(BadgeDomain::BaselineSnapshotFidelity, $item['fidelity'] ?? null);
$itemGapSpec = BadgeRenderer::spec(BadgeDomain::BaselineSnapshotGapStatus, data_get($item, 'gapSummary.badge_state'));
@endphp
<div class="rounded-xl border border-gray-200 bg-white p-4 shadow-sm dark:border-gray-700 dark:bg-gray-900">
<div class="flex flex-col gap-3 md:flex-row md:items-start md:justify-between">
<div class="space-y-1">
<div class="text-sm font-semibold text-gray-900 dark:text-white">
{{ $item['label'] ?? 'Snapshot item' }}
</div>
<div class="text-xs text-gray-500 dark:text-gray-400">
{{ $item['typeLabel'] ?? 'Policy type' }}
</div>
</div>
<div class="flex flex-wrap items-center gap-2">
<span class="rounded-full bg-gray-100 px-2.5 py-1 text-xs font-medium text-gray-700 dark:bg-gray-800 dark:text-gray-200">
{{ $item['referenceStatus'] ?? 'Captured metadata' }}
</span>
<x-filament::badge :color="$itemFidelitySpec->color" :icon="$itemFidelitySpec->icon" size="sm">
{{ $itemFidelitySpec->label }}
</x-filament::badge>
<x-filament::badge :color="$itemGapSpec->color" :icon="$itemGapSpec->icon" size="sm">
{{ $itemGapSpec->label }}
</x-filament::badge>
</div>
</div>
<div class="mt-3 grid gap-2 text-sm text-gray-700 dark:text-gray-200 md:grid-cols-3">
<div>
<div class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Identity</div>
<div class="mt-1 break-all">{{ $item['identityHint'] ?? '—' }}</div>
</div>
<div>
<div class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Observed</div>
<div class="mt-1">{{ $formatTimestamp($item['observedAt'] ?? null) }}</div>
</div>
<div>
<div class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">Source reference</div>
<div class="mt-1">{{ $item['sourceReference'] ?? '—' }}</div>
</div>
</div>
@if (is_array(data_get($item, 'gapSummary.messages')) && data_get($item, 'gapSummary.messages') !== [])
<div class="mt-3 rounded-lg border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-900 dark:border-amber-800 dark:bg-amber-950/30 dark:text-amber-200">
{{ implode(' ', data_get($item, 'gapSummary.messages', [])) }}
</div>
@endif
@if (($item['structuredAttributes'] ?? []) !== [])
<dl class="mt-4 grid gap-3 md:grid-cols-2">
@foreach (($item['structuredAttributes'] ?? []) as $attribute)
<div class="rounded-lg border border-gray-100 bg-gray-50 px-3 py-2 dark:border-gray-800 dark:bg-gray-950/40">
<dt class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
{{ $attribute['label'] ?? 'Attribute' }}
</dt>
<dd class="mt-1 text-sm text-gray-800 dark:text-gray-100">
{{ $attribute['value'] ?? '—' }}
</dd>
</div>
@endforeach
</dl>
@endif
</div>
@endforeach
</div>
</div>
</x-filament::section>
@endforeach
@endif
</div>