functions/private/tui-helpers.ps1
#helper functions for Open-PSWorkItemConsole Function ConvertTo-DataTable { [cmdletbinding()] [OutputType('System.Data.DataTable')] Param( [Parameter( Mandatory, Position = 0, ValueFromPipeline )] [ValidateNotNullOrEmpty()] [object]$InputObject ) Begin { Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Starting $($MyInvocation.MyCommand)" Write-Verbose "[$((Get-Date).TimeOfDay) BEGIN ] Running under PowerShell version $($PSVersionTable.PSVersion)" $data = [System.Collections.Generic.List[object]]::New() $Table = [System.Data.DataTable]::New('PSData') } #begin Process { $Data.Add($InputObject) } #process End { Write-Verbose "[$((Get-Date).TimeOfDay) END ] Building a table of $($data.count) items" #define columns foreach ($item in $data[0].PSObject.Properties) { Write-Verbose "[$((Get-Date).TimeOfDay) END ] Defining column $($item.name)" [void]$table.Columns.Add($item.Name, $item.TypeNameOfValue) } #add rows for ($i = 0; $i -lt $Data.count; $i++) { $row = $table.NewRow() foreach ($item in $Data[$i].PSObject.Properties) { $row.Item($item.name) = $item.Value } [void]$table.Rows.Add($row) } #This is a trick to return the table object #as the output and not the rows , $table Write-Verbose "[$((Get-Date).TimeOfDay) END ] Ending $($MyInvocation.MyCommand)" } #end } #close ConvertTo-DataTable Function ClearForm { #clear entry forms but leave category and path [CmdletBinding()] Param() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" $txtTaskName.Text = '' $txtDescription.Text = '' $chkWhatIf.Checked = $False $txtProgress.Text = '' $dropCategory.SelectedItem = $script:DefaultCategoryIndex $txtDays.Text = 30 $txtDueDate.Text = '' $radioGrp.SelectedItem = 0 $lblOverDue.Visible = $False $StatusBar.Items[0].Title = Get-Date -Format g $StatusBar.Items[3].Title = 'Ready' $FilterDays.Text = '' $txtTaskName.SetFocus() [Terminal.Gui.Application]::Refresh() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" } Function ResetForm { [CmdletBinding()] Param( ) Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" $txtTaskName.Text = '' $txtDescription.Text = '' $chkWhatIf.Checked = $False $txtProgress.Text = '' $dropCategory.SelectedItem = $script:DefaultCategoryIndex $txtDays.Text = 30 $txtDueDate.Text = '' $radioGrp.SelectedItem = 0 $lblOverDue.Visible = $False $StatusBar.Items[3].Title = Get-Date -Format g $StatusBar.Items[3].Title = 'Ready' $chkFilterTable.Checked = $False $txtTaskName.SetFocus() $txtPath.Text = $PSWorkItemPath $FilterDays.Text = '' RefreshCategoryList RefreshTable [Terminal.Gui.Application]::Refresh() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" } Function ShowHelp { [CmdletBinding()] Param() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" $title = 'Open-PSWorkItemConsole' $getHelp = Get-Help Open-PSWorkItemConsole #(Get-Help Open-PSWorkItemConsole).Description.Text | Out-String #$(($getHelp.Description.Text | Out-String).Trim()) #$(($getHelp.AlertSet.Alert | Out-String).Trim()) $help = @" This command will launch a terminal-based console for managing PSWorkItems. You can select items from the table which will populate the entry forms. You can then modify the work item and click Set-PSWorkItem, or you can mark the item as complete or remove it. To enter a new PSWorkItem, use Options - Clear Form. Enter your new item, selecting a category from the list, and click the Add New PSWorkItem button. You cannot set a progress value when creating a new work item. Use the category menu options to add, set, or remove a category. You can right-click a task in the table to show detailed information. You can also enter a different database path by entering the path in the Database field, or using Options - Open database. Use the Reset Form option to reset the form with your default settings. You cannot specify a PSWorkItem completion date using this tool. If you have difficulty seeing the cursor in text fields, and you are running in Windows Terminal, you might try changing the cursor in your Windows Terminal profile setting. The TUI color scheme is also influenced by the Windows Terminal color scheme. You may also have to adjust the zoom level in Windows Terminal to see the entire form. "@ $dialog = [Terminal.Gui.Dialog]@{ Title = 'Help Open-PSWorkItemConsole' TextAlignment = 'Left' Width = 75 Height = 30 Text = $help } $ok = [Terminal.Gui.Button]@{ Text = 'OK' } $ok.Add_Clicked({ $dialog.RequestStop() }) $dialog.AddButton($ok) Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Invoking dialog" [Terminal.Gui.Application]::Run($dialog) Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" } Function RefreshTable { [CmdletBinding()] Param( [string]$FilterCategory = '*', [int]$DaysDue ) Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" $TableView.RemoveAll() $TableView.Clear() #4 Jan 2024 format due date with leading zeros and no seconds $cult = Get-Culture if ($DaysDue -gt 0) { $Items = Get-PSWorkItem -Path $txtPath.Text.ToString() -DaysDue $DaysDue } else { $items = Get-PSWorkItem -Path $txtPath.Text.ToString() -All } $Data = $Items | Where-Object { $_.Category -Like $FilterCategory } | Select-Object ID, Name, Description, @{Name = 'Due'; Expression = { if ($cult.DateTimeFormat.ShortDatePattern -match "^M/d/yyyy$") { "{0:MM/dd/yyyy hh:mm tt}" -f $_.DueDate } else { "{0:$($cult.DateTimeFormat.ShortDatePattern) $($cult.DateTimeFormat.LongTimePattern)}" -f $_.DueDate } }}, Progress, Category, OverDue | ConvertTo-DataTable $TableView.Table = $Data <# Black Blue Green Cyan Red Magenta Brown Gray DarkGray BrightBlue BrightGreen BrightCyan BrightRed BrightMagenta BrightYellow White #> $TableView.Style.RowColorGetter = { Param ($Table) $item = $table.Table.Rows[$Table.RowIndex] $due = $item.Due -as [DateTime] $ts = New-TimeSpan -Start (Get-Date) -End $due $cs = [Terminal.Gui.ColorScheme]::new() $bg =$window.ColorScheme.Normal.Background if ($Item.OverDue) { $cs.Normal = [Terminal.Gui.Attribute]::new("BrightRed", $bg) $cs } elseif ($ts.TotalDays -le 5 ) { #highlight tasks due in the next 5 days $cs.Normal = [Terminal.Gui.Attribute]::new("Cyan", $bg) $cs } } $TableView.Style.ColumnStyles.Add( $TableView.Table.Columns['ID'], [Terminal.Gui.TableView+ColumnStyle]@{ Alignment = 'Right' MinWidth = 4 } ) $TableView.Style.ColumnStyles.Add( $TableView.Table.Columns['Name'], [Terminal.Gui.TableView+ColumnStyle]@{ Alignment = 'Left' MinWidth =30 } ) $TableView.Style.ColumnStyles.Add( $TableView.Table.Columns['Description'], [Terminal.Gui.TableView+ColumnStyle]@{ Alignment = 'Left' MinWidth =35 } ) $TableView.Style.ColumnStyles.Add( $TableView.Table.Columns['Progress'], [Terminal.Gui.TableView+ColumnStyle]@{ Alignment = 'Right' RepresentationGetter = { Param($item) "{0}% " -f $item } } ) $TableView.Style.ColumnStyles.Add( $TableView.Table.Columns['Due'], [Terminal.Gui.TableView+ColumnStyle]@{ Alignment = 'Justified' MinWidth = 22 } ) #hide the OverDue column since it is represented in Red #this allows more space for other columns $TableView.Style.ColumnStyles.Add( $TableView.Table.Columns['OverDue'], [Terminal.Gui.TableView+ColumnStyle]@{ Alignment = 'Right' Visible = $False } ) $TableView.SetNeedsDisplay() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" } Function RefreshCategoryList { [CmdletBinding()] Param() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" $src = (Get-PSWorkItemCategory -Path $txtPath.Text.ToString()).Category | Sort-Object $src | Write-Verbose #create a lookup list $script:CatList = [System.Collections.Generic.List[string]]::New() $script:CatList.AddRange([string[]]$src) if ($global:PSDefaultParameterValues.ContainsKey("New-PSWorkItem:Category")) { $DefaultCategory = $global:PSDefaultParameterValues["New-PSWorkItem:Category"] Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Default category is $DefaultCategory" $script:DefaultCategoryIndex = $script:CatList.FindIndex({$args[0] -eq $DefaultCategory}) } else { $script:DefaultCategoryIndex = 0 } Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Using default category index $($script:DefaultCategoryIndex)" $dropCategory.Clear() $dropCategory.SetSource($src) $dropCategory.SelectedItem = $script:DefaultCategoryIndex $dropCategory.EnsureSelectedItemVisible() $dropCategory.SetNeedsDisplay() [Terminal.Gui.Application]::Refresh() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" } Function UpdateReport { Param() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" $lblReport.Text = (Get-PSWorkItemReport -Path $txtPath.Text.ToString() | Format-Table Category, Count, PctTotal | Out-String).Trim() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" } Function ShowWhatIf { Param( [ValidateSet('New', 'Set', 'Complete', 'Remove')] [string]$Command, [string]$ID ) Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" Switch ($command) { 'New' { $cmd = 'New-PSWorkItem' $cat = $dropCategory.Source.ToList()[$dropCategory.SelectedItem] if ($txtDays.Enabled) { #calculate Date $due = (Get-Date).AddDays( $txtDays.Text.ToString()) } else { $due = $txtDueDate.Text.ToString() } $msg = @" $cmd PSWorkItem: {0} [{1}] Description: {3} Due: {4} Using database: {2} "@ -f $txtTaskName.Text.ToString(), $cat, $txtPath.Text.ToString(), $txtDescription.Text.ToString(), $due } 'Set' { $cmd = 'Set-PSWorkItem' $cat = $dropCategory.Source.ToList()[$dropCategory.SelectedItem] if ($txtDays.Enabled) { #calculate Date $due = (Get-Date).AddDays( $txtDays.Text.ToString()) } else { $due = $txtDueDate.Text.ToString() } $msg = @" $cmd ID : $ID PSWorkItem: {0} [{1}] Description: {3} Progress: {5} Due: {4} Using database: {2} "@ -f $txtTaskName.Text.ToString(), $cat, $txtPath.Text.ToString(), $txtDescription.Text.ToString(), $due, $txtProgress.Text.ToString() } 'Complete' { $cmd = 'Complete-PSWorkItem' $msg = @" $cmd PSWorkItem : {0} [ID {1}] Using database: {2} "@ -f $txtTaskName.Text.ToString(), $ID, $txtPath.Text.ToString() } 'Remove' { $cmd = 'Remove-PSWorkItem' $msg = @" $cmd PSWorkItem : {0} [ID {1}] Using database: {2} "@ -f $txtTaskName.Text.ToString(), $ID, $txtPath.Text.ToString() } } #switch Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Show message box" [Terminal.Gui.MessageBox]::Query('WhatIf Operation', $msg, @('Ok')) Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" } Function OpenDatabase { [CmdletBinding()] Param() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" $Dialog = [Terminal.Gui.OpenDialog]::new('Open PSWorkItem Database', '') $Dialog.CanChooseDirectories = $false $Dialog.CanChooseFiles = $true $Dialog.AllowsMultipleSelection = $false $Dialog.DirectoryPath = $HOME $Dialog.AllowedFileTypes = @('.db') [Terminal.Gui.Application]::Run($Dialog) If (-Not $Dialog.Canceled -AND $dialog.FilePath.ToString()) { $txtPath.Text = $dialog.FilePath.ToString() RefreshCategoryList RefreshTable } Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" } Function ShowAbout { [CmdletBinding()] Param() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" $TerminalGuiVersion = [System.Reflection.Assembly]::GetAssembly([Terminal.Gui.Application]).GetName().version $NStackVersion = [System.Reflection.Assembly]::GetAssembly([NStack.UString]).GetName().version $SQLiteVersion = [System.Reflection.Assembly]::GetAssembly([System.Data.Sqlite.SqLiteConnection]).GetName().version $about = @" PSWorkItem: $scriptVer mySQLite: $((Get-Module mySQLite).version.ToString()) PSVersion: $($PSVersionTable.PSVersion) Terminal.Gui: $TerminalGuiVersion NStack: $NStackVersion System.Data.SQLite: $SQLiteVersion "@ $dialog = [Terminal.Gui.Dialog]@{ Title = 'About Open-PSWorkItemConsole' TextAlignment = 'Left' Width = 40 Height = 12 Text = $about } $ok = [Terminal.Gui.Button]@{ Text = 'OK' } $ok.Add_Clicked({ $dialog.RequestStop() }) $dialog.AddButton($ok) Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Invoking dialog" [Terminal.Gui.Application]::Run($dialog) #Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Show message box" # Replaced 24 Feb 2024 with a dialog which allows for better formatting #[Terminal.Gui.MessageBox]::Query('About Open-PSWorkItemConsole', $About, @('Ok')) Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" } Function UpdateStatusTime { [CmdletBinding()] Param() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" $StatusBar.Items[0].Title = Get-Date -Format g [Terminal.Gui.Application]::Refresh() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" #need to return a Boolean result Return $True } Function Populate { [CmdletBinding()] Param() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" <# sample $TableView.table.rows[$TableView.SelectedRow] ID : 21 Name : Blog updates Description : update pages DueDate : 1/15/2023 5:00:00 PM Progress : 0 Category : Blog #> $item = $TableView.table.rows[$TableView.SelectedRow] if ($item.Overdue) { $lblOverDue.Visible = $True } else { $lblOverDue.Visible = $False } If ($item.Description -match '\w+') { $chkClearDescription.Visible = $True } else { $chkClearDescription.Visible = $False } $txtTaskName.Text = $item.Name $txtDueDate.Text = '{0:g}' -f $item.Due $radioGrp.SelectedItem = 1 $txtDays.Enabled = $False $txtDescription.Text = $item.Description $dropCategory.SelectedItem = $script:CatList.FindIndex({ $args -eq $item.Category }) $dropCategory.EnsureSelectedItemVisible() $txtProgress.Text = $item.Progress Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" } Function AddCategory { [CmdletBinding()] Param() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" $cs = [Terminal.Gui.ColorScheme]::New() $cs.Normal = [Terminal.Gui.Attribute]::New([Terminal.Gui.Color]::Black, [Terminal.Gui.Color]::Gray) $cs.Focus = [Terminal.Gui.Attribute]::New([Terminal.Gui.Color]::White, [Terminal.Gui.Color]::DarkGray) $cs.HotNormal = [Terminal.Gui.Attribute]::New([Terminal.Gui.Color]::BrightBlue, [Terminal.Gui.Color]::Gray) $subWin = [Terminal.Gui.Dialog]@{ Title = 'Add Category' X = [Terminal.Gui.Pos]::Center() Y = [Terminal.Gui.Pos]::Center() Width = 50 Height = 10 ColorScheme = $cs } $lblCategory = [Terminal.Gui.Label]@{ X = 1 Y = 1 Width = 10 Height = 1 Text = 'New Category' TabStop = $False } $txtCategory = [Terminal.Gui.TextField]@{ X = $lblCategory.Frame.Width + 3 Y = 1 Width = 30 Height = 1 } $lblDescription = [Terminal.Gui.Label]@{ X = 1 Y = 3 Width = 10 Height = 1 Text = 'Description' TabStop = $False } $txtDescription = [Terminal.Gui.TextField]@{ X = $txtCategory.X Y = 3 Width = 30 Height = 1 } $chkWhatIf = [Terminal.Gui.CheckBox]@{ X = 1 Y = 5 Width = 10 Height = 1 Text = 'WhatIf' } $chkForce = [Terminal.Gui.CheckBox]@{ X = 1 Y = 6 Width = 10 Height = 1 Text = 'Force' } $btnOk = [Terminal.Gui.Button]@{ X = 13 Y = 6 Width = 10 Height = 1 Text = 'Ok' } $btnOK.Add_Clicked({ if ($txtCategory.Text.ToString() -match '\w+') { if ($chkWhatIf.Checked) { $msg = @" Category = $($txtCategory.Text.ToString()) Description = $($txtDescription.Text.ToString()) Force = $($chkForce.Checked) Path = $($txtPath.Text.ToString()) "@ [Terminal.Gui.MessageBox]::Query('Add-PSWorkitemCategory -WhatIf', $msg, @('Ok')) } else { $splat = @{ Category = $txtCategory.Text.ToString() Path = $txtPath.Text.ToString() ErrorAction = 'Stop' WarningVariable = 'warn' } if ($chkForce.Checked) { $splat['Force'] = $True } if ($txtDescription.Text.ToString() -match '\w+') { $splat['Description'] = $txtDescription.Text.ToString() } Try { Add-PSWorkItemCategory @splat if ($warn) { [Terminal.Gui.MessageBox]::ErrorQuery('Warning', $warn.message) } else { RefreshCategoryList UpdateStatusTime $subWin.RequestStop() } } Catch { [Terminal.Gui.MessageBox]::ErrorQuery('Error', $_.Exception.Message) } } } else { [Terminal.Gui.MessageBox]::ErrorQuery('Add-PSWorkitemCategory', 'A category name is required', @('Ok')) } }) $btnCancel = [Terminal.Gui.Button]@{ X = 23 Y = 6 Width = 10 Height = 1 Text = 'Cancel' } $btnCancel.Add_Clicked({ UpdateStatusTime $subWin.RequestStop() }) $subWin.Add($chkWhatIf) $subWin.Add($chkForce) $subWin.Add($lblDescription) $subWin.Add($txtDescription) $subWin.Add($lblCategory) $subWin.Add($txtCategory) $subWin.Add($btnCancel) $subWin.Add($btnOk) #set tab order $txtCategory.TabIndex = 0 $txtDescription.TabIndex = 1 $chkWhatIf.TabIndex = 2 $chkForce.TabIndex = 3 $btnOk.TabIndex = 4 $btnCancel.TabIndex = 5 $txtCategory.SetFocus() [Terminal.Gui.Application]::Run($subWin) [Terminal.Gui.Application]::Refresh() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" } Function RemoveCategory { [CmdletBinding()] Param() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" $cs = [Terminal.Gui.ColorScheme]::New() $cs.Normal = [Terminal.Gui.Attribute]::New([Terminal.Gui.Color]::Black, [Terminal.Gui.Color]::Gray) $cs.Focus = [Terminal.Gui.Attribute]::New([Terminal.Gui.Color]::White, [Terminal.Gui.Color]::DarkGray) $cs.HotNormal = [Terminal.Gui.Attribute]::New([Terminal.Gui.Color]::BrightBlue, [Terminal.Gui.Color]::Gray) $subWin = [Terminal.Gui.Dialog]@{ Title = 'Remove Category' X = [Terminal.Gui.Pos]::Center() Y = [Terminal.Gui.Pos]::Center() Width = 50 Height = 10 ColorScheme = $cs } $lblCategory = [Terminal.Gui.Label]@{ X = 1 Y = 1 Width = 10 Height = 1 Text = 'Category' TabStop = $False } $subDropCategory = [Terminal.Gui.ListView]@{ Width = 25 Height = 1 X = $lblCategory.Frame.Width + 3 Y = $lblCategory.Y TabIndex = 1 TabStop = $True AllowsMultipleSelection = $False CanFocus = $True } $chkWhatIf = [Terminal.Gui.CheckBox]@{ X = 1 Y = 3 Width = 10 Height = 1 Text = 'WhatIf' } $btnOk = [Terminal.Gui.Button]@{ X = 13 Y = 4 Width = 10 Height = 1 Text = 'Ok' } $btnOK.Add_Clicked({ if ($subDropCategory.Source.ToList()[$subDropCategory.SelectedItem] -match '\w+') { if ($chkWhatIf.Checked) { $msg = @" Category = $($subDropCategory.Source.ToList()[$subDropCategory.SelectedItem]) Path = $($txtPath.Text.ToString()) "@ [Terminal.Gui.MessageBox]::Query('Remove-PSWorkitemCategory -WhatIf', $msg, @('Ok')) } else { $splat = @{ Category = $subDropCategory.Source.ToList()[$subDropCategory.SelectedItem] Path = $txtPath.Text.ToString() ErrorAction = 'Stop' WarningVariable = 'warn' } Try { Remove-PSWorkItemCategory @splat if ($warn) { [Terminal.Gui.MessageBox]::ErrorQuery('Warning', $warn.message) } else { Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Removed category successfully" #refresh the main form list RefreshCategoryList UpdateStatusTime $subWin.RequestStop() } } Catch { [Terminal.Gui.MessageBox]::ErrorQuery('Error', $_.Exception.Message) } } } else { [Terminal.Gui.MessageBox]::ErrorQuery('Remove-PSWorkitemCategory', 'A category name is required', @('Ok')) } }) $btnCancel = [Terminal.Gui.Button]@{ X = 23 Y = 4 Width = 10 Height = 1 Text = 'Cancel' } $btnCancel.Add_Clicked({ UpdateStatusTime $subWin.RequestStop() }) $subWin.Add($chkWhatIf) $subWin.Add($lblCategory) $subWin.Add($subDropCategory) $subWin.Add($btnCancel) $subWin.Add($btnOk) #set tab order $subDropCategory.TabIndex = 0 $chkWhatIf.TabIndex = 1 $btnOk.TabIndex = 2 $btnCancel.TabIndex = 3 $dropCategory.SetFocus() #populate drop down list $src = (Get-PSWorkItemCategory -Path $txtPath.Text.ToString()).Category | Sort-Object $subDropCategory.SetSource($src) $subDropCategory.SetNeedsDisplay() $subDropCategory.SelectedItem = 0 [Terminal.Gui.Application]::Run($subWin) Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" } Function SetCategory { [CmdletBinding()] Param() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" #cache current categories $catHash = Get-PSWorkItemCategory -Path $txtPath.Text.ToString() | Group-Object -Property Category -AsHashTable -AsString $cs = [Terminal.Gui.ColorScheme]::New() $cs.Normal = [Terminal.Gui.Attribute]::New([Terminal.Gui.Color]::Black, [Terminal.Gui.Color]::Gray) $cs.Focus = [Terminal.Gui.Attribute]::New([Terminal.Gui.Color]::White, [Terminal.Gui.Color]::DarkGray) $cs.HotNormal = [Terminal.Gui.Attribute]::New([Terminal.Gui.Color]::BrightBlue, [Terminal.Gui.Color]::Gray) $subWin = [Terminal.Gui.Dialog]@{ Title = 'Set Category' X = [Terminal.Gui.Pos]::Center() Y = [Terminal.Gui.Pos]::Center() Width = 50 Height = 10 ColorScheme = $cs } $lblCategory = [Terminal.Gui.Label]@{ X = 1 Y = 1 Width = 10 Height = 1 Text = 'Category' TabStop = $False } $subDropCategory = [Terminal.Gui.ListView]@{ Width = 25 Height = 1 X = $lblCategory.Frame.Width + 3 Y = $lblCategory.Y TabIndex = 1 TabStop = $True AllowsMultipleSelection = $False CanFocus = $True } $subDropCategory.Add_SelectedItemChanged({ $cat = $subDropCategory.Source.ToList()[$subDropCategory.SelectedItem] $txtDescription.Text = $catHash[$cat].Description }) $lblDescription = [Terminal.Gui.Label]@{ X = 1 Y = 3 Width = 10 Height = 1 Text = 'Description' TabStop = $False } $txtDescription = [Terminal.Gui.TextField]@{ X = $lblDescription.Frame.Width +2 Y = 3 Width = 30 Height = 1 } $lblNewName = [Terminal.Gui.Label]@{ X = 1 Y = 5 Width = 10 Height = 1 Text = 'New name' TabStop = $False } $txtNewName = [Terminal.Gui.TextField]@{ X = $lblNewName.Frame.Width +3 Y = 5 Width = 30 Height = 1 } $chkWhatIf = [Terminal.Gui.CheckBox]@{ X = 1 Y = 7 Width = 10 Height = 1 Text = 'WhatIf' } $btnOk = [Terminal.Gui.Button]@{ X = 13 Y = $chkWhatIf.Y Width = 10 Height = 1 Text = 'Ok' } $btnOK.Add_Clicked({ if ($subDropCategory.Source.ToList()[$subDropCategory.SelectedItem] -match '\w+') { if ($chkWhatIf.Checked) { $msg = @" Category = $($subDropCategory.Source.ToList()[$subDropCategory.SelectedItem]) Description = $($txtDescription.Text.ToString()) New Name = $($txtNewName.Text.ToString()) Path = $($txtPath.Text.ToString()) "@ [Terminal.Gui.MessageBox]::Query('Set-PSWorkItemCategory -WhatIf', $msg, @('Ok')) } else { $splat = @{ Category = $subDropCategory.Source.ToList()[$subDropCategory.SelectedItem] Path = $txtPath.Text.ToString() ErrorAction = 'Stop' WarningVariable = 'warn' } if ($txtNewName.Text.ToString() -match "\w+") { $splat.Add("NewName",$txtNewName.Text.ToString()) } if ($txtDescription.Text.ToString() -match "\w+") { $splat.Add("Description",$txtDescription.Text.ToString()) } Try { $tmpfile = [System.IO.Path]::GetTempFileName() $splat | Out-String | Out-File -FilePath $tmpFile Set-PSWorkItemCategory @splat -verbose 4>>$tmpfile if ($warn) { [Terminal.Gui.MessageBox]::ErrorQuery('Warning', $warn.message) } else { Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Changed category successfully" #refresh the main form list RefreshCategoryList UpdateStatusTime $subWin.RequestStop() } } Catch { [Terminal.Gui.MessageBox]::ErrorQuery('Error', $_.Exception.Message) } } } else { [Terminal.Gui.MessageBox]::ErrorQuery('Remove-PSWorkitemCategory', 'A category name is required', @('Ok')) } }) $btnCancel = [Terminal.Gui.Button]@{ X = 23 Y = $btnOk.Y Width = 10 Height = 1 Text = 'Cancel' } $btnCancel.Add_Clicked({ UpdateStatusTime $subWin.RequestStop() }) $subWin.Add($chkWhatIf) $subWin.Add($lblDescription) $subWin.Add($txtDescription) $subWin.Add($lblCategory) $subWin.Add($subDropCategory) $subWin.Add($lblNewName) $subWin.add($txtNewName) $subWin.Add($btnCancel) $subWin.Add($btnOk) #set tab order $subDropCategory.TabIndex = 0 $txtDescription.TabIndex = 1 $txtNewName.TabIndex = 2 $chkWhatIf.TabIndex = 3 $btnOk.TabIndex = 4 $btnCancel.TabIndex = 5 $dropCategory.SetFocus() #populate drop down list $src = (Get-PSWorkItemCategory -Path $txtPath.Text.ToString()).Category | Sort-Object $subDropCategory.SetSource($src) $subDropCategory.SetNeedsDisplay() $subDropCategory.SelectedItem = 0 [Terminal.Gui.Application]::Run($subWin) Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" } Function ShowDatabaseDetail { [CmdletBinding()] Param() Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Starting $($MyInvocation.MyCommand)" $info = Get-PSWorkItemDatabase -Path $txtPath.Text.ToString() | Format-List | Out-String $dialog = [Terminal.Gui.Dialog]@{ Title = 'PSWorkItem Database Details' TextAlignment = 'Left' Width = 50 Height = 20 Text = $info } $ok = [Terminal.Gui.Button]@{ Text = 'OK' } $ok.Add_Clicked({ $dialog.RequestStop() }) $dialog.AddButton($ok) Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Invoking dialog" [Terminal.Gui.Application]::Run($dialog) Write-Verbose "[$((Get-Date).TimeOfDay) PRIVATE] Ending $($MyInvocation.MyCommand)" } |