feat(007): device config & compliance snapshot/restore improvements #9

Merged
ahmido merged 18 commits from feat/007-device-config-compliance into dev 2025-12-29 12:46:20 +00:00
3 changed files with 179 additions and 1 deletions
Showing only changes of commit 1b2892d60b - Show all commits

View File

@ -14,10 +14,114 @@ public function mount(PolicyVersion $version): void
$this->version = $version; $this->version = $version;
} }
public function render() public function render(): \Illuminate\Contracts\View\View
{ {
return view('livewire.policy-version-assignments-widget', [ return view('livewire.policy-version-assignments-widget', [
'version' => $this->version, 'version' => $this->version,
'compliance' => $this->complianceNotifications(),
]); ]);
} }
/**
* @return array{total:int,templates:array<int,string>,items:array<int,array{rule_name:?string,template_id:string,template_key:string}>}
*/
private function complianceNotifications(): array
{
if ($this->version->policy_type !== 'deviceCompliancePolicy') {
return [
'total' => 0,
'templates' => [],
'items' => [],
];
}
$snapshot = $this->version->snapshot;
if (! is_array($snapshot)) {
return [
'total' => 0,
'templates' => [],
'items' => [],
];
}
$scheduled = $snapshot['scheduledActionsForRule'] ?? null;
if (! is_array($scheduled)) {
return [
'total' => 0,
'templates' => [],
'items' => [],
];
}
$items = [];
$templateIds = [];
foreach ($scheduled as $rule) {
if (! is_array($rule)) {
continue;
}
$ruleName = $rule['ruleName'] ?? null;
$configs = $rule['scheduledActionConfigurations'] ?? null;
if (! is_array($configs)) {
continue;
}
foreach ($configs as $config) {
if (! is_array($config)) {
continue;
}
if (($config['actionType'] ?? null) !== 'notification') {
continue;
}
$templateKey = $this->resolveNotificationTemplateKey($config);
if ($templateKey === null) {
continue;
}
$templateId = $config[$templateKey] ?? null;
if (! is_string($templateId) || $templateId === '' || $this->isEmptyGuid($templateId)) {
continue;
}
$items[] = [
'rule_name' => is_string($ruleName) ? $ruleName : null,
'template_id' => $templateId,
'template_key' => $templateKey,
];
$templateIds[] = $templateId;
}
}
return [
'total' => count($items),
'templates' => array_values(array_unique($templateIds)),
'items' => $items,
];
}
private function resolveNotificationTemplateKey(array $config): ?string
{
if (array_key_exists('notificationTemplateId', $config)) {
return 'notificationTemplateId';
}
if (array_key_exists('notificationMessageTemplateId', $config)) {
return 'notificationMessageTemplateId';
}
return null;
}
private function isEmptyGuid(string $value): bool
{
return strtolower($value) === '00000000-0000-0000-0000-000000000000';
}
} }

View File

@ -155,4 +155,46 @@
</div> </div>
</div> </div>
@endif @endif
@php
$complianceTotal = $compliance['total'] ?? 0;
$complianceTemplates = $compliance['templates'] ?? [];
@endphp
@if($complianceTotal > 0)
<div class="mt-6 rounded-lg bg-white shadow-sm ring-1 ring-gray-950/5 dark:bg-gray-900 dark:ring-white/10">
<div class="px-6 py-4">
<div class="flex items-center justify-between">
<div>
<h3 class="text-base font-semibold leading-6 text-gray-950 dark:text-white">
Compliance notifications
</h3>
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">
{{ $complianceTotal }} action(s) {{ count($complianceTemplates) }} template(s)
</p>
</div>
</div>
</div>
<div class="border-t border-gray-200 px-6 py-4 dark:border-white/10">
<div class="space-y-2">
@foreach($compliance['items'] ?? [] as $item)
@php
$ruleName = $item['rule_name'] ?? null;
$templateId = $item['template_id'] ?? null;
@endphp
<div class="flex items-center gap-2 text-sm">
<span class="text-gray-600 dark:text-gray-400"></span>
<span class="font-medium text-gray-900 dark:text-white">
{{ $ruleName ?: 'Unnamed rule' }}
</span>
@if($templateId)
<span class="text-xs text-gray-500 dark:text-gray-500">
Template: {{ $templateId }}
</span>
@endif
</div>
@endforeach
</div>
</div>
</div>
@endif
</div> </div>

View File

@ -112,3 +112,35 @@
$response->assertOk(); $response->assertOk();
$response->assertSee('No assignments found for this version'); $response->assertSee('No assignments found for this version');
}); });
it('shows compliance notifications when present', function () {
$version = PolicyVersion::factory()->create([
'tenant_id' => $this->tenant->id,
'policy_id' => $this->policy->id,
'version_number' => 1,
'policy_type' => 'deviceCompliancePolicy',
'assignments' => null,
'snapshot' => [
'scheduledActionsForRule' => [
[
'ruleName' => 'Test rule',
'scheduledActionConfigurations' => [
[
'actionType' => 'notification',
'notificationTemplateId' => 'template-123',
],
],
],
],
],
]);
$this->actingAs($this->user);
$response = $this->get("/admin/policy-versions/{$version->id}");
$response->assertOk();
$response->assertSee('Compliance notifications');
$response->assertSee('Test rule');
$response->assertSee('template-123');
});