Public/Add-DhTable.ps1
|
function Add-DhTable { <# .SYNOPSIS Add a sortable, filterable, pageable data table to a dashboard definition. .PARAMETER Report Dashboard object from New-DhDashboard. .PARAMETER TableId Unique identifier (alphanumeric, - or _). .PARAMETER Title Display heading. .PARAMETER Data Array of PSObjects or hashtables. .PARAMETER Columns Array of column definition hashtables. Auto-detected when omitted. Full column property reference: # Identity Field = 'PropertyName' # REQUIRED Label = 'Header Text' # REQUIRED Width = '120px' # optional fixed width Sortable = $false # default $true # Alignment Align = 'right' # 'left'(default) | 'center' | 'right' # Cell type CellType = 'progressbar' # 'text'(default) | 'progressbar' | 'badge' ProgressMax = 100 # denominator for progressbar # Number / value formatting (displayed in cell and exported) Format = 'number' # see Format values below Locale = 'en-US' # BCP-47 locale (default: browser locale) Decimals = 2 # decimal places Currency = 'USD' # for Format='currency' DatePattern = 'MM/dd/yyyy' # for Format='datetime' # Format values: # 'number' - locale number e.g. 12342.2 + en-US -> "12,342.20" # 'currency' - locale currency e.g. 1234.5 + en-US + USD -> "$1,234.50" # 'bytes' - auto KB/MB/GB/TB e.g. 1536000000 -> "1.43 GB" # 'percent' - appends % e.g. 0.856 -> "85.60 %" # 'datetime' - custom pattern e.g. "2026-03-19T14:00" -> "03/19/2026 14:00" # 'duration' - seconds -> "2h 14m 05s" # Text formatting Bold = $true # --- PINNED FIRST COLUMN --- PinFirst = $true # stick column during horizontal scroll # --- COLUMN FOOTER AGGREGATE --- Aggregate = 'sum' # 'sum'|'avg'|'min'|'max'|'count' — adds footer row Italic = $true Font = 'mono' # 'mono' | 'ui' | 'display' # Threshold colour rules - evaluated in order, first match wins # Numeric match: use Min / Max # String match: use Value (exact, case-insensitive) Thresholds = @( @{ Max = 70; Class = 'cell-ok' } # numeric: value < 70 @{ Min = 70; Max = 85; Class = 'cell-warn' } # numeric: 70 <= value < 85 @{ Class = 'cell-danger' } # catch-all # --- OR string matching --- @{ Value = 'Connected'; Class = 'cell-ok' } @{ Value = 'Maintenance'; Class = 'cell-warn' } @{ Value = 'NotResponding';Class = 'cell-danger' } ) # Row highlighting # When $true, the matching threshold class is applied to the ENTIRE ROW # (not just this cell). Useful for "if status=critical, highlight whole row" RowHighlight = $true .PARAMETER Charts Array of chart definitions: @{ Title='X'; Field='Y'; Type='pie' } .PARAMETER ExportFileName Custom base filename for downloaded exports (without extension). Default is the TableId. E.g. -ExportFileName 'servers-2026-03' produces servers-2026-03.csv, servers-2026-03.xlsx, servers-2026-03.pdf .PARAMETER PageSize Rows per page (default 15). .PARAMETER Sortable Enable column sort globally (default $true). .PARAMETER Filterable Show filter input (default $true). .PARAMETER Pageable Show pagination (default $true). .PARAMETER MultiSelect Checkbox multi-select (default $false). .PARAMETER Description Paragraph below the table title. #> [CmdletBinding()] param( [Parameter(Mandatory)] [System.Collections.Specialized.OrderedDictionary] $Report, [Parameter(Mandatory)] [ValidatePattern('^[A-Za-z0-9_-]+$')] [string] $TableId, [Parameter(Mandatory)] [string] $Title, [Parameter(Mandatory)] [object[]] $Data, [object[]] $Columns = @(), [object[]] $Charts = @(), [int] $PageSize = 15, [bool] $Sortable = $true, [bool] $Filterable = $true, [bool] $Pageable = $true, [switch] $MultiSelect, [string] $Description = '', [string] $ExportFileName = '', # custom filename for CSV/XLSX/PDF download [string] $NavGroup = '' # primary nav group label (enables two-tier nav) ) if ($Report.Tables | Where-Object { $_.Id -eq $TableId }) { throw "Add-DhTable: A table with Id '$TableId' already exists." } if ($Data.Count -eq 0) { Write-Warning "Add-DhTable: '$TableId' — Data array is empty. An empty table will be rendered." } # Auto-detect columns if ($Columns.Count -eq 0 -and $Data.Count -gt 0) { $first = $Data[0] $Columns = if ($first -is [hashtable] -or $first -is [System.Collections.Specialized.OrderedDictionary]) { $first.Keys | ForEach-Object { @{ Field = $_; Label = $_ } } } else { $first.PSObject.Properties | ForEach-Object { @{ Field = $_.Name; Label = $_.Name } } } } # Normalise columns - apply defaults for all recognised properties $normCols = foreach ($col in $Columns) { $c = @{} + $col if (-not $c.Contains('Sortable')) { $c['Sortable'] = $Sortable } if (-not $c.Contains('CellType')) { $c['CellType'] = 'text' } if (-not $c.Contains('ProgressMax')) { $c['ProgressMax'] = 100 } if (-not $c.Contains('Bold')) { $c['Bold'] = $false } if (-not $c.Contains('Italic')) { $c['Italic'] = $false } if (-not $c.Contains('Font')) { $c['Font'] = '' } if (-not $c.Contains('Align')) { $c['Align'] = 'left' } if (-not $c.Contains('Format')) { $c['Format'] = '' } if (-not $c.Contains('Locale')) { $c['Locale'] = '' } if (-not $c.Contains('Decimals')) { $c['Decimals'] = -1 } # -1 = not set if (-not $c.Contains('Currency')) { $c['Currency'] = '' } if (-not $c.Contains('DatePattern')) { $c['DatePattern'] = '' } if (-not $c.Contains('RowHighlight')) { $c['RowHighlight'] = $false } if (-not $c.Contains('PinFirst')) { $c['PinFirst'] = $false } if (-not $c.Contains('Aggregate')) { $c['Aggregate'] = '' } # sum|avg|min|max|count if (-not $c.Contains('Thresholds')) { $c['Thresholds'] = @() } $c } # Normalise data rows $normData = foreach ($row in $Data) { $h = [ordered]@{} if ($row -is [hashtable] -or $row -is [System.Collections.Specialized.OrderedDictionary]) { foreach ($k in $row.Keys) { $h[$k] = $row[$k] } } else { foreach ($p in $row.PSObject.Properties) { $h[$p.Name] = $p.Value } } $h } # Normalise charts $normCharts = foreach ($ch in $Charts) { $c = @{} + $ch if (-not $c.Contains('Type')) { $c['Type'] = 'pie' } if (-not $c.Contains('Title')) { $c['Title'] = $c['Field'] } $c } $Report.Tables.Add([ordered]@{ Id = $TableId Title = $Title Description = $Description Columns = @($normCols) Data = @($normData) Charts = @($normCharts) PageSize = $PageSize Sortable = $Sortable Filterable = $Filterable Pageable = $Pageable MultiSelect = $MultiSelect ExportFileName = $ExportFileName NavGroup = $NavGroup }) Write-Verbose "Add-DhTable: '$TableId' — $(@($normData).Count) rows, $(@($normCols).Count) cols, $(@($normCharts).Count) charts." } |