From 3fb5c04693f366019c85bb47cef6bf143bf3bfde Mon Sep 17 00:00:00 2001 From: Eren Date: Mon, 2 Mar 2026 22:02:48 +0300 Subject: [PATCH] Fix import/export functionality (#4131) * fix: cast selections to string to prevent PSCustomObject type issues * fix(presets): clear existing selections before importing to replace state instead of merging * refactor(impex): warn user when exporting empty selections or importing empty config --- .../private/Update-WinUtilSelections.ps1 | 6 +++-- functions/public/Invoke-WPFImpex.ps1 | 23 ++++++++++++++++++- functions/public/Invoke-WPFPresets.ps1 | 20 ++++++++-------- .../Invoke-WPFSelectedCheckboxesUpdate.ps1 | 2 +- 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/functions/private/Update-WinUtilSelections.ps1 b/functions/private/Update-WinUtilSelections.ps1 index b97c1b71..a4d65f0e 100644 --- a/functions/private/Update-WinUtilSelections.ps1 +++ b/functions/private/Update-WinUtilSelections.ps1 @@ -14,7 +14,9 @@ function Update-WinUtilSelections { Write-Debug "JSON to import: $($flatJson)" - foreach ($cbkey in $flatJson) { + foreach ($item in $flatJson) { + # Ensure each item is treated as a string to handle PSCustomObject from JSON deserialization + $cbkey = [string]$item $group = if ($cbkey.StartsWith("WPFInstall")) { "Install" } elseif ($cbkey.StartsWith("WPFTweaks")) { "Tweaks" } elseif ($cbkey.StartsWith("WPFToggle")) { "Toggle" } @@ -26,7 +28,7 @@ function Update-WinUtilSelections { if (!$sync.selectedApps.Contains($cbkey)) { $sync.selectedApps.Add($cbkey) # The List type needs to be specified again, because otherwise Sort-Object will convert the list to a string if there is only a single entry - [System.Collections.Generic.List[pscustomobject]]$sync.selectedApps = $sync.SelectedApps | Sort-Object + [System.Collections.Generic.List[string]]$sync.selectedApps = $sync.SelectedApps | Sort-Object } } "Tweaks" { diff --git a/functions/public/Invoke-WPFImpex.ps1 b/functions/public/Invoke-WPFImpex.ps1 index d005c2fc..67e1b129 100644 --- a/functions/public/Invoke-WPFImpex.ps1 +++ b/functions/public/Invoke-WPFImpex.ps1 @@ -44,7 +44,13 @@ function Invoke-WPFImpex { try { $Config = ConfigDialog if ($Config) { - $allConfs = $sync.selectedApps + $sync.selectedTweaks + $sync.selectedToggles + $sync.selectedFeatures + $allConfs = ($sync.selectedApps + $sync.selectedTweaks + $sync.selectedToggles + $sync.selectedFeatures) | ForEach-Object { [string]$_ } + if (-not $allConfs) { + [System.Windows.MessageBox]::Show( + "No settings are selected to export. Please select at least one app, tweak, toggle, or feature before exporting.", + "Nothing to Export", "OK", "Warning") + return + } $jsonFile = $allConfs | ConvertTo-Json $jsonFile | Out-File $Config -Force "iex ""& { `$(irm https://christitus.com/win) } -Config '$Config'""" | Set-Clipboard @@ -70,6 +76,21 @@ function Invoke-WPFImpex { # TODO how to handle old style? detected json type then flatten it in a func? # $flattenedJson = $jsonFile.PSObject.Properties.Where({ $_.Name -ne "Install" }).ForEach({ $_.Value }) $flattenedJson = $jsonFile + + if (-not $flattenedJson) { + [System.Windows.MessageBox]::Show( + "The selected file contains no settings to import. No changes have been made.", + "Empty Configuration", "OK", "Warning") + return + } + + # Clear all existing selections before importing so the import replaces + # the current state rather than merging with it + $sync.selectedApps = [System.Collections.Generic.List[string]]::new() + $sync.selectedTweaks = [System.Collections.Generic.List[string]]::new() + $sync.selectedToggles = [System.Collections.Generic.List[string]]::new() + $sync.selectedFeatures = [System.Collections.Generic.List[string]]::new() + Update-WinUtilSelections -flatJson $flattenedJson if (!$PARAM_NOUI) { diff --git a/functions/public/Invoke-WPFPresets.ps1 b/functions/public/Invoke-WPFPresets.ps1 index d56d48eb..2139c47e 100644 --- a/functions/public/Invoke-WPFPresets.ps1 +++ b/functions/public/Invoke-WPFPresets.ps1 @@ -32,17 +32,17 @@ function Invoke-WPFPresets { $CheckBoxesToCheck = $sync.configs.preset.$preset } - # clear out the filtered pattern - if (!$preset) { - switch ($checkboxfilterpattern) { - "WPFTweak*" { $sync.selectedTweaks = [System.Collections.Generic.List[string]]::new() } - "WPFInstall*" { $sync.selectedApps = [System.Collections.Generic.List[string]]::new() } - "WPFeatures" { $sync.selectedFeatures = [System.Collections.Generic.List[string]]::new() } - "WPFToggle" { $sync.selectedToggles = [System.Collections.Generic.List[string]]::new() } - default {} - } + # clear out the filtered pattern so applying a preset replaces the current + # state rather than merging with it + switch ($checkboxfilterpattern) { + "WPFTweak*" { $sync.selectedTweaks = [System.Collections.Generic.List[string]]::new() } + "WPFInstall*" { $sync.selectedApps = [System.Collections.Generic.List[string]]::new() } + "WPFeatures" { $sync.selectedFeatures = [System.Collections.Generic.List[string]]::new() } + "WPFToggle" { $sync.selectedToggles = [System.Collections.Generic.List[string]]::new() } + default {} } - else { + + if ($preset) { Update-WinUtilSelections -flatJson $CheckBoxesToCheck } diff --git a/functions/public/Invoke-WPFSelectedCheckboxesUpdate.ps1 b/functions/public/Invoke-WPFSelectedCheckboxesUpdate.ps1 index 45bd275d..6bdee481 100644 --- a/functions/public/Invoke-WPFSelectedCheckboxesUpdate.ps1 +++ b/functions/public/Invoke-WPFSelectedCheckboxesUpdate.ps1 @@ -38,7 +38,7 @@ function Invoke-WPFSelectedCheckboxesUpdate{ if (!$sync.selectedApps.Contains($appKey)) { $sync.selectedApps.Add($appKey) # The List type needs to be specified again, because otherwise Sort-Object will convert the list to a string if there is only a single entry - [System.Collections.Generic.List[pscustomobject]]$sync.selectedApps = $sync.SelectedApps | Sort-Object + [System.Collections.Generic.List[string]]$sync.selectedApps = $sync.SelectedApps | Sort-Object } } else{