merge: agent session work
This commit is contained in:
commit
028fa817d1
@ -52,8 +52,25 @@ public static function infolist(Schema $schema): Schema
|
|||||||
|
|
||||||
// For Settings Catalog policies: Tabs with Settings table + JSON viewer
|
// For Settings Catalog policies: Tabs with Settings table + JSON viewer
|
||||||
Tabs::make('policy_content')
|
Tabs::make('policy_content')
|
||||||
|
->activeTab(1)
|
||||||
|
->persistTabInQueryString()
|
||||||
->tabs([
|
->tabs([
|
||||||
|
Tab::make('General')
|
||||||
|
->id('general')
|
||||||
|
->schema([
|
||||||
|
ViewEntry::make('policy_general')
|
||||||
|
->label('')
|
||||||
|
->view('filament.infolists.entries.policy-general')
|
||||||
|
->state(function (Policy $record) {
|
||||||
|
$normalized = static::normalizedPolicyState($record);
|
||||||
|
$split = static::splitGeneralBlock($normalized);
|
||||||
|
|
||||||
|
return $split['general'];
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
->visible(fn (Policy $record) => $record->versions()->exists()),
|
||||||
Tab::make('Settings')
|
Tab::make('Settings')
|
||||||
|
->id('settings')
|
||||||
->schema([
|
->schema([
|
||||||
ViewEntry::make('settings_catalog')
|
ViewEntry::make('settings_catalog')
|
||||||
->label('')
|
->label('')
|
||||||
@ -87,20 +104,8 @@ public static function infolist(Schema $schema): Schema
|
|||||||
->helperText('This policy has been inventoried but no configuration snapshot has been captured yet.')
|
->helperText('This policy has been inventoried but no configuration snapshot has been captured yet.')
|
||||||
->visible(fn (Policy $record) => ! $record->versions()->exists()),
|
->visible(fn (Policy $record) => ! $record->versions()->exists()),
|
||||||
]),
|
]),
|
||||||
Tab::make('General')
|
|
||||||
->schema([
|
|
||||||
ViewEntry::make('policy_general')
|
|
||||||
->label('')
|
|
||||||
->view('filament.infolists.entries.policy-general')
|
|
||||||
->state(function (Policy $record) {
|
|
||||||
$normalized = static::normalizedPolicyState($record);
|
|
||||||
$split = static::splitGeneralBlock($normalized);
|
|
||||||
|
|
||||||
return $split['general'];
|
|
||||||
}),
|
|
||||||
])
|
|
||||||
->visible(fn (Policy $record) => $record->versions()->exists()),
|
|
||||||
Tab::make('JSON')
|
Tab::make('JSON')
|
||||||
|
->id('json')
|
||||||
->schema([
|
->schema([
|
||||||
ViewEntry::make('snapshot_json')
|
ViewEntry::make('snapshot_json')
|
||||||
->view('filament.infolists.entries.snapshot-json')
|
->view('filament.infolists.entries.snapshot-json')
|
||||||
@ -336,12 +341,15 @@ private static function latestSnapshot(Policy $record): array
|
|||||||
*/
|
*/
|
||||||
private static function normalizedPolicyState(Policy $record): array
|
private static function normalizedPolicyState(Policy $record): array
|
||||||
{
|
{
|
||||||
static $cache = [];
|
$cacheKey = 'tenantpilot.normalizedPolicyState.'.(string) $record->getKey();
|
||||||
|
$request = request();
|
||||||
|
|
||||||
$cacheKey = (string) $record->getKey();
|
if ($request->attributes->has($cacheKey)) {
|
||||||
|
$cached = $request->attributes->get($cacheKey);
|
||||||
|
|
||||||
if (isset($cache[$cacheKey])) {
|
if (is_array($cached)) {
|
||||||
return $cache[$cacheKey];
|
return $cached;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$snapshot = static::latestSnapshot($record);
|
$snapshot = static::latestSnapshot($record);
|
||||||
@ -355,7 +363,7 @@ private static function normalizedPolicyState(Policy $record): array
|
|||||||
$normalized['context'] = 'policy';
|
$normalized['context'] = 'policy';
|
||||||
$normalized['record_id'] = (string) $record->getKey();
|
$normalized['record_id'] = (string) $record->getKey();
|
||||||
|
|
||||||
$cache[$cacheKey] = $normalized;
|
$request->attributes->set($cacheKey, $normalized);
|
||||||
|
|
||||||
return $normalized;
|
return $normalized;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,8 +25,18 @@
|
|||||||
@endif
|
@endif
|
||||||
|
|
||||||
@if (! empty($settingsTableRows))
|
@if (! empty($settingsTableRows))
|
||||||
<div class="space-y-2 rounded-md border border-gray-200 bg-white p-3 shadow-sm">
|
@php
|
||||||
<div class="text-sm font-semibold text-gray-800">{{ is_array($settingsTable) ? ($settingsTable['title'] ?? 'Settings') : 'Settings' }}</div>
|
$settingsTableTitle = is_array($settingsTable) ? ($settingsTable['title'] ?? null) : null;
|
||||||
|
$shouldShowTitle = is_string($settingsTableTitle)
|
||||||
|
&& $settingsTableTitle !== ''
|
||||||
|
&& ! ($context === 'policy' && strtolower($settingsTableTitle) === 'settings');
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<div class="space-y-2">
|
||||||
|
@if ($shouldShowTitle)
|
||||||
|
<div class="text-sm font-semibold text-gray-800">{{ $settingsTableTitle }}</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
<livewire:settings-catalog-settings-table
|
<livewire:settings-catalog-settings-table
|
||||||
:settings-rows="$settingsTableRows"
|
:settings-rows="$settingsTableRows"
|
||||||
:context="$context"
|
:context="$context"
|
||||||
|
|||||||
@ -90,16 +90,16 @@
|
|||||||
$isNumericValue = is_numeric($value);
|
$isNumericValue = is_numeric($value);
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
<div class="group relative overflow-hidden rounded-xl border border-gray-200/70 bg-gradient-to-br from-white via-amber-50/40 to-amber-100/60 p-4 shadow-sm transition duration-200 hover:-translate-y-0.5 hover:border-amber-200/70 hover:shadow-md dark:border-gray-700/60 dark:from-gray-950 dark:via-gray-900 dark:to-amber-950/30 dark:hover:border-amber-700/60">
|
<div class="tp-policy-general-card group relative overflow-hidden rounded-xl border border-gray-200/70 bg-white p-4 shadow-sm transition duration-200 hover:-translate-y-0.5 hover:border-gray-300/70 hover:shadow-md dark:border-gray-700/60 dark:bg-gray-900 dark:hover:border-gray-600">
|
||||||
<div class="flex items-start gap-3">
|
<div class="flex items-start gap-3">
|
||||||
<div class="flex h-10 w-10 items-center justify-center rounded-lg ring-1 {{ $tone['ring'] ?? '' }} {{ $toneClass }}">
|
<div class="flex h-10 w-10 items-center justify-center rounded-lg ring-1 {{ $tone['ring'] ?? '' }} {{ $toneClass }}">
|
||||||
<x-filament::icon icon="{{ $tone['icon'] ?? 'heroicon-o-document-text' }}" class="h-5 w-5" />
|
<x-filament::icon icon="{{ $tone['icon'] ?? 'heroicon-o-document-text' }}" class="h-5 w-5" />
|
||||||
</div>
|
</div>
|
||||||
<div class="min-w-0 flex-1">
|
<div class="min-w-0 flex-1">
|
||||||
<dt class="text-xs font-semibold uppercase tracking-wide text-gray-500 dark:text-gray-400">
|
<dt class="text-xs font-semibold tracking-wide text-gray-500 dark:text-gray-400">
|
||||||
{{ $entry['key'] ?? '-' }}
|
{{ $entry['key'] ?? '-' }}
|
||||||
</dt>
|
</dt>
|
||||||
<dd class="mt-2">
|
<dd class="mt-2 text-left">
|
||||||
@if ($isListValue)
|
@if ($isListValue)
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
@foreach ($value as $item)
|
@foreach ($value as $item)
|
||||||
@ -121,11 +121,11 @@
|
|||||||
{{ $boolLabel }}
|
{{ $boolLabel }}
|
||||||
</x-filament::badge>
|
</x-filament::badge>
|
||||||
@elseif ($isNumericValue)
|
@elseif ($isNumericValue)
|
||||||
<div class="text-lg font-semibold text-gray-900 dark:text-white tabular-nums">
|
<div class="text-sm font-semibold text-gray-900 dark:text-white tabular-nums">
|
||||||
{{ number_format((float) $value) }}
|
{{ number_format((float) $value) }}
|
||||||
</div>
|
</div>
|
||||||
@else
|
@else
|
||||||
<div class="text-sm text-gray-900 dark:text-white whitespace-pre-wrap break-words">
|
<div class="text-sm text-gray-900 dark:text-white whitespace-pre-wrap break-words text-left">
|
||||||
{{ is_string($value) ? $value : json_encode($value, JSON_PRETTY_PRINT) }}
|
{{ is_string($value) ? $value : json_encode($value, JSON_PRETTY_PRINT) }}
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
// Normalize payload to array for the JSON viewer
|
// Normalize payload to array for the JSON viewer
|
||||||
$payloadArray = is_string($payload) ? (json_decode($payload, true) ?? []) : ($payload ?? []);
|
$payloadArray = is_string($payload) ? (json_decode($payload, true) ?? []) : ($payload ?? []);
|
||||||
|
$rawJson = json_encode($payloadArray, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
// Provide the small set of helpers the pepperfm json view expects
|
// Provide the small set of helpers the pepperfm json view expects
|
||||||
$getState = fn () => $payloadArray;
|
$getState = fn () => $payloadArray;
|
||||||
@ -17,10 +18,51 @@
|
|||||||
$getRenderMode = fn () => \PepperFM\FilamentJson\Enums\RenderModeEnum::Tree;
|
$getRenderMode = fn () => \PepperFM\FilamentJson\Enums\RenderModeEnum::Tree;
|
||||||
$getInitiallyCollapsed = fn () => 1;
|
$getInitiallyCollapsed = fn () => 1;
|
||||||
$getExpandAllToggle = fn () => false;
|
$getExpandAllToggle = fn () => false;
|
||||||
$getCopyJsonAction = fn () => true;
|
$getCopyJsonAction = fn () => false;
|
||||||
$getMaxDepth = fn () => 3;
|
$getMaxDepth = fn () => 3;
|
||||||
$applyLimit = fn ($v) => $v;
|
$applyLimit = fn ($v) => $v;
|
||||||
@endphp
|
@endphp
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="space-y-2"
|
||||||
|
x-data="{
|
||||||
|
text: @js($rawJson),
|
||||||
|
async copyJson() {
|
||||||
|
try {
|
||||||
|
if (navigator.clipboard && (location.protocol === 'https:' || location.hostname === 'localhost')) {
|
||||||
|
await navigator.clipboard.writeText(this.text);
|
||||||
|
} else {
|
||||||
|
const ta = document.createElement('textarea');
|
||||||
|
ta.value = this.text;
|
||||||
|
ta.style.position = 'fixed';
|
||||||
|
ta.style.inset = '0';
|
||||||
|
document.body.appendChild(ta);
|
||||||
|
ta.focus();
|
||||||
|
ta.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
ta.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
new FilamentNotification()
|
||||||
|
.title('Copied!')
|
||||||
|
.icon('heroicon-o-clipboard-document-check')
|
||||||
|
.success()
|
||||||
|
.send();
|
||||||
|
} catch (e) {
|
||||||
|
new FilamentNotification()
|
||||||
|
.title('Copy failed!')
|
||||||
|
.danger()
|
||||||
|
.send();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div class="flex items-center justify-end">
|
||||||
|
<x-filament::button size="xs" color="gray" x-on:click="copyJson()">
|
||||||
|
Copy JSON
|
||||||
|
</x-filament::button>
|
||||||
|
</div>
|
||||||
|
|
||||||
{{-- Render pepperfm filament-json viewer --}}
|
{{-- Render pepperfm filament-json viewer --}}
|
||||||
@include('filament-json::json')
|
@include('filament-json::json')
|
||||||
|
</div>
|
||||||
|
|||||||
@ -80,7 +80,8 @@
|
|||||||
$response->assertSee('Settings'); // Settings tab should appear for Settings Catalog
|
$response->assertSee('Settings'); // Settings tab should appear for Settings Catalog
|
||||||
$response->assertSee('General');
|
$response->assertSee('General');
|
||||||
$response->assertSee('JSON');
|
$response->assertSee('JSON');
|
||||||
$response->assertSee('bg-gradient-to-br');
|
$response->assertSee('tp-policy-general-card');
|
||||||
|
$response->assertSee('Copy JSON');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('shows display names instead of definition IDs', function () {
|
it('shows display names instead of definition IDs', function () {
|
||||||
|
|||||||
@ -59,7 +59,7 @@
|
|||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
|
|
||||||
$policyResponse = $this->actingAs($user)
|
$policyResponse = $this->actingAs($user)
|
||||||
->get(PolicyResource::getUrl('view', ['record' => $policy]));
|
->get(PolicyResource::getUrl('view', ['record' => $policy]).'?tab=settings');
|
||||||
|
|
||||||
$policyResponse->assertOk();
|
$policyResponse->assertOk();
|
||||||
$policyResponse->assertSee('fi-width-full');
|
$policyResponse->assertSee('fi-width-full');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user