Public/Show-HDTSequenceEditor.ps1

function Show-HDTSequenceEditor {
    <#
        .SYNOPSIS
            Opens the task sequence editor on one task sequence.
 
        .DESCRIPTION
            Deployment Workbench's shape: the browser lists task sequences and
            editing their steps happens in a window opened from one. This toolkit
            asks for a console close enough to it that muscle memory transfers.
 
            THE DECISIONS ARE Get-HDTConsoleSequenceEditor'S; THIS ONE HANDS
            THEM OVER. The rows, the title, the properties and the cmdlet each
            row shows are all built there and asserted in tests. This command
            loads the markup, resolves the palette and calls the injected host,
            which is what leaves the host branch-free and honestly exempt from
            TDD.
 
            THE DOCUMENT PATH GOES TO THE WINDOW SEPARATELY, and the window
            shows it. Both of this lab's shares hold a DEMO-M4, so two editors
            open at once would otherwise be identical windows over different
            files - and the difference would only appear at the moment one of
            them saved.
 
            IT TAKES THE SEQUENCE OBJECT, NEVER AN ID, for the same reason.
 
            IT OPENS AT THE SIZE OF THE WINDOW IT WAS OPENED FROM. An
            administrator who has dragged the browser out to fill a monitor has
            said how big a window on this machine should be, and a second window
            that ignores that reads as a different application. The caller passes
            what the owner MEASURES, not what its markup says, so a maximised
            console opens a maximised-size editor - and
            Resolve-HDTConsoleEditorSize decides what to do with it, including
            when there is no owner at all, because the host that assigns it is
            not unit tested and must decide nothing.
 
        .PARAMETER Sequence
            One task sequence row from Get-HDTConsoleWorkspace's TaskSequence
            collection.
 
        .PARAMETER XamlPath
            The window markup. Defaults to the module's own.
 
        .PARAMETER ConsoleHost
            An IConsoleHost with a ShowEditor method. Defaults to the real
            adapter.
 
        .PARAMETER Theme
            Light or Dark. Light by default, matching the console.
 
        .PARAMETER OwnerWidth
            The current width of the window the editor was opened from - the
            console's ActualWidth. Left at zero when it was run on its own, and
            the editor then opens at its own size.
 
        .PARAMETER OwnerHeight
            The current height of the window the editor was opened from.
 
        .PARAMETER Screen
            An IScreen - the real adapter by default. Injected so a size that
            does not fit a 1280 x 800 laptop can be proven from any desk.
 
        .INPUTS
            None. This command does not accept pipeline input.
 
        .OUTPUTS
            System.Management.Automation.PSCustomObject with Action, Id, Name,
            DocumentPath and NodeCount.
 
        .EXAMPLE
            $share = Get-HDTConsoleWorkspace -Path 'C:\HDTLab\Share'
            Show-HDTSequenceEditor -Sequence @($share.TaskSequence)[0]
    #>

    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '',
        Justification = 'Opens a window. The editing cmdlets it offers carry their own ShouldProcess, and this writes nothing itself.')]
    [CmdletBinding()]
    [OutputType([pscustomobject])]
    param(
        [Parameter(Mandatory = $true, Position = 0)]
        [ValidateNotNull()]
        [object] $Sequence,

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string] $XamlPath = (Join-Path -Path $script:HDTModuleRoot -ChildPath 'UI\Console\HDTSequenceEditor.xaml'),

        [Parameter()]
        [ValidateNotNullOrEmpty()]
        [string] $PartitionXamlPath = (Join-Path -Path $script:HDTModuleRoot -ChildPath 'UI\Console\HDTPartitionProperties.xaml'),

        [Parameter()]
        [AllowNull()]
        [object] $ConsoleHost,

        [Parameter()]
        [AllowNull()]
        [object] $FileSystem,

        [Parameter()]
        [ValidateSet('Light', 'Dark')]
        [string] $Theme = 'Light',

        [Parameter()]
        [ValidateRange(0, 100000)]
        [int] $OwnerWidth = 0,

        [Parameter()]
        [ValidateRange(0, 100000)]
        [int] $OwnerHeight = 0,

        [Parameter()]
        [AllowNull()]
        [object] $Screen
    )

    Set-StrictMode -Version Latest
    $ErrorActionPreference = 'Stop'

    if ($null -eq $ConsoleHost) { $ConsoleHost = New-HDTConsoleHost }
    if ($null -eq $FileSystem) { $FileSystem = New-HDTFileSystem }
    if ($null -eq $Screen) { $Screen = New-HDTConsoleScreen }

    if (-not (Test-Path -LiteralPath $XamlPath)) {
        $PSCmdlet.ThrowTerminatingError((New-HDTErrorRecord -Path $XamlPath `
                    -Category ObjectNotFound `
                    -Message 'the task sequence editor markup is missing, so the editor cannot be shown.'))
    }

    $editor = Get-HDTConsoleSequenceEditor -Sequence $Sequence

    $xaml = [System.IO.File]::ReadAllText($XamlPath)

    # THE VOLUME DIALOG'S MARKUP TRAVELS WITH THE EDITOR'S. It is opened from a
    # button on the Disk tab, so reading it here means the host never touches the
    # file system - the same reason the editor's own markup arrives as a string.
    $partitionXaml = ''
    if (Test-Path -LiteralPath $PartitionXamlPath) {
        $partitionXaml = [System.IO.File]::ReadAllText($PartitionXamlPath)
    }

    # THE DOCUMENT'S OWN LINES, WHICH ARE WHAT THE EDITOR EDITS. Every editing
    # cmdlet splices a string array, and the whole reason for that (see
    # ConsoleStepEdit.Tests.ps1) is that the comments survive - so the text is
    # read once, here, and never round-tripped through the parser.
    #
    # A sequence that would not parse still opens: its rows are empty and the
    # engine's message is already on its row in the browser, but the file's
    # lines are the one thing that might let an administrator fix it.
    $line = [string[]] @()

    if ($FileSystem.TestPath($editor.DocumentPath)) {
        $line = [string[]] @([string] $FileSystem.ReadAllText($editor.DocumentPath) -split "`r?`n")
    }

    # THE SIZE OF THE WINDOW THIS WAS OPENED FROM, FITTED TO THE DESKTOP. The
    # host assigns the two numbers and works out neither of them.
    $size = Resolve-HDTConsoleEditorSize -OwnerWidth $OwnerWidth -OwnerHeight $OwnerHeight -Screen $Screen

    $answer = [string] $ConsoleHost.ShowEditor($xaml, $editor.Title, $editor.DocumentPath,
        [object[]] @($editor.Root), $line,
        [object[]] @(Get-HDTConsoleStepCatalog), (Get-HDTConsoleTheme -Name $Theme), $size,
        $partitionXaml, $editor)

    $action = 'Close'
    if (-not [string]::IsNullOrWhiteSpace($answer)) { $action = $answer }

    return [pscustomobject] @{
        Action       = $action
        Id           = $editor.Id
        Name         = $editor.Name
        DocumentPath = $editor.DocumentPath
        NodeCount    = @($editor.Node).Count
    }
}