modules/interactive_components.ps1
|
<#
.SYNOPSIS PSConsoleUI - Interactive Components .DESCRIPTION Interactive UI components including menus, choices, inputs. #> function Show-ConsoleMenu { <# .SYNOPSIS Displays an interactive menu with numbered options. .DESCRIPTION Shows a formatted menu with title, optional header, numbered options, and optional footer. Supports non-selectable headers ([...]) and separators (---). Can return either the count of options or the user's selected index. .PARAMETER Title The title displayed at the top of the menu. .PARAMETER Options Array of menu options. Items starting with '[' or '---' are non-selectable. .PARAMETER Header Optional text displayed before the menu options. .PARAMETER ReturnIndex If present, prompts user for selection and returns the selected index (1-based). If not present, returns the count of selectable options (legacy behavior). .PARAMETER Color Color for borders and numbers (default: Cyan). .PARAMETER OptionColor Color for option text (default: Gray). .PARAMETER Footer Optional text displayed after the menu options. .PARAMETER NoClear If present, does not clear the screen before displaying the menu. .EXAMPLE # Legacy usage (returns count) $count = Show-ConsoleMenu -Title "Main Menu" -Options @("Option 1", "Option 2") .EXAMPLE # Cassiel-compatible usage (returns selected index) $choice = Show-ConsoleMenu -Title "Main Menu" -Options @("Option 1", "Option 2") -Header "Select an option:" -ReturnIndex #> [CmdletBinding()] param( [string]$Title, [array]$Options, [string]$Header = '', [switch]$ReturnIndex, [string]$Color = 'Cyan', [string]$OptionColor = 'Gray', [string]$Footer = '', [switch]$NoClear ) if (-not $Color -or $Color.Trim() -eq '') { $Color = 'Cyan' } if (-not $OptionColor -or $OptionColor.Trim() -eq '') { $OptionColor = 'Gray' } # Respect Global Dev Mode (Infinite Scroll) if (-not $NoClear -and -not $Global:CassielDevMode) { Clear-Host } $width = 60 $border = '=' * $width Write-Host '' Write-Host $border -ForegroundColor $Color $padding = [Math]::Floor(($width - $Title.Length) / 2) Write-Host ((' ' * $padding) + $Title) -ForegroundColor White Write-Host $border -ForegroundColor $Color Write-Host '' # Display Header if provided (Cassiel compatibility) if ($Header) { Write-Host (' ' + $Header) -ForegroundColor Yellow Write-Host '' } $selectableCount = 0 for ($i = 0; $i -lt $Options.Count; $i++) { $opt = $Options[$i] if ($opt -match '^---') { Write-Host (' ' + $opt) -ForegroundColor DarkGray } elseif ($opt -match '^\[') { Write-Host (' ' + $opt) -ForegroundColor $Color } else { $selectableCount++ $text = $opt $itemColor = $OptionColor if ($opt -match '^\\{([a-zA-Z]+)\\}(.*)') { $itemColor = $matches[1] $text = $matches[2] } Write-Host ' [' -NoNewline -ForegroundColor Gray Write-Host ([string]$selectableCount) -NoNewline -ForegroundColor $Color Write-Host '] ' -NoNewline -ForegroundColor Gray Write-Host $text -ForegroundColor $itemColor } } if ($Footer) { Write-Host '' Write-Host (' ' + $Footer) -ForegroundColor Yellow } Write-Host '' # Cassiel compatibility: If -ReturnIndex is present, prompt for selection and return index if ($ReturnIndex) { $choice = Read-ConsoleChoice -MaxChoice $selectableCount -AllowZero $true return $choice } # Legacy behavior: Return count of selectable options return $selectableCount } function Read-ConsoleChoice { <# .SYNOPSIS Reads and validates a numeric menu choice from the user. #> [CmdletBinding()] param( [int]$MaxChoice, [string]$Prompt = 'Selecciona una opcion', [bool]$AllowZero = $true ) if ($AllowZero) { Write-Host '(0 para salir)' -ForegroundColor Gray } Write-Host '' do { Write-Host ($Prompt + ': ') -NoNewline -ForegroundColor Cyan $val = Read-Host if ($val -match '^\d+$') { $choice = [int]$val if ($AllowZero -and $choice -eq 0) { return 0 } if ($choice -ge 1 -and $choice -le $MaxChoice) { return $choice } } Write-Host ' [!] Opcion invalida. Intenta de nuevo.' -ForegroundColor Red Write-Host '' } while ($true) } function Invoke-ConsoleMenu { <# .SYNOPSIS Displays an interactive menu and executes selected actions. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Title, [Parameter(Mandatory = $true)] [array]$MenuItems, [Parameter(Mandatory = $false)] [string]$Footer = '' ) do { $options = $MenuItems | ForEach-Object { $_.Label } $count = Show-ConsoleMenu -Title $Title -Options $options -Footer $Footer $choice = Read-ConsoleChoice -MaxChoice $count -AllowZero $true if ($choice -eq 0) { break } $selectedItem = $MenuItems[$choice - 1] if ($selectedItem.Action) { & $selectedItem.Action } Write-Host '' Write-Host ' Presiona Enter para continuar...' -ForegroundColor Gray Read-Host } while ($true) } function Read-ConsoleMultiChoice { <# .SYNOPSIS Reads multiple selections from a list of options. #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [array]$Options, [Parameter(Mandatory = $false)] [string]$Prompt = 'Seleccione opciones (Separadas por coma)' ) Write-Host (' ' + $Prompt) -ForegroundColor Cyan $i = 1 foreach ($opt in $Options) { Write-Host (' [' + $i + '] ' + $opt) $i++ } $val = Read-Host ' > ' if (-not $val) { return @() } $selectedIndices = $val.Split(',') $results = @() foreach ($idx in $selectedIndices) { if ($idx -match '^\d+$' -and [int]$idx -le $Options.Count) { $results += $Options[[int]$idx - 1] } } return $results } function Write-ConsoleTable { param( [Parameter()] [array]$Data, [Parameter()] [array]$Columns, [string]$Title = '', [string]$ColorMapProperty = '', [hashtable]$ColorMap = @{} ) if ($Data.Count -eq 0) { Write-Host ' (No data to display)' -ForegroundColor Gray return } # Helper: Wrap Text function Get-WrappedLines { param([string]$Text, [int]$Width) if ([string]::IsNullOrEmpty($Text)) { return @('') } $rawLines = $Text -split "`n" $finalLines = @() foreach ($line in $rawLines) { if ($line.Length -le $Width) { $finalLines += $line } else { $currentLine = '' $words = $line -split ' ' foreach ($word in $words) { if (($currentLine.Length + $word.Length + 1) -le $Width) { $currentLine += ($word + ' ') } else { $finalLines += $currentLine.Trim() $currentLine = ($word + ' ') } } if ($currentLine) { $finalLines += $currentLine.Trim() } } } return $finalLines } # Simple table rendering Write-Host '' if ($Title) { Write-Host (' ' + $Title) -ForegroundColor Cyan } # Headers Write-Host ' ' -NoNewline foreach ($col in $Columns) { Write-Host ($col.Header.PadRight($col.Width)) -NoNewline -ForegroundColor Yellow } Write-Host '' # Rows foreach ($row in $Data) { Write-Host ' ' -NoNewline foreach ($col in $Columns) { $val = $row.($col.Property) Write-Host ([string]$val).PadRight($col.Width) -NoNewline -ForegroundColor White } Write-Host '' } Write-Host '' } function Invoke-ConsoleSpinner { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Message, [Parameter(Mandatory = $true)] [Alias('ScriptBlock')] [scriptblock]$Action ) Write-Host $Message -NoNewline $spinner = @('|', '/', '-', '\') $job = Start-Job -ScriptBlock $Action while ($job.State -eq 'Running') { foreach ($s in $spinner) { Write-Host "`b$s" -NoNewline Start-Sleep -Milliseconds 100 } } Receive-Job $job Write-Host "`bDone" -ForegroundColor Green } function Write-ConsoleProgress { param([string]$Activity, [int]$Percent) Write-Progress -Activity $Activity -PercentComplete $Percent } function Show-ConsoleProgress { <# .SYNOPSIS Displays a visual progress bar in the console. .DESCRIPTION Shows a progress bar with percentage using safe ASCII characters. .PARAMETER Activity Description of the activity being performed. .PARAMETER PercentComplete Percentage complete (0-100). .PARAMETER BarLength Length of the progress bar (default: 20). .PARAMETER Color Color of the filled portion (default: Cyan). #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Activity, [Parameter(Mandatory = $true)] [ValidateRange(0, 100)] [int]$PercentComplete, [int]$BarLength = 20, [string]$Color = 'Cyan' ) # Calculate filled and empty portions $filled = [Math]::Floor(($PercentComplete / 100) * $BarLength) $empty = $BarLength - $filled # Build progress bar using safe ASCII characters $filledBar = '#' * $filled $emptyBar = '.' * $empty # Display progress bar Write-Host " $Activity " -NoNewline Write-Host '[' -NoNewline -ForegroundColor Gray Write-Host $filledBar -NoNewline -ForegroundColor $Color Write-Host $emptyBar -NoNewline -ForegroundColor DarkGray Write-Host '] ' -NoNewline -ForegroundColor Gray Write-Host "$PercentComplete%" -ForegroundColor $Color } function Read-ConsoleInput { param([string]$Prompt) return Read-Host -Prompt $Prompt } function Read-ConsoleConfirmation { param([string]$Message) $response = Read-Host "$Message (y/n)" return $response -eq 'y' } function Read-ConsolePassword { param([string]$Prompt) return Read-Host -Prompt $Prompt -AsSecureString } function Show-ConsoleNotification { param([string]$Message, [string]$Type = 'Info') Write-Host "[$Type] $Message" -ForegroundColor Yellow } # No local Export-ModuleMember here - handled by main module |