345 lines
16 KiB
PHP
345 lines
16 KiB
PHP
@php
|
|
use Illuminate\Support\Str;
|
|
|
|
// Extract state from Filament ViewEntry
|
|
$state = $getState();
|
|
$status = $state['status'] ?? 'success';
|
|
$warnings = $state['warnings'] ?? [];
|
|
$settings = $state['settings'] ?? [];
|
|
$settingsTable = $state['settings_table'] ?? null;
|
|
|
|
$policyType = $state['policy_type'] ?? null;
|
|
|
|
$stringifyValue = function (mixed $value): string {
|
|
if (is_null($value)) {
|
|
return 'N/A';
|
|
}
|
|
|
|
if (is_bool($value)) {
|
|
return $value ? 'Enabled' : 'Disabled';
|
|
}
|
|
|
|
if (is_scalar($value)) {
|
|
return (string) $value;
|
|
}
|
|
|
|
if (is_array($value)) {
|
|
$encoded = json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
|
|
|
return is_string($encoded) ? $encoded : 'N/A';
|
|
}
|
|
|
|
if (is_object($value)) {
|
|
if (method_exists($value, '__toString')) {
|
|
return (string) $value;
|
|
}
|
|
|
|
$encoded = json_encode((array) $value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
|
|
|
return is_string($encoded) ? $encoded : 'N/A';
|
|
}
|
|
|
|
return 'N/A';
|
|
};
|
|
|
|
$shouldRenderBadges = function (mixed $value): bool {
|
|
if (! is_array($value) || $value === []) {
|
|
return false;
|
|
}
|
|
|
|
if (! array_is_list($value)) {
|
|
return false;
|
|
}
|
|
|
|
foreach ($value as $item) {
|
|
if (! is_scalar($item) && ! is_null($item)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
$asEnabledDisabledBadgeValue = function (mixed $value): ?bool {
|
|
if (is_bool($value)) {
|
|
return $value;
|
|
}
|
|
|
|
if (! is_string($value)) {
|
|
return null;
|
|
}
|
|
|
|
$normalized = strtolower(trim($value));
|
|
|
|
return match ($normalized) {
|
|
'enabled', 'true', 'yes', '1' => true,
|
|
'disabled', 'false', 'no', '0' => false,
|
|
default => null,
|
|
};
|
|
};
|
|
@endphp
|
|
|
|
<div class="space-y-4">
|
|
{{-- Warnings --}}
|
|
@if(!empty($warnings))
|
|
<x-filament::section>
|
|
<div class="space-y-2">
|
|
@foreach($warnings as $warning)
|
|
<div class="flex items-start gap-2 text-sm text-warning-600 dark:text-warning-400">
|
|
<svg class="w-5 h-5 flex-shrink-0 mt-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
|
</svg>
|
|
<span>{{ $warning }}</span>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</x-filament::section>
|
|
@endif
|
|
|
|
{{-- Settings Table (for Settings Catalog legacy format) --}}
|
|
@if($settingsTable && !empty($settingsTable['rows']))
|
|
<x-filament::section
|
|
:heading="$settingsTable['title'] ?? 'Settings'"
|
|
:description="$settingsTable['description'] ?? null"
|
|
>
|
|
<x-slot name="headerEnd">
|
|
<span class="text-sm text-gray-500 dark:text-gray-400">
|
|
{{ count($settingsTable['rows']) }} {{ Str::plural('setting', count($settingsTable['rows'])) }}
|
|
</span>
|
|
</x-slot>
|
|
|
|
<div class="divide-y divide-gray-200 dark:divide-gray-700">
|
|
@foreach($settingsTable['rows'] as $row)
|
|
<div class="py-3 sm:grid sm:grid-cols-3 sm:gap-4">
|
|
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">
|
|
{{ $row['definition'] ?? $row['label'] ?? $row['path'] ?? 'Setting' }}
|
|
</dt>
|
|
<dd class="mt-1 sm:mt-0 sm:col-span-2">
|
|
<span class="text-sm text-gray-900 dark:text-white">
|
|
@php
|
|
$badgeValue = $asEnabledDisabledBadgeValue($row['value'] ?? null);
|
|
@endphp
|
|
|
|
@if(! is_null($badgeValue))
|
|
<x-filament::badge :color="$badgeValue ? 'success' : 'gray'" size="sm">
|
|
{{ $badgeValue ? 'Enabled' : 'Disabled' }}
|
|
</x-filament::badge>
|
|
@elseif(is_numeric($row['value']))
|
|
<span class="font-mono font-semibold">{{ $row['value'] }}</span>
|
|
@else
|
|
{{ $row['value'] ?? 'N/A' }}
|
|
@endif
|
|
</span>
|
|
</dd>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</x-filament::section>
|
|
@endif
|
|
|
|
{{-- Settings Blocks (for OMA Settings, Key/Value pairs, etc.) --}}
|
|
@foreach($settings as $block)
|
|
@php
|
|
$blockType = is_array($block) ? ($block['type'] ?? null) : null;
|
|
@endphp
|
|
|
|
@if($blockType === 'table')
|
|
<x-filament::section
|
|
:heading="$block['title'] ?? 'Settings'"
|
|
collapsible
|
|
>
|
|
<x-slot name="headerEnd">
|
|
<span class="text-sm text-gray-500 dark:text-gray-400">
|
|
{{ count($block['rows'] ?? []) }} {{ Str::plural('item', count($block['rows'] ?? [])) }}
|
|
</span>
|
|
</x-slot>
|
|
|
|
<div class="divide-y divide-gray-200 dark:divide-gray-700">
|
|
@foreach($block['rows'] ?? [] as $row)
|
|
<div class="py-3 sm:grid sm:grid-cols-3 sm:gap-4">
|
|
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 break-words">
|
|
{{ $row['label'] ?? $row['path'] ?? 'Setting' }}
|
|
|
|
@if (! empty($row['path']) && ($row['label'] ?? null) !== ($row['path'] ?? null))
|
|
<p class="mt-0.5 text-xs font-mono text-gray-400 dark:text-gray-500 break-all">
|
|
{{ (string) $row['path'] }}
|
|
</p>
|
|
@endif
|
|
@if(!empty($row['description']))
|
|
<p class="text-xs text-gray-400 mt-0.5">{{ Str::limit($row['description'], 80) }}</p>
|
|
@endif
|
|
</dt>
|
|
<dd class="mt-1 sm:mt-0 sm:col-span-2">
|
|
@php
|
|
$badgeValue = $asEnabledDisabledBadgeValue($row['value'] ?? null);
|
|
@endphp
|
|
|
|
@if(! is_null($badgeValue))
|
|
<x-filament::badge :color="$badgeValue ? 'success' : 'gray'" size="sm">
|
|
{{ $badgeValue ? 'Enabled' : 'Disabled' }}
|
|
</x-filament::badge>
|
|
@elseif(is_numeric($row['value']))
|
|
<span class="font-mono text-sm font-semibold text-gray-900 dark:text-white">
|
|
{{ $row['value'] }}
|
|
</span>
|
|
@elseif($shouldRenderBadges($row['value'] ?? null))
|
|
<div class="flex flex-wrap gap-1.5">
|
|
@foreach(($row['value'] ?? []) as $item)
|
|
<x-filament::badge color="gray" size="sm">
|
|
{{ is_bool($item) ? ($item ? 'Enabled' : 'Disabled') : (string) $item }}
|
|
</x-filament::badge>
|
|
@endforeach
|
|
</div>
|
|
@else
|
|
<span class="text-sm text-gray-900 dark:text-white break-words">
|
|
{{ Str::limit($stringifyValue($row['value'] ?? null), 200) }}
|
|
</span>
|
|
@endif
|
|
</dd>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</x-filament::section>
|
|
|
|
@elseif($blockType === 'keyValue')
|
|
<x-filament::section
|
|
:heading="$block['title'] ?? 'Settings'"
|
|
collapsible
|
|
>
|
|
<x-slot name="headerEnd">
|
|
<span class="text-sm text-gray-500 dark:text-gray-400">
|
|
{{ count($block['entries'] ?? []) }} {{ Str::plural('entry', count($block['entries'] ?? [])) }}
|
|
</span>
|
|
</x-slot>
|
|
|
|
<div class="divide-y divide-gray-200 dark:divide-gray-700">
|
|
@foreach($block['entries'] ?? [] as $entry)
|
|
<div class="py-3 sm:grid sm:grid-cols-3 sm:gap-4">
|
|
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400">
|
|
{{ $entry['key'] }}
|
|
</dt>
|
|
<dd class="mt-1 sm:mt-0 sm:col-span-2">
|
|
@php
|
|
$rawValue = $entry['value'] ?? null;
|
|
|
|
$isScriptContent = in_array($entry['key'] ?? null, ['scriptContent', 'detectionScriptContent', 'remediationScriptContent'], true)
|
|
&& (bool) config('tenantpilot.display.show_script_content', false);
|
|
|
|
$badgeValue = $asEnabledDisabledBadgeValue($rawValue);
|
|
@endphp
|
|
|
|
@if($isScriptContent)
|
|
@php
|
|
$code = is_string($rawValue) ? $rawValue : $stringifyValue($rawValue);
|
|
$firstLine = strtok($code, "\n") ?: '';
|
|
|
|
$grammar = 'powershell';
|
|
|
|
if ($policyType === 'deviceShellScript') {
|
|
$shebang = trim($firstLine);
|
|
|
|
if (str_starts_with($shebang, '#!')) {
|
|
if (str_contains($shebang, 'zsh')) {
|
|
$grammar = 'zsh';
|
|
} elseif (str_contains($shebang, 'bash')) {
|
|
$grammar = 'bash';
|
|
} else {
|
|
$grammar = 'sh';
|
|
}
|
|
} else {
|
|
$grammar = 'sh';
|
|
}
|
|
} elseif ($policyType === 'deviceManagementScript' || $policyType === 'deviceHealthScript') {
|
|
$grammar = 'powershell';
|
|
}
|
|
|
|
$highlightedHtml = null;
|
|
|
|
if (class_exists(\Torchlight\Engine\Engine::class)) {
|
|
try {
|
|
$highlightedHtml = (new \Torchlight\Engine\Engine())->codeToHtml(
|
|
code: $code,
|
|
grammar: $grammar,
|
|
theme: [
|
|
'light' => 'github-light',
|
|
'dark' => 'github-dark',
|
|
],
|
|
withGutter: false,
|
|
withWrapper: true,
|
|
);
|
|
} catch (\Throwable $e) {
|
|
$highlightedHtml = null;
|
|
}
|
|
}
|
|
@endphp
|
|
|
|
<div x-data="{ open: false }" class="space-y-2">
|
|
<div class="flex items-center gap-2">
|
|
<x-filament::button
|
|
size="xs"
|
|
color="gray"
|
|
type="button"
|
|
x-on:click="open = !open"
|
|
>
|
|
<span x-show="!open" x-cloak>Show</span>
|
|
<span x-show="open" x-cloak>Hide</span>
|
|
</x-filament::button>
|
|
|
|
<span class="text-xs text-gray-500 dark:text-gray-400">
|
|
{{ number_format(Str::length($code)) }} chars
|
|
</span>
|
|
</div>
|
|
|
|
<div x-show="open" x-cloak>
|
|
@if (is_string($highlightedHtml) && $highlightedHtml !== '')
|
|
@once
|
|
@include('filament.partials.torchlight-dark-overrides')
|
|
@endonce
|
|
|
|
<div class="overflow-x-auto">{!! $highlightedHtml !!}</div>
|
|
@else
|
|
<pre class="text-xs font-mono text-gray-900 dark:text-white whitespace-pre-wrap break-words">{{ $code }}</pre>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
@elseif($shouldRenderBadges($rawValue))
|
|
<div class="flex flex-wrap gap-1.5">
|
|
@foreach(($rawValue ?? []) as $item)
|
|
<x-filament::badge color="gray" size="sm">
|
|
{{ is_bool($item) ? ($item ? 'Enabled' : 'Disabled') : (string) $item }}
|
|
</x-filament::badge>
|
|
@endforeach
|
|
</div>
|
|
@elseif(! is_null($badgeValue))
|
|
<x-filament::badge :color="$badgeValue ? 'success' : 'gray'" size="sm">
|
|
{{ $badgeValue ? 'Enabled' : 'Disabled' }}
|
|
</x-filament::badge>
|
|
@else
|
|
<span class="text-sm text-gray-900 dark:text-white break-words">
|
|
{{ Str::limit($stringifyValue($rawValue), 200) }}
|
|
</span>
|
|
@endif
|
|
</dd>
|
|
</div>
|
|
@endforeach
|
|
</div>
|
|
</x-filament::section>
|
|
@endif
|
|
@endforeach
|
|
|
|
{{-- Empty state --}}
|
|
@if(empty($settings) && (!$settingsTable || empty($settingsTable['rows'])))
|
|
<div class="text-center py-12">
|
|
<svg class="mx-auto h-12 w-12 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
|
|
</svg>
|
|
<p class="mt-4 text-sm text-gray-500 dark:text-gray-400">
|
|
No settings data available
|
|
</p>
|
|
<p class="mt-1 text-xs text-gray-400 dark:text-gray-500">
|
|
This policy may not contain settings, or they are in an unsupported format
|
|
</p>
|
|
</div>
|
|
@endif
|
|
</div>
|