private/output/New-ErrorsTab.ps1
|
function New-ErrorsTab { <# .SYNOPSIS Creates the Errors tab with DataGrid for error records. #> [CmdletBinding()] param( [Parameter(Mandatory)] [hashtable]$Colors ) $errorsTab = [System.Windows.Controls.TabItem]@{ Header = "Errors" Visibility = 'Collapsed' } Set-TabItemStyle -TabItem $errorsTab # Container for errors display with toolbar, DataGrid and detail panel $errorsContainer = [System.Windows.Controls.Grid]::new() $errorsContainer.RowDefinitions.Add([System.Windows.Controls.RowDefinition]@{ Height = [System.Windows.GridLength]::Auto }) $errorsContainer.RowDefinitions.Add([System.Windows.Controls.RowDefinition]@{ Height = [System.Windows.GridLength]::new(1, [System.Windows.GridUnitType]::Star) }) $errorsContainer.RowDefinitions.Add([System.Windows.Controls.RowDefinition]@{ Height = [System.Windows.GridLength]::Auto }) # Errors toolbar - DockPanel for left/right alignment $errorsToolbar = [System.Windows.Controls.DockPanel]@{ Margin = [System.Windows.Thickness]::new(8, 8, 8, 4) } [System.Windows.Controls.Grid]::SetRow($errorsToolbar, 0) $filterPanel = [System.Windows.Controls.StackPanel]@{ Orientation = 'Horizontal' VerticalAlignment = 'Center' } [System.Windows.Controls.DockPanel]::SetDock($filterPanel, 'Left') $filterResult = New-FilterBoxWithClear -Width 180 -Height 26 -IncludeIcon $errorsFilterBox = $filterResult.TextBox [void]$filterPanel.Children.Add($filterResult.Icon) [void]$filterPanel.Children.Add($filterResult.Container) [void]$errorsToolbar.Children.Add($filterPanel) $rightPanel = [System.Windows.Controls.StackPanel]@{ Orientation = 'Horizontal' HorizontalAlignment = 'Right' VerticalAlignment = 'Center' } [System.Windows.Controls.DockPanel]::SetDock($rightPanel, 'Right') $errorsCopyInfo = New-UiIconButton -IconChar ([PsUi.ModuleContext]::GetIcon('Copy')) -ToolTip 'Copy All Errors' -Margin ([System.Windows.Thickness]::new(0, 0, 4, 0)) -ReturnIcon $errorsCopyBtn = $errorsCopyInfo.Button $errorsCopyIcon = $errorsCopyInfo.Icon [void]$rightPanel.Children.Add($errorsCopyBtn) $errorsExportInfo = New-UiIconButton -IconChar ([PsUi.ModuleContext]::GetIcon('Export')) -ToolTip 'Export Errors to CSV' -ReturnIcon $errorsExportBtn = $errorsExportInfo.Button $errorsExportIcon = $errorsExportInfo.Icon [void]$rightPanel.Children.Add($errorsExportBtn) [void]$errorsToolbar.Children.Add($rightPanel) [void]$errorsContainer.Children.Add($errorsToolbar) # Collection to hold error records for the DataGrid $errorsList = [System.Collections.ObjectModel.ObservableCollection[PSObject]]::new() # Create errors DataGrid $errorsDataGrid = [System.Windows.Controls.DataGrid]@{ IsReadOnly = $true AutoGenerateColumns = $false CanUserAddRows = $false CanUserDeleteRows = $false CanUserReorderColumns = $false SelectionMode = 'Extended' GridLinesVisibility = 'Horizontal' Background = ConvertTo-UiBrush $Colors.ControlBg BorderBrush = ConvertTo-UiBrush $Colors.Border RowBackground = ConvertTo-UiBrush $Colors.ControlBg AlternatingRowBackground = ConvertTo-UiBrush $(if ($Colors.AlternateBg) { $Colors.AlternateBg } else { $Colors.ControlBg }) HorizontalGridLinesBrush = ConvertTo-UiBrush $Colors.Border HeadersVisibility = 'Column' } $timeColumn = [System.Windows.Controls.DataGridTextColumn]::new() $timeColumn.Header = "Time" $timeColumn.Width = [System.Windows.Controls.DataGridLength]::new(75) $timeColumn.Binding = [System.Windows.Data.Binding]::new("Time") [void]$errorsDataGrid.Columns.Add($timeColumn) $lineColumn = [System.Windows.Controls.DataGridTextColumn]::new() $lineColumn.Header = "Line" $lineColumn.Width = [System.Windows.Controls.DataGridLength]::new(50) $lineColumn.Binding = [System.Windows.Data.Binding]::new("LineNumber") [void]$errorsDataGrid.Columns.Add($lineColumn) $categoryColumn = [System.Windows.Controls.DataGridTextColumn]::new() $categoryColumn.Header = "Category" $categoryColumn.Width = [System.Windows.Controls.DataGridLength]::new(100) $categoryColumn.Binding = [System.Windows.Data.Binding]::new("Category") [void]$errorsDataGrid.Columns.Add($categoryColumn) $messageColumn = [System.Windows.Controls.DataGridTextColumn]::new() $messageColumn.Header = "Message" $messageColumn.Width = [System.Windows.Controls.DataGridLength]::new(1, [System.Windows.Controls.DataGridLengthUnitType]::Star) $messageColumn.Binding = [System.Windows.Data.Binding]::new("Message") [void]$errorsDataGrid.Columns.Add($messageColumn) $errorsDataGrid.ItemsSource = $errorsList Set-DataGridStyle -Grid $errorsDataGrid New-DataGridContextMenu -DataGrid $errorsDataGrid [System.Windows.Controls.Grid]::SetRow($errorsDataGrid, 1) [void]$errorsContainer.Children.Add($errorsDataGrid) # Track unfiltered errors for collection-based filtering $unfilteredErrors = [System.Collections.Generic.List[object]]::new() $originalTag = $errorsFilterBox.Tag $errorsFilterBox.Tag = @{ DataGrid = $errorsDataGrid Timer = $null ClearButton = $originalTag.ClearButton Watermark = $originalTag.Watermark UnfilteredErrors = $unfilteredErrors ErrorsList = $errorsList } $errorsFilterBox.Add_TextChanged({ $tag = $this.Tag # Show/hide clear button and watermark $isEmpty = [string]::IsNullOrEmpty($this.Text) if ($tag.ClearButton) { $tag.ClearButton.Visibility = if ($isEmpty) { 'Collapsed' } else { 'Visible' } } if ($tag.Watermark) { $tag.Watermark.Visibility = if ($isEmpty) { 'Visible' } else { 'Collapsed' } } if ($tag.Timer) { $tag.Timer.Stop() $tag.Timer = $null } $timer = [System.Windows.Threading.DispatcherTimer]::new() $timer.Interval = [TimeSpan]::FromMilliseconds(250) $timer.Tag = $this $tag.Timer = $timer $timer.Add_Tick({ $this.Stop() $filterBox = $this.Tag $grid = $filterBox.Tag.DataGrid $text = $filterBox.Text.Trim().ToLower() $unfilteredList = $filterBox.Tag.UnfilteredErrors $errorsList = $filterBox.Tag.ErrorsList # Sync unfiltered list with any new errors added since last filter # (errors are added to errorsList dynamically) foreach ($item in $errorsList) { if (!$unfilteredList.Contains($item)) { [void]$unfilteredList.Add($item) } } # Capture sort state before rebuild $view = [System.Windows.Data.CollectionViewSource]::GetDefaultView($errorsList) $sortDescriptions = @() if ($view) { foreach ($sd in $view.SortDescriptions) { $sortDescriptions += $sd } } # Clear and repopulate $errorsList.Clear() foreach ($item in $unfilteredList) { if ([string]::IsNullOrEmpty($text)) { [void]$errorsList.Add($item) } else { $details = if ($item._ErrorDetails) { $item._ErrorDetails.ToString().ToLower() } else { '' } if ($details -like "*$text*") { [void]$errorsList.Add($item) } } } # Reapply sort if ($view -and $sortDescriptions.Count -gt 0) { $view.SortDescriptions.Clear() foreach ($sd in $sortDescriptions) { $view.SortDescriptions.Add($sd) } } }.GetNewClosure()) $timer.Start() }.GetNewClosure()) $errorsTab.Content = $errorsContainer return @{ Tab = $errorsTab Container = $errorsContainer DataGrid = $errorsDataGrid List = $errorsList FilterBox = $errorsFilterBox CopyButton = $errorsCopyBtn ExportButton = $errorsExportBtn } } |