Fix legacy json import compatibility, UI sidebar refactor, and improved test coverage (#4911)

* Fix backward compatibility for old-style JSON config imports

* Refactor sidebar UI generation and add tests for Get-WinUtilVariables

* Fix appnavigation config test following UI generation refactor

* Restore global sync state in variables tests

* fix(impex): migrate supported legacy selections

Keep modern imports strict while allowing legacy backups to skip retired entries with clear logging and user feedback. Add fixtures covering partial and all-retired imports.

* test: strengthen UI and global state coverage

Exercise app category rendering through Initialize-WPFUI and restore global sync without leaking test state.

* fix(impex): ignore legacy metadata fields

Limit legacy selection migration to supported WPF key families so unrelated string metadata does not produce false retired-setting warnings.

* docs: clarify legacy config imports

Distinguish strict modern flat imports from partial legacy object migration, including single-setting export shape and historical groups.

---------

Co-authored-by: Chris Titus <contact@christitus.com>
This commit is contained in:
Nikhil
2026-08-19 17:13:14 -05:00
committed by GitHub
co-authored by Chris Titus
parent 4b2fe55a7a
commit 436773df73
10 changed files with 254 additions and 23 deletions
@@ -14,7 +14,6 @@ function Initialize-WinUtilTabContent {
switch ($TabName) {
"Install" {
Invoke-WPFUIElements -configVariable $sync.configs.appnavigation -targetGridName "appscategory" -columncount 1
Initialize-WPFUI -targetGridName "appscategory"
Initialize-WPFUI -targetGridName "appspanel"
+16 -1
View File
@@ -3,7 +3,9 @@ function Update-WinUtilSelections {
[Parameter(Mandatory)]
[string[]]$flatJson,
[switch]$Replace
[switch]$Replace,
[switch]$SkipUnknown
)
$nextSelections = @{
@@ -25,6 +27,10 @@ function Update-WinUtilSelections {
}
if (-not $listName) {
if ($SkipUnknown) {
$cbkey
continue
}
throw "Unsupported selection key '$cbkey'."
}
@@ -47,12 +53,21 @@ function Update-WinUtilSelections {
}
if (-not $isKnownSelection) {
if ($SkipUnknown) {
$cbkey
continue
}
throw "Unknown selection key '$cbkey'."
}
$nextSelections[$listName].Add($cbkey)
}
$validSelectionCount = ($nextSelections.Values | ForEach-Object { $_.Count } | Measure-Object -Sum).Sum
if ($SkipUnknown -and $validSelectionCount -eq 0) {
return
}
if ($Replace) {
foreach ($listName in $nextSelections.Keys) {
$sync[$listName] = $nextSelections[$listName]
+1 -4
View File
@@ -7,10 +7,7 @@ function Initialize-WPFUI {
switch ($TargetGridName) {
"appscategory"{
# TODO
# Switch UI generation of the sidebar to this function
# $sync.ItemsControl = Initialize-InstallAppArea -TargetElement $TargetGridName
# ...
Invoke-WPFUIElements -configVariable $sync.configs.appnavigation -targetGridName "appscategory" -columncount 1
# Create and configure a popup for displaying selected apps
$selectedAppsPopup = New-Object Windows.Controls.Primitives.Popup
+51 -9
View File
@@ -73,15 +73,29 @@ function Invoke-WPFImpex {
Write-Error "Failed to load the JSON file from the specified path or URL: $_"
return
}
if ($null -ne $jsonFile -and $jsonFile.PSObject.Properties['Install']) {
$isLegacyConfig = $jsonFile -is [System.Management.Automation.PSCustomObject] -and
$null -ne $jsonFile.PSObject.Properties["Install"] -and
$null -ne $jsonFile.PSObject.Properties["WPFInstall"]
if ($isLegacyConfig) {
Write-WinUtilLog -Component "Impex" -Message "Detected legacy WinUtil config structure; flattening import object."
$flattenedJson = @()
foreach ($prop in $jsonFile.PSObject.Properties) {
if ($prop.Name -ne "Install" -and $null -ne $prop.Value) {
$flattenedJson += @($prop.Value)
# Legacy exports stored checkbox keys in WPFInstall and duplicated package
# source metadata in Install. Current package IDs come from the app catalog,
# so only the selection-key properties are restored.
$flattenedJson = @(
foreach ($property in $jsonFile.PSObject.Properties) {
if ($property.Name -notmatch '^WPF(?:Install|Tweaks|Toggle|Feature|Appx)') {
continue
}
foreach ($selection in @($property.Value)) {
if ($selection -is [string] -and -not [string]::IsNullOrWhiteSpace($selection)) {
$selection
}
}
}
}
)
} else {
# New style config: flat array of strings
$flattenedJson = $jsonFile
}
@@ -92,9 +106,37 @@ function Invoke-WPFImpex {
return
}
# Build and validate every imported selection before replacing the current
# state. This keeps a malformed config from leaving partial selections behind.
Update-WinUtilSelections -flatJson $flattenedJson -Replace
# Modern configs stay strict. Legacy configs can reference entries that no
# longer exist, so restore supported selections and report the retired keys.
if ($isLegacyConfig) {
$skippedSelections = @(Update-WinUtilSelections -flatJson $flattenedJson -Replace -SkipUnknown)
if ($skippedSelections.Count -gt 0) {
$skippedSummary = $skippedSelections -join ", "
Write-WinUtilLog -Component "Impex" -Level "WARN" -Message "Skipped unsupported legacy selections: $skippedSummary"
}
if ($skippedSelections.Count -eq @($flattenedJson).Count) {
if ($sync.Form) {
Show-WinUtilMessage -Message "This legacy configuration contains no settings supported by this version of WinUtil. No changes have been made." -Title "Unsupported Legacy Configuration" -Icon "Warning" | Out-Null
}
return
}
if ($skippedSelections.Count -gt 0) {
$skippedDisplay = @($skippedSelections | Select-Object -First 10) -join ", "
if ($skippedSelections.Count -gt 10) {
$skippedDisplay += "`n...and $($skippedSelections.Count - 10) more. See the WinUtil log for details."
}
if ($sync.Form) {
Show-WinUtilMessage -Message "Supported settings were imported. The following retired settings were skipped:`n`n$skippedDisplay" -Title "Legacy Configuration Partially Imported" -Icon "Warning" | Out-Null
}
}
} else {
# Build and validate every imported selection before replacing the current
# state. This keeps a malformed config from leaving partial selections behind.
Update-WinUtilSelections -flatJson $flattenedJson -Replace
}
if ($sync.Form) {
Reset-WPFCheckBoxes -doToggles $true