modules/HomeLab.UI/Public/Handlers/6-DocumentationHandler.ps1
<#
.SYNOPSIS Documentation Menu Handler for HomeLab Setup .DESCRIPTION Processes user selections in the documentation menu using the new modular structure. Options include: 1. Viewing the Main README. 2. Viewing VPN Gateway Documentation. 3. Viewing the Client Certificate Management Guide. 0. Return to the Main Menu. .PARAMETER ShowProgress If specified, shows a progress bar while loading the menu and rendering documentation. .PARAMETER UseMarkdownRendering If specified, attempts to render markdown with basic formatting (headers, lists, code blocks). .EXAMPLE Invoke-DocumentationMenu .EXAMPLE Invoke-DocumentationMenu -ShowProgress .EXAMPLE Invoke-DocumentationMenu -UseMarkdownRendering .EXAMPLE Invoke-DocumentationMenu -ShowProgress -UseMarkdownRendering .NOTES Author: Jurie Smit Date: March 8, 2025 #> function Invoke-DocumentationMenu { [CmdletBinding()] param( [Parameter(Mandatory = $false)] [switch]$ShowProgress, [Parameter(Mandatory = $false)] [switch]$UseMarkdownRendering ) # Check if required functions exist $requiredFunctions = @( "Show-DocumentationMenu", "Pause" ) foreach ($function in $requiredFunctions) { if (-not (Get-Command -Name $function -ErrorAction SilentlyContinue)) { Write-Error "Required function '$function' not found. Make sure all required modules are imported." return } } # Check if logging is available $canLog = Get-Command -Name "Write-Log" -ErrorAction SilentlyContinue if ($canLog) { Write-Log -Message "Entering Documentation Menu" -Level INFO } # Determine the module root and docs path $moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) $docsPath = Join-Path -Path $moduleRoot -ChildPath "docs" if ($canLog) { Write-Log -Message "Module root path: $moduleRoot" -Level DEBUG Write-Log -Message "Documentation path: $docsPath" -Level DEBUG } # Function to render markdown with basic formatting function Format-Markdown { param ( [Parameter(Mandatory = $true)] [string[]]$Content ) $inCodeBlock = $false $codeBlockIndent = 0 foreach ($line in $Content) { # Handle code blocks if ($line -match '^\s*```') { $inCodeBlock = -not $inCodeBlock if ($inCodeBlock) { # Extract language if specified $lang = $line -replace '^\s*```\s*', '' if ($lang) { Write-Host "[$lang]" -ForegroundColor DarkGray } $codeBlockIndent = ($line -match '^\s+') ? ($line.Length - $line.TrimStart().Length) : 0 } continue } if ($inCodeBlock) { # In code block - show with different background Write-Host $line -ForegroundColor DarkYellow continue } # Handle headers if ($line -match '^#{1,6}\s+') { $level = $line.IndexOf(' ') $text = $line.Substring($level + 1) switch ($level) { 1 { Write-Host $text -ForegroundColor Cyan -BackgroundColor DarkBlue } 2 { Write-Host $text -ForegroundColor Cyan } 3 { Write-Host $text -ForegroundColor White -BackgroundColor DarkCyan } 4 { Write-Host $text -ForegroundColor White } 5 { Write-Host $text -ForegroundColor Gray } 6 { Write-Host $text -ForegroundColor DarkGray } } continue } # Handle lists if ($line -match '^\s*[\*\-\+]\s+') { $indent = $line.IndexOf($line -replace '^\s*', '') $text = $line -replace '^\s*[\*\-\+]\s+', '' $prefix = " " * ($indent / 2) + "• " Write-Host "$prefix$text" -ForegroundColor Yellow continue } # Handle numbered lists if ($line -match '^\s*\d+\.\s+') { $indent = $line.IndexOf($line -replace '^\s*', '') $num = $line -replace '^\s*(\d+)\.\s+.*$', '$1' $text = $line -replace '^\s*\d+\.\s+', '' $prefix = " " * ($indent / 2) + "$num. " Write-Host "$prefix$text" -ForegroundColor Yellow continue } # Handle emphasis and bold (basic) $line = $line -replace '\*\*([^\*]+)\*\*', ("`e[1m`$1`e[0m") # Bold $line = $line -replace '\*([^\*]+)\*', ("`e[3m`$1`e[0m") # Italic # Regular text Write-Host $line } } # Function to display a document with progress function Show-Document { param ( [string]$Title, [string[]]$FilePaths, [switch]$UseMarkdownRendering, [switch]$ShowProgress ) Clear-Host Write-Host "╔══════════════════════════════════════════╗" -ForegroundColor Cyan Write-Host "║ $($Title.PadRight(28))║" -ForegroundColor Cyan Write-Host "╚══════════════════════════════════════════╝" -ForegroundColor Cyan Write-Host "" $content = $null $foundFile = $false $foundPath = "" if ($ShowProgress) { # Create a progress task for loading documentation $task = Start-ProgressTask -Activity "Loading Documentation" -TotalSteps 3 -ScriptBlock { # Step 1: Searching for documentation files $syncHash.Status = "Searching for documentation files..." $syncHash.CurrentStep = 1 foreach ($path in $FilePaths) { if (Test-Path $path) { $foundFile = $true $foundPath = $path break } } if (-not $foundFile) { return @{ Success = $false ErrorMessage = "Documentation not found." SearchedPaths = $FilePaths } } # Step 2: Reading documentation content $syncHash.Status = "Reading documentation content..." $syncHash.CurrentStep = 2 try { $content = Get-Content -Path $foundPath -Raw # Step 3: Processing content $syncHash.Status = "Processing content..." $syncHash.CurrentStep = 3 return @{ Success = $true Content = $content -split "`n" Path = $foundPath } } catch { return @{ Success = $false ErrorMessage = "Error reading documentation: $_" Path = $foundPath } } } $result = $task.Complete() if ($result.Success) { if ($UseMarkdownRendering) { Format-Markdown -Content $result.Content } else { $result.Content | ForEach-Object { Write-Host $_ } } Write-Host "" Write-Host "Documentation loaded from: $($result.Path)" -ForegroundColor DarkGray if ($canLog) { Write-Log -Message "Successfully displayed documentation from $($result.Path)" -Level INFO } } else { Write-Host $result.ErrorMessage -ForegroundColor Red if ($result.SearchedPaths) { Write-Host "Searched locations:" -ForegroundColor Yellow foreach ($path in $result.SearchedPaths) { Write-Host "- $path" -ForegroundColor Yellow } } if ($canLog) { Write-Log -Message $result.ErrorMessage -Level ERROR if ($result.SearchedPaths) { Write-Log -Message "Searched paths: $($result.SearchedPaths -join ', ')" -Level DEBUG } } } } else { # Original implementation without progress bar $foundFile = $false foreach ($path in $FilePaths) { if (Test-Path $path) { $foundFile = $true $foundPath = $path try { $content = Get-Content -Path $path if ($UseMarkdownRendering) { Format-Markdown -Content $content } else { $content | ForEach-Object { Write-Host $_ } } Write-Host "" Write-Host "Documentation loaded from: $path" -ForegroundColor DarkGray if ($canLog) { Write-Log -Message "Successfully displayed documentation from $path" -Level INFO } } catch { Write-Host "Error reading documentation: $_" -ForegroundColor Red if ($canLog) { Write-Log -Message ("Error reading documentation from $path" + ": $_") -Level ERROR } } break } } if (-not $foundFile) { Write-Host "Documentation not found." -ForegroundColor Red Write-Host "Searched locations:" -ForegroundColor Yellow foreach ($path in $FilePaths) { Write-Host "- $path" -ForegroundColor Yellow } if ($canLog) { Write-Log -Message "Documentation not found. Searched paths: $($FilePaths -join ', ')" -Level ERROR } } } } $selection = 0 do { try { Show-DocumentationMenu -ShowProgress:$ShowProgress } catch { Write-Host "Error displaying Documentation Menu: $_" -ForegroundColor Red if ($canLog) { Write-Log -Message "Error displaying Documentation Menu: $_" -Level ERROR } break } $selection = Read-Host "Select an option" switch ($selection) { "1" { if ($canLog) { Write-Log -Message "User selected: View Main README" -Level INFO } $readmePaths = @( (Join-Path -Path $moduleRoot -ChildPath "..\README.md"), (Join-Path -Path $moduleRoot -ChildPath "README.md") ) Show-Document -Title "MAIN README" -FilePaths $readmePaths -UseMarkdownRendering:$UseMarkdownRendering -ShowProgress:$ShowProgress Pause } "2" { if ($canLog) { Write-Log -Message "User selected: View VPN Gateway Documentation" -Level INFO } $vpnReadmePaths = @( (Join-Path -Path $docsPath -ChildPath "VPN-GATEWAY.README.md"), (Join-Path -Path $docsPath -ChildPath "vpn-gateway.md"), (Join-Path -Path $docsPath -ChildPath "vpn-gateway-guide.md"), (Join-Path -Path $docsPath -ChildPath "vpn-documentation.md") ) Show-Document -Title "VPN GATEWAY DOCUMENTATION" -FilePaths $vpnReadmePaths -UseMarkdownRendering:$UseMarkdownRendering -ShowProgress:$ShowProgress Pause } "3" { if ($canLog) { Write-Log -Message "User selected: View Client Certificate Management Guide" -Level INFO } $certGuidePaths = @( (Join-Path -Path $docsPath -ChildPath "client-certificate-management.md"), (Join-Path -Path $docsPath -ChildPath "vpn-certificates.md"), (Join-Path -Path $docsPath -ChildPath "certificate-guide.md"), (Join-Path -Path $docsPath -ChildPath "cert-management.md") ) Show-Document -Title "CLIENT CERTIFICATE MANAGEMENT GUIDE" -FilePaths $certGuidePaths -UseMarkdownRendering:$UseMarkdownRendering -ShowProgress:$ShowProgress Pause } "0" { # Return to main menu if ($canLog) { Write-Log -Message "User exited Documentation Menu" -Level INFO } } default { Write-Host "Invalid option. Please try again." -ForegroundColor Red if ($canLog) { Write-Log -Message "User selected invalid option: $selection" -Level Warning } Start-Sleep -Seconds 2 } } } while ($selection -ne "0") } |