From d8fdec4da77838db61e767f2bb9b214a1bb350c7 Mon Sep 17 00:00:00 2001 From: Johannes Date: Mon, 15 Jun 2026 16:18:30 -0400 Subject: [PATCH] fix(aria): rewrite filter UI to follow canonical template pattern PrecursorAlerts and DevicePosture were using custom inline select dropdowns for filtering. Both now use the canonical left filter sidebar with collapsible status-pills, active filter chips, and content-frame layout from hiveops-template/TablePage.svelte. Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/components/DevicePosture.svelte | 815 +++++++------ .../src/components/PrecursorAlerts.svelte | 1012 +++++++++-------- 2 files changed, 975 insertions(+), 852 deletions(-) diff --git a/frontend/src/components/DevicePosture.svelte b/frontend/src/components/DevicePosture.svelte index 48cff27..492909c 100644 --- a/frontend/src/components/DevicePosture.svelte +++ b/frontend/src/components/DevicePosture.svelte @@ -2,6 +2,7 @@ import { onMount } from 'svelte'; import { ariaApi, type DeviceSecurityPosture, type OsEolStatus } from '../lib/api'; import { addToast } from '../lib/stores'; + import Pagination from './common/Pagination.svelte'; let postures: DeviceSecurityPosture[] = []; let totalElements = 0; @@ -11,10 +12,13 @@ let loading = true; - // Filters + // Filter sidebar + let filterSidebarCollapsed = false; let filterScore: '' | 'low' | 'medium' = ''; let filterEol: OsEolStatus | '' = ''; + $: hasActiveFilters = !!filterScore || !!filterEol; + // Detail panel let panelOpen = false; let panelDevice: DeviceSecurityPosture | null = null; @@ -23,8 +27,8 @@ loading = true; try { const params: Record = { page, size: pageSize }; - if (filterScore) params.scoreFilter = filterScore; - if (filterEol) params.osEolStatus = filterEol; + if (filterScore) params.scoreFilter = filterScore; + if (filterEol) params.osEolStatus = filterEol; const res = await ariaApi.getPostures(params); postures = res.data.content; @@ -38,6 +42,25 @@ } } + function setScoreFilter(val: '' | 'low' | 'medium') { + filterScore = filterScore === val ? '' : val; + currentPage = 0; + load(0); + } + + function setEolFilter(val: OsEolStatus | '') { + filterEol = filterEol === val ? '' : val; + currentPage = 0; + load(0); + } + + function clearAllFilters() { + filterScore = ''; + filterEol = ''; + currentPage = 0; + load(0); + } + function openPanel(device: DeviceSecurityPosture) { panelDevice = device; panelOpen = true; @@ -50,7 +73,7 @@ return 'bad'; } - function eolLabel(s: OsEolStatus): string { + function eolLabel(s: OsEolStatus | string): string { if (s === 'SUPPORTED') return 'Supported'; if (s === 'EOL') return 'EOL'; return 'Unknown'; @@ -77,411 +100,478 @@ return !!(d.goldImageHash && d.currentImageHash && d.goldImageHash !== d.currentImageHash); } - function onFilterChange() { load(0); } - onMount(() => load(0)); -
+
+

Device Posture

Per-device security compliance — disk encryption, image integrity, OS currency

-
- {#if !loading} - {totalElements} device{totalElements !== 1 ? 's' : ''} +
+ +
+ + +
+ +
+ {#if !filterSidebarCollapsed} + Filters +
+ {totalElements} + +
+ {:else} + + {/if} +
+ + {#if !filterSidebarCollapsed} +
+ {#if hasActiveFilters} + + {/if} + +
+ +
+ + +
+
+ +
+ +
+ + + +
+
+
{/if}
-
-
-
-
- - -
+ +
-
- - -
-
+ {#if hasActiveFilters} +
+ Filters: + {#if filterScore} + + + Score: {filterScore === 'low' ? 'Low (<50)' : 'Below Good (<80)'} + + + {/if} + {#if filterEol} + + + OS: {eolLabel(filterEol)} + + + {/if} +
+ {/if} - -
+
+
- {#if loading} -
Loading…
- {:else if postures.length === 0} -
-
🔒
-
No posture data yet
-
Devices report posture via POST /api/aria/posture/report using the service secret
-
- {:else} -
- - - - - - - - - - - - - - - - - {#each postures as device (device.deviceId)} - - - - - - - - - - - - - {/each} - -
DeviceOS VersionOS StatusDisk Enc.Audit PolicyWhitelistImageScoreLast Check
{device.deviceAgentId ?? device.deviceId}{device.osVersion ?? '—'} - - {eolLabel(device.osEolStatus)} - - {boolCell(device.diskEncryptionEnabled)}{boolCell(device.auditPolicyCompliant)}{boolCell(device.softwareWhitelistEnabled)} - {#if imageMismatch(device)} - Drift - {:else if device.goldImageHash} - Match - {:else} - - {/if} - -
-
-
-
- - {device.postureScore ?? '—'} - +
+ {totalElements} device{totalElements !== 1 ? 's' : ''} +
+ +
+
+ +
+ { currentPage = e.detail.page; load(currentPage); }} + on:pageSizeChange={e => { currentPage = 0; load(0); }} + /> + +
+ {#if loading} +
Loading…
+ {:else if postures.length === 0} +
+ {hasActiveFilters ? 'No devices match the current filters.' : 'No posture data yet. Devices report posture via the ARIA signals module.'}
-
{formatDate(device.lastPostureCheckAt)} - -
-
+ {:else} + + + + + + + + + + + + + + + + + {#each postures as device (device.deviceId)} + openPanel(device)}> + + + + + + + + + + + + {/each} + +
DeviceOS VersionOS StatusDisk Enc.Audit PolicyWhitelistImageScoreLast Check
{device.deviceAgentId ?? device.deviceId}{device.osVersion ?? '—'} + + {eolLabel(device.osEolStatus)} + + {boolCell(device.diskEncryptionEnabled)}{boolCell(device.auditPolicyCompliant)}{boolCell(device.softwareWhitelistEnabled)} + {#if imageMismatch(device)} + Drift + {:else if device.goldImageHash} + Match + {:else} + + {/if} + +
+
+
+
+ + {device.postureScore ?? '—'} + +
+
{formatDate(device.lastPostureCheckAt)} + +
+ {/if} +
+
- {#if totalPages > 1} -
- {/if} - {/if} +
+
{#if panelOpen && panelDevice} - - -
{ panelOpen = false; panelDevice = null; }}>
-
+ +
{ panelOpen = false; panelDevice = null; }}>
+