Public/Add-DhEventFeed.ps1
|
function Add-DhEventFeed { <# .SYNOPSIS Add a chronological event-feed block — severity-tagged audit trail. .DESCRIPTION Renders a list of timestamped events with severity colour-coding. Per the IT-infrastructure KPI dashboard specification (§4.1 and §4.2), the event feed is the canonical "Row 5" of an ops dashboard — the evidence trail that pairs with the at-a-glance KPI tiles above. Distinct from Add-DhAlertBanner: a banner surfaces a single CURRENT condition (visible at the top of the page until dismissed); an event feed lists a chronological history (typically the last N events from a log query). .PARAMETER Report Dashboard object from New-DhDashboard. .PARAMETER Id Unique identifier (alphanumeric, dash, underscore). .PARAMETER Title Block heading shown above the list. .PARAMETER Events Array of event hashtables. Per event: @{ Timestamp = '2026-05-22 14:32' # REQUIRED — free-form string Severity = 'critical' # REQUIRED — info | ok | warning | critical Message = 'Replication failure to DC03' # REQUIRED — the event text Source = 'DC01' # optional — origin tag, shown in brackets Icon = '!' # optional — overrides default severity glyph } .PARAMETER MaxItems Cap on the number of events shown. Defaults to 50. Older events are dropped after the sort+slice. Range 1..1000. .PARAMETER GroupBy Optional grouping: 'None' (default), 'Severity', or 'Source'. When grouped, the events within each group are still ordered by Timestamp; groups themselves appear in a fixed priority order (Severity: critical > warning > ok > info; Source: alphabetical). .PARAMETER SortDescending Newest-first by Timestamp. Default $true. Set $false to show oldest events at the top (chronological reading order). .PARAMETER NavGroup Primary nav group label (enables two-tier nav). .PARAMETER NavSubGroup Optional second-level group under NavGroup. .EXAMPLE Add-DhEventFeed -Report $report -Id 'recent-events' ` -Title 'Recent events (24h)' -MaxItems 50 ` -Events @( @{ Timestamp='2026-05-22 14:32'; Severity='critical'; Source='DC01'; Message='Replication failure to DC03' } @{ Timestamp='2026-05-22 14:18'; Severity='warning'; Source='DC02'; Message='LDAP bind time > 80 ms (avg)' } @{ Timestamp='2026-05-22 13:55'; Severity='info'; Source='vSphere'; Message='vMotion: VM-027 → ESXi-04' } ) .EXAMPLE # Group by severity so critical entries float to the top Add-DhEventFeed -Report $report -Id 'incidents-by-sev' ` -Title 'Open incidents' -GroupBy 'Severity' ` -Events $incidents #> [CmdletBinding()] param( [Parameter(Mandatory)] [System.Collections.Specialized.OrderedDictionary] $Report, [Parameter(Mandatory)] [ValidatePattern('^[A-Za-z0-9_-]+$')] [string] $Id, [Parameter(Mandatory)] [string] $Title, [Parameter(Mandatory)] [object[]] $Events, [ValidateRange(1, 1000)] [int] $MaxItems = 50, [ValidateSet('None','Severity','Source')] [string] $GroupBy = 'None', [bool] $SortDescending = $true, [string] $NavGroup = '', [string] $NavSubGroup = '' ) if (-not $Report.Contains('Blocks')) { $Report['Blocks'] = [System.Collections.Generic.List[hashtable]]::new() } foreach ($existing in $Report.Blocks) { if ($existing.Id -eq $Id) { throw "Add-DhEventFeed: A block with Id '$Id' already exists in this report. Use a unique Id." } } if (-not $Events -or $Events.Count -lt 1) { throw "Add-DhEventFeed: -Events must contain at least one event." } $allowedSeverities = @('info','ok','warning','critical') $normEvents = foreach ($e in $Events) { if ($e -isnot [hashtable] -and $e -isnot [System.Collections.Specialized.OrderedDictionary]) { throw "Add-DhEventFeed: each event must be a hashtable. Got: $($e.GetType().Name)" } foreach ($req in 'Timestamp','Severity','Message') { if (-not $e.Contains($req) -or [string]::IsNullOrWhiteSpace([string]$e[$req])) { throw "Add-DhEventFeed: each event must have a non-empty '$req' key." } } $sev = ([string]$e['Severity']).ToLowerInvariant() if ($sev -notin $allowedSeverities) { throw "Add-DhEventFeed: event Severity must be 'info', 'ok', 'warning', or 'critical'. Got: $($e['Severity'])" } @{ Timestamp = [string]$e['Timestamp'] Severity = $sev Message = [string]$e['Message'] Source = if ($e.Contains('Source') -and $null -ne $e['Source']) { [string]$e['Source'] } else { '' } Icon = if ($e.Contains('Icon') -and $null -ne $e['Icon']) { [string]$e['Icon'] } else { '' } } } $Report.Blocks.Add([ordered]@{ BlockType = 'eventfeed' Id = $Id Title = $Title Events = @($normEvents) MaxItems = $MaxItems GroupBy = $GroupBy.ToLowerInvariant() SortDescending = [bool]$SortDescending NavGroup = $NavGroup NavSubGroup = $NavSubGroup }) Write-Verbose "Add-DhEventFeed: '$Id' ($($normEvents.Count) event(s), max=$MaxItems, groupBy=$GroupBy)." } |