Applied diagnostic surface contract rules to Audit Log inspect modal and Support Diagnostics action context, consolidating raw diagnostic data into safe modals according to Spec 374. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #445
355 lines
18 KiB
PHP
355 lines
18 KiB
PHP
@php
|
|
use Illuminate\Support\Str;
|
|
|
|
/** @var array<string, mixed> $bundle */
|
|
$summary = is_array($bundle['summary'] ?? null) ? $bundle['summary'] : [];
|
|
$context = is_array($bundle['context'] ?? null) ? $bundle['context'] : [];
|
|
$sections = is_array($bundle['sections'] ?? null) ? $bundle['sections'] : [];
|
|
$redaction = is_array($bundle['redaction'] ?? null) ? $bundle['redaction'] : [];
|
|
$notes = is_array($bundle['notes'] ?? null) ? $bundle['notes'] : [];
|
|
$recommendedFirstCheck = is_array(data_get($summary, 'recommended_first_check'))
|
|
? data_get($summary, 'recommended_first_check')
|
|
: null;
|
|
$contextNotes = collect($notes)
|
|
->filter(static fn (mixed $note): bool => is_string($note) && trim($note) !== '')
|
|
->reject(static fn (string $note): bool => str_contains($note, 'redacted support view'))
|
|
->values()
|
|
->all();
|
|
|
|
$availabilityLabel = static function (?string $availability): string {
|
|
return match ($availability) {
|
|
'available' => 'Available',
|
|
'current' => 'Current',
|
|
'fresh' => 'Fresh',
|
|
'ready' => 'Ready',
|
|
'partial' => 'Partial',
|
|
'stale' => 'Stale',
|
|
'error' => 'Error',
|
|
'missing' => 'Not observed',
|
|
'unavailable' => 'Unavailable',
|
|
'redacted' => 'Redacted',
|
|
default => filled($availability) ? Str::headline(str_replace('_', ' ', (string) $availability)) : 'Unknown',
|
|
};
|
|
};
|
|
|
|
$availabilityColor = static function (?string $availability): string {
|
|
return match ($availability) {
|
|
'available', 'current', 'fresh', 'ready' => 'success',
|
|
'partial', 'stale' => 'warning',
|
|
'error', 'missing', 'unavailable' => 'danger',
|
|
default => 'gray',
|
|
};
|
|
};
|
|
|
|
$contextTypeLabel = static function (?string $type): string {
|
|
return match ($type) {
|
|
'operation_run' => 'Operation context',
|
|
'tenant' => 'Environment context',
|
|
default => filled($type) ? Str::headline(str_replace('_', ' ', (string) $type)) : 'Environment context',
|
|
};
|
|
};
|
|
|
|
$freshnessStateLabel = static function (?string $state): string {
|
|
return match ($state) {
|
|
'fresh' => 'Fresh',
|
|
'mixed' => 'Mixed freshness',
|
|
'missing_context' => 'Missing context',
|
|
default => filled($state) ? Str::headline(str_replace('_', ' ', (string) $state)) : 'Unknown freshness',
|
|
};
|
|
};
|
|
|
|
$redactionModeLabel = static function (?string $mode): string {
|
|
return match ($mode) {
|
|
'default_redacted', 'default-redacted' => 'Redacted support view',
|
|
default => filled($mode) ? Str::headline(str_replace('_', ' ', (string) $mode)) : 'Redacted support view',
|
|
};
|
|
};
|
|
|
|
$referenceTypeLabel = static function (?string $type): string {
|
|
return match ($type) {
|
|
'audit_log' => 'Audit event',
|
|
'environment_review' => 'Environment review',
|
|
'finding' => 'Finding',
|
|
'operation_run' => 'Operation',
|
|
'provider_connection' => 'Provider connection',
|
|
'review_pack' => 'Review pack',
|
|
'stored_report' => 'Stored report',
|
|
'tenant' => 'Environment',
|
|
default => filled($type) ? Str::headline(str_replace('_', ' ', (string) $type)) : 'Reference',
|
|
};
|
|
};
|
|
|
|
$referenceDescription = static function (array $reference) use ($availabilityLabel, $referenceTypeLabel): string {
|
|
$parts = [
|
|
$referenceTypeLabel(is_string($reference['type'] ?? null) ? (string) $reference['type'] : null),
|
|
$availabilityLabel(is_string($reference['availability'] ?? null) ? (string) $reference['availability'] : 'missing'),
|
|
];
|
|
|
|
if (is_string($reference['freshness_note'] ?? null) && trim((string) $reference['freshness_note']) !== '') {
|
|
$parts[] = (string) $reference['freshness_note'];
|
|
}
|
|
|
|
return implode(' - ', $parts);
|
|
};
|
|
|
|
$sectionObserved = static function (array $section, array $references): string {
|
|
if (is_string($section['freshness_note'] ?? null) && trim((string) $section['freshness_note']) !== '') {
|
|
return (string) $section['freshness_note'];
|
|
}
|
|
|
|
$availableCount = collect($references)
|
|
->filter(static fn (array $reference): bool => ($reference['availability'] ?? null) === 'available')
|
|
->count();
|
|
|
|
if ($availableCount > 0) {
|
|
return $availableCount === 1 ? '1 related reference observed.' : $availableCount.' related references observed.';
|
|
}
|
|
|
|
return 'No related record observed in this support context.';
|
|
};
|
|
@endphp
|
|
|
|
<div class="space-y-4">
|
|
<x-filament::section
|
|
:heading="data_get($summary, 'headline', data_get($bundle, 'headline', 'Support diagnostics'))"
|
|
:description="data_get($summary, 'dominant_issue', data_get($bundle, 'dominant_issue', 'No dominant issue available.'))"
|
|
>
|
|
<x-slot name="afterHeader">
|
|
<div class="flex flex-wrap gap-2">
|
|
<x-filament::badge color="gray" size="sm">
|
|
{{ $contextTypeLabel(data_get($context, 'type', data_get($bundle, 'context_type', 'tenant'))) }}
|
|
</x-filament::badge>
|
|
<x-filament::badge color="gray" size="sm">
|
|
{{ $freshnessStateLabel(data_get($summary, 'freshness_state', data_get($bundle, 'freshness_state', 'mixed'))) }}
|
|
</x-filament::badge>
|
|
<x-filament::badge color="warning" size="sm">
|
|
{{ $redactionModeLabel(data_get($redaction, 'mode', data_get($bundle, 'redaction_mode', 'default_redacted'))) }}
|
|
</x-filament::badge>
|
|
</div>
|
|
</x-slot>
|
|
|
|
<div class="space-y-4">
|
|
<p class="text-sm leading-6 text-gray-700 dark:text-gray-200">
|
|
Use this quick support context to start with the recommended first check before opening lower technical sections.
|
|
</p>
|
|
|
|
@if ($recommendedFirstCheck !== null)
|
|
@php
|
|
$firstCheckReference = is_array($recommendedFirstCheck['reference'] ?? null)
|
|
? $recommendedFirstCheck['reference']
|
|
: null;
|
|
$firstCheckReferenceLabel = $firstCheckReference['label'] ?? 'Reference unavailable';
|
|
$firstCheckReferenceUrl = is_string($firstCheckReference['url'] ?? null) && trim((string) $firstCheckReference['url']) !== ''
|
|
? (string) $firstCheckReference['url']
|
|
: null;
|
|
$firstCheckReferenceActionLabel = $firstCheckReference['action_label'] ?? ($firstCheckReferenceUrl ? 'Open' : 'Unavailable');
|
|
@endphp
|
|
|
|
<div class="space-y-3 border-t border-gray-200 pt-4 dark:border-white/10">
|
|
<div class="flex flex-wrap items-start justify-between gap-3">
|
|
<div class="space-y-1">
|
|
<h3 class="text-sm font-semibold text-gray-950 dark:text-white">
|
|
Recommended first check
|
|
</h3>
|
|
<p class="text-sm leading-6 text-gray-700 dark:text-gray-200">
|
|
{{ data_get($recommendedFirstCheck, 'body', 'Start with the highest-confidence support reference before inspecting lower sections.') }}
|
|
</p>
|
|
</div>
|
|
<x-filament::badge color="warning" size="sm">
|
|
{{ data_get($recommendedFirstCheck, 'label', 'Review source first') }}
|
|
</x-filament::badge>
|
|
</div>
|
|
|
|
@if ($firstCheckReference !== null)
|
|
<div class="flex flex-wrap items-center gap-2 text-sm">
|
|
<span class="font-medium text-gray-950 dark:text-white">
|
|
{{ $firstCheckReferenceLabel }}
|
|
</span>
|
|
|
|
@if ($firstCheckReferenceUrl)
|
|
<x-filament::link
|
|
:href="$firstCheckReferenceUrl"
|
|
rel="noopener noreferrer"
|
|
size="sm"
|
|
target="_blank"
|
|
>
|
|
{{ $firstCheckReferenceActionLabel }}
|
|
</x-filament::link>
|
|
@else
|
|
<x-filament::badge color="gray" size="sm">
|
|
{{ $firstCheckReferenceActionLabel }}
|
|
</x-filament::badge>
|
|
@endif
|
|
</div>
|
|
@endif
|
|
</div>
|
|
@endif
|
|
|
|
<dl class="grid grid-cols-1 gap-3 text-sm sm:grid-cols-2">
|
|
<div class="space-y-1">
|
|
<dt class="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">Workspace</dt>
|
|
<dd class="text-gray-950 dark:text-white">{{ data_get($context, 'workspace_label', 'Workspace unavailable') }}</dd>
|
|
</div>
|
|
<div class="space-y-1">
|
|
<dt class="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">Environment</dt>
|
|
<dd class="text-gray-950 dark:text-white">{{ data_get($context, 'tenant_label', 'Environment unavailable') }}</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
</x-filament::section>
|
|
|
|
@if (is_array($bundle['contextual_help'] ?? null))
|
|
@include('filament.components.product-knowledge.contextual-help', ['help' => $bundle['contextual_help']])
|
|
@endif
|
|
|
|
@if ($notes !== [])
|
|
<div class="rounded-md border border-gray-200 bg-gray-50 px-4 py-3 dark:border-white/10 dark:bg-white/5">
|
|
<div class="flex flex-col gap-2 sm:flex-row sm:items-start sm:justify-between">
|
|
<div class="space-y-1">
|
|
<p class="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">
|
|
Support scope
|
|
</p>
|
|
<p class="text-sm leading-6 text-gray-700 dark:text-gray-200">
|
|
Read-only, redacted support view. Restricted provider details are excluded.
|
|
</p>
|
|
</div>
|
|
|
|
@if ($contextNotes !== [])
|
|
<div class="flex flex-wrap gap-2 sm:justify-end">
|
|
@foreach ($contextNotes as $note)
|
|
<span class="inline-flex max-w-full rounded-md bg-white px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-gray-950/10 dark:bg-white/5 dark:text-gray-300 dark:ring-white/10">
|
|
{{ $note }}
|
|
</span>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="space-y-3">
|
|
@foreach ($sections as $section)
|
|
@php
|
|
$references = is_array($section['references'] ?? null) ? $section['references'] : [];
|
|
$markers = is_array($section['redaction_markers'] ?? null) ? $section['redaction_markers'] : [];
|
|
$availability = is_string($section['availability'] ?? null) && trim((string) $section['availability']) !== ''
|
|
? (string) $section['availability']
|
|
: 'missing';
|
|
$sectionLabel = $section['label'] ?? $section['key'] ?? 'Section';
|
|
$sectionSummary = $section['summary'] ?? 'No summary available.';
|
|
$actionReference = collect($references)
|
|
->first(static fn (array $reference): bool => is_string($reference['url'] ?? null) && trim((string) $reference['url']) !== '');
|
|
$actionReference = is_array($actionReference)
|
|
? $actionReference
|
|
: (is_array($references[0] ?? null) ? $references[0] : null);
|
|
$sectionActionUrl = is_array($actionReference) && is_string($actionReference['url'] ?? null) && trim((string) $actionReference['url']) !== ''
|
|
? (string) $actionReference['url']
|
|
: null;
|
|
$sectionActionLabel = is_array($actionReference)
|
|
? (string) ($actionReference['action_label'] ?? ($sectionActionUrl ? 'Open' : 'No action available'))
|
|
: 'No action available';
|
|
$sectionObservedText = $sectionObserved($section, $references);
|
|
@endphp
|
|
|
|
<x-filament::section
|
|
:heading="$sectionLabel"
|
|
compact
|
|
>
|
|
<x-slot name="afterHeader">
|
|
<x-filament::badge :color="$availabilityColor($availability)" size="sm">
|
|
{{ $availabilityLabel($availability) }}
|
|
</x-filament::badge>
|
|
</x-slot>
|
|
|
|
<div class="space-y-3">
|
|
<dl class="grid grid-cols-1 gap-3 text-sm md:grid-cols-4">
|
|
<div class="space-y-1">
|
|
<dt class="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">Status</dt>
|
|
<dd class="text-gray-950 dark:text-white">{{ $availabilityLabel($availability) }}</dd>
|
|
</div>
|
|
<div class="space-y-1 md:col-span-1">
|
|
<dt class="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">Why relevant</dt>
|
|
<dd class="leading-6 text-gray-700 dark:text-gray-200">{{ $sectionSummary }}</dd>
|
|
</div>
|
|
<div class="space-y-1 md:col-span-1">
|
|
<dt class="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">Observed</dt>
|
|
<dd class="leading-6 text-gray-700 dark:text-gray-200">{{ $sectionObservedText }}</dd>
|
|
</div>
|
|
<div class="space-y-1 md:col-span-1">
|
|
<dt class="text-xs font-medium uppercase tracking-wide text-gray-500 dark:text-gray-400">Action</dt>
|
|
<dd>
|
|
@if ($sectionActionUrl)
|
|
<x-filament::link
|
|
:href="$sectionActionUrl"
|
|
rel="noopener noreferrer"
|
|
size="sm"
|
|
target="_blank"
|
|
>
|
|
{{ $sectionActionLabel }}
|
|
</x-filament::link>
|
|
@else
|
|
<x-filament::badge color="gray" size="sm">
|
|
{{ $sectionActionLabel }}
|
|
</x-filament::badge>
|
|
@endif
|
|
</dd>
|
|
</div>
|
|
</dl>
|
|
|
|
@if ($references !== [])
|
|
<div class="divide-y divide-gray-200 border-t border-gray-200 dark:divide-white/10 dark:border-white/10">
|
|
@foreach ($references as $reference)
|
|
@php
|
|
$referenceLabel = $reference['label'] ?? 'Reference unavailable';
|
|
$referenceUrl = is_string($reference['url'] ?? null) && trim((string) $reference['url']) !== ''
|
|
? (string) $reference['url']
|
|
: null;
|
|
$referenceActionLabel = $reference['action_label'] ?? ($referenceUrl ? 'Open' : 'Unavailable');
|
|
@endphp
|
|
|
|
<div class="flex flex-wrap items-start justify-between gap-3 py-3">
|
|
<div class="space-y-1">
|
|
<p class="text-sm font-medium text-gray-950 dark:text-white">
|
|
{{ $referenceLabel }}
|
|
</p>
|
|
<p class="text-xs leading-5 text-gray-500 dark:text-gray-400">
|
|
{{ $referenceDescription($reference) }}
|
|
</p>
|
|
</div>
|
|
|
|
<div>
|
|
@if ($referenceUrl)
|
|
<x-filament::link
|
|
:href="$referenceUrl"
|
|
rel="noopener noreferrer"
|
|
size="sm"
|
|
target="_blank"
|
|
>
|
|
{{ $referenceActionLabel }}
|
|
</x-filament::link>
|
|
@else
|
|
<x-filament::badge color="gray" size="sm">
|
|
{{ $referenceActionLabel }}
|
|
</x-filament::badge>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
|
|
@if ($markers !== [])
|
|
<div class="flex flex-wrap gap-2">
|
|
@foreach ($markers as $marker)
|
|
<x-filament::badge color="warning" size="sm">
|
|
{{ trim((string) (($marker['replacement_text'] ?? '[REDACTED]').' '.Str::of((string) ($marker['reason'] ?? 'redacted'))->replace('_', ' '))) }}
|
|
</x-filament::badge>
|
|
@endforeach
|
|
</div>
|
|
@endif
|
|
</div>
|
|
</x-filament::section>
|
|
@endforeach
|
|
</div>
|
|
</div>
|