From 6ca2cd667bdf269a42fd8de13f97865821ad9291 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 23:48:22 +0000 Subject: [PATCH 1/8] Initial plan From 25d20737190ffc3901c378d1890c2e79a83f24fc Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 23:52:38 +0000 Subject: [PATCH 2/8] Migrate SettingsManager to use JSON format with automatic XML migration Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- .../NETworkManager.Settings/SettingsInfo.cs | 4 +- .../SettingsManager.cs | 83 +++++++++++++++++-- 2 files changed, 79 insertions(+), 8 deletions(-) diff --git a/Source/NETworkManager.Settings/SettingsInfo.cs b/Source/NETworkManager.Settings/SettingsInfo.cs index 7f195085d2..d3d5d4c83f 100644 --- a/Source/NETworkManager.Settings/SettingsInfo.cs +++ b/Source/NETworkManager.Settings/SettingsInfo.cs @@ -13,7 +13,7 @@ using System.Collections.Specialized; using System.ComponentModel; using System.Runtime.CompilerServices; -using System.Xml.Serialization; +using System.Text.Json.Serialization; // ReSharper disable InconsistentNaming @@ -42,7 +42,7 @@ private void OnPropertyChanged([CallerMemberName] string propertyName = null) #region Variables - [XmlIgnore] public bool SettingsChanged { get; set; } + [JsonIgnore] public bool SettingsChanged { get; set; } /// /// Private field for the property. diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs index cbd20d5ff4..678e9ac7a4 100644 --- a/Source/NETworkManager.Settings/SettingsManager.cs +++ b/Source/NETworkManager.Settings/SettingsManager.cs @@ -4,6 +4,8 @@ using System; using System.IO; using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; using System.Xml.Serialization; namespace NETworkManager.Settings; @@ -30,7 +32,12 @@ public static class SettingsManager /// /// Settings file extension. /// - private static string SettingsFileExtension => ".xml"; + private static string SettingsFileExtension => ".json"; + + /// + /// Legacy XML settings file extension. + /// + private static string LegacySettingsFileExtension => ".xml"; /// /// Settings that are currently loaded. @@ -76,6 +83,15 @@ public static string GetSettingsFilePath() return Path.Combine(GetSettingsFolderLocation(), GetSettingsFileName()); } + /// + /// Method to get the legacy XML settings file path. + /// + /// Legacy XML settings file path. + private static string GetLegacySettingsFilePath() + { + return Path.Combine(GetSettingsFolderLocation(), $"{SettingsFileName}{LegacySettingsFileExtension}"); + } + #endregion #region Initialize, load and save @@ -99,7 +115,9 @@ public static void Initialize() public static void Load() { var filePath = GetSettingsFilePath(); + var legacyFilePath = GetLegacySettingsFilePath(); + // Check if JSON file exists if (File.Exists(filePath)) { Current = DeserializeFromFile(filePath); @@ -109,16 +127,64 @@ public static void Load() return; } + // Check if legacy XML file exists and migrate it + if (File.Exists(legacyFilePath)) + { + Log.Info("Legacy XML settings file found. Migrating to JSON format..."); + + Current = DeserializeFromXmlFile(legacyFilePath); + + Current.SettingsChanged = false; + + // Save in new JSON format + Save(); + + // Backup the old XML file + var backupFilePath = Path.Combine(GetSettingsFolderLocation(), + $"{SettingsFileName}{LegacySettingsFileExtension}.backup"); + File.Copy(legacyFilePath, backupFilePath, true); + Log.Info($"Legacy XML settings file backed up to: {backupFilePath}"); + + // Optionally, delete the original XML file after successful migration + // File.Delete(legacyFilePath); + + Log.Info("Settings migration from XML to JSON completed successfully."); + + return; + } + // Initialize the default settings if there is no settings file. Initialize(); } /// - /// Method to deserialize the settings from a file. + /// Method to deserialize the settings from a JSON file. /// /// Path to the settings file. /// Settings as . private static SettingsInfo DeserializeFromFile(string filePath) + { + var jsonString = File.ReadAllText(filePath); + + var options = new JsonSerializerOptions + { + WriteIndented = true, + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.Never, + Converters = { new JsonStringEnumConverter() } + }; + + var settingsInfo = JsonSerializer.Deserialize(jsonString, options); + + return settingsInfo; + } + + /// + /// Method to deserialize the settings from a legacy XML file. + /// + /// Path to the XML settings file. + /// Settings as . + private static SettingsInfo DeserializeFromXmlFile(string filePath) { var xmlSerializer = new XmlSerializer(typeof(SettingsInfo)); @@ -145,16 +211,21 @@ public static void Save() } /// - /// Method to serialize the settings to a file. + /// Method to serialize the settings to a JSON file. /// /// Path to the settings file. private static void SerializeToFile(string filePath) { - var xmlSerializer = new XmlSerializer(typeof(SettingsInfo)); + var options = new JsonSerializerOptions + { + WriteIndented = true, + DefaultIgnoreCondition = JsonIgnoreCondition.Never, + Converters = { new JsonStringEnumConverter() } + }; - using var fileStream = new FileStream(filePath, FileMode.Create); + var jsonString = JsonSerializer.Serialize(Current, options); - xmlSerializer.Serialize(fileStream, Current); + File.WriteAllText(filePath, jsonString); } #endregion From 68874f22a81f7efa289c858a44a6c119c1d7d3e1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 23:55:27 +0000 Subject: [PATCH 3/8] Add JSON exception handling in App.xaml.cs Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- Source/NETworkManager/App.xaml.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Source/NETworkManager/App.xaml.cs b/Source/NETworkManager/App.xaml.cs index 249efe1a39..611d0a3f19 100644 --- a/Source/NETworkManager/App.xaml.cs +++ b/Source/NETworkManager/App.xaml.cs @@ -2,6 +2,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Text.Json; using System.Threading; using System.Windows; using System.Windows.Threading; @@ -108,6 +109,24 @@ by BornToBeRoot SettingsManager.Initialize(); ConfigurationManager.Current.ShowSettingsResetNoteOnStartup = true; } + catch (JsonException ex) + { + Log.Error("Could not load application settings! JSON file is corrupted or invalid."); + Log.Error(ex.Message + "-" + ex.StackTrace); + + // Create backup of corrupted file + var destinationFile = + $"{TimestampHelper.GetTimestamp()}_corrupted_" + SettingsManager.GetSettingsFileName(); + File.Copy(SettingsManager.GetSettingsFilePath(), + Path.Combine(SettingsManager.GetSettingsFolderLocation(), destinationFile)); + Log.Info($"A backup of the corrupted settings file has been saved under {destinationFile}"); + + // Initialize default application settings + Log.Info("Initialize default application settings..."); + + SettingsManager.Initialize(); + ConfigurationManager.Current.ShowSettingsResetNoteOnStartup = true; + } // Upgrade settings if necessary var settingsVersion = Version.Parse(SettingsManager.Current.Version); From 47faca2d42d54d7e70a2293fd24c4bf1c072ca72 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 23 Dec 2025 23:57:19 +0000 Subject: [PATCH 4/8] Address code review comments: refactor JSON options and add null check Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- .../SettingsManager.cs | 37 ++++++++++--------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs index 678e9ac7a4..c6634abf14 100644 --- a/Source/NETworkManager.Settings/SettingsManager.cs +++ b/Source/NETworkManager.Settings/SettingsManager.cs @@ -49,6 +49,17 @@ public static class SettingsManager /// public static bool HotKeysChanged { get; set; } + /// + /// JSON serializer options for consistent serialization/deserialization. + /// + private static readonly JsonSerializerOptions JsonOptions = new() + { + WriteIndented = true, + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.Never, + Converters = { new JsonStringEnumConverter() } + }; + #endregion #region Settings location, default paths and file names @@ -145,8 +156,8 @@ public static void Load() File.Copy(legacyFilePath, backupFilePath, true); Log.Info($"Legacy XML settings file backed up to: {backupFilePath}"); - // Optionally, delete the original XML file after successful migration - // File.Delete(legacyFilePath); + // Note: The original XML file is intentionally not deleted to allow users to revert if needed. + // Users can manually delete Settings.xml after verifying the migration was successful. Log.Info("Settings migration from XML to JSON completed successfully."); @@ -166,15 +177,12 @@ private static SettingsInfo DeserializeFromFile(string filePath) { var jsonString = File.ReadAllText(filePath); - var options = new JsonSerializerOptions - { - WriteIndented = true, - PropertyNameCaseInsensitive = true, - DefaultIgnoreCondition = JsonIgnoreCondition.Never, - Converters = { new JsonStringEnumConverter() } - }; + var settingsInfo = JsonSerializer.Deserialize(jsonString, JsonOptions); - var settingsInfo = JsonSerializer.Deserialize(jsonString, options); + if (settingsInfo == null) + { + throw new InvalidOperationException("Failed to deserialize settings from JSON file. The result was null."); + } return settingsInfo; } @@ -216,14 +224,7 @@ public static void Save() /// Path to the settings file. private static void SerializeToFile(string filePath) { - var options = new JsonSerializerOptions - { - WriteIndented = true, - DefaultIgnoreCondition = JsonIgnoreCondition.Never, - Converters = { new JsonStringEnumConverter() } - }; - - var jsonString = JsonSerializer.Serialize(Current, options); + var jsonString = JsonSerializer.Serialize(Current, JsonOptions); File.WriteAllText(filePath, jsonString); } From a1037c361ae50254de37273d1c500aff2016e21d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 00:00:14 +0000 Subject: [PATCH 5/8] Fix remaining code review issues: extract common error handling, add null checks, use timestamped backups Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- .../SettingsManager.cs | 14 ++++-- Source/NETworkManager/App.xaml.cs | 45 +++++++++---------- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs index c6634abf14..6e3cd571f7 100644 --- a/Source/NETworkManager.Settings/SettingsManager.cs +++ b/Source/NETworkManager.Settings/SettingsManager.cs @@ -1,6 +1,7 @@ using log4net; using NETworkManager.Models; using NETworkManager.Models.Network; +using NETworkManager.Utilities; using System; using System.IO; using System.Linq; @@ -150,10 +151,10 @@ public static void Load() // Save in new JSON format Save(); - // Backup the old XML file + // Backup the old XML file with timestamp to avoid overwriting existing backups var backupFilePath = Path.Combine(GetSettingsFolderLocation(), - $"{SettingsFileName}{LegacySettingsFileExtension}.backup"); - File.Copy(legacyFilePath, backupFilePath, true); + $"{SettingsFileName}_{TimestampHelper.GetTimestamp()}{LegacySettingsFileExtension}.backup"); + File.Copy(legacyFilePath, backupFilePath, false); Log.Info($"Legacy XML settings file backed up to: {backupFilePath}"); // Note: The original XML file is intentionally not deleted to allow users to revert if needed. @@ -198,7 +199,12 @@ private static SettingsInfo DeserializeFromXmlFile(string filePath) using var fileStream = new FileStream(filePath, FileMode.Open); - var settingsInfo = (SettingsInfo)xmlSerializer.Deserialize(fileStream); + var settingsInfo = xmlSerializer.Deserialize(fileStream) as SettingsInfo; + + if (settingsInfo == null) + { + throw new InvalidOperationException("Failed to deserialize settings from XML file. The result was null."); + } return settingsInfo; } diff --git a/Source/NETworkManager/App.xaml.cs b/Source/NETworkManager/App.xaml.cs index 611d0a3f19..b1d067e00e 100644 --- a/Source/NETworkManager/App.xaml.cs +++ b/Source/NETworkManager/App.xaml.cs @@ -96,36 +96,14 @@ by BornToBeRoot Log.Error("Could not load application settings!"); Log.Error(ex.Message + "-" + ex.StackTrace); - // Create backup of corrupted file - var destinationFile = - $"{TimestampHelper.GetTimestamp()}_corrupted_" + SettingsManager.GetSettingsFileName(); - File.Copy(SettingsManager.GetSettingsFilePath(), - Path.Combine(SettingsManager.GetSettingsFolderLocation(), destinationFile)); - Log.Info($"A backup of the corrupted settings file has been saved under {destinationFile}"); - - // Initialize default application settings - Log.Info("Initialize default application settings..."); - - SettingsManager.Initialize(); - ConfigurationManager.Current.ShowSettingsResetNoteOnStartup = true; + HandleCorruptedSettingsFile(); } catch (JsonException ex) { Log.Error("Could not load application settings! JSON file is corrupted or invalid."); Log.Error(ex.Message + "-" + ex.StackTrace); - // Create backup of corrupted file - var destinationFile = - $"{TimestampHelper.GetTimestamp()}_corrupted_" + SettingsManager.GetSettingsFileName(); - File.Copy(SettingsManager.GetSettingsFilePath(), - Path.Combine(SettingsManager.GetSettingsFolderLocation(), destinationFile)); - Log.Info($"A backup of the corrupted settings file has been saved under {destinationFile}"); - - // Initialize default application settings - Log.Info("Initialize default application settings..."); - - SettingsManager.Initialize(); - ConfigurationManager.Current.ShowSettingsResetNoteOnStartup = true; + HandleCorruptedSettingsFile(); } // Upgrade settings if necessary @@ -239,6 +217,25 @@ by BornToBeRoot } } + /// + /// Handles a corrupted settings file by creating a backup and initializing default settings. + /// + private void HandleCorruptedSettingsFile() + { + // Create backup of corrupted file + var destinationFile = + $"{TimestampHelper.GetTimestamp()}_corrupted_" + SettingsManager.GetSettingsFileName(); + File.Copy(SettingsManager.GetSettingsFilePath(), + Path.Combine(SettingsManager.GetSettingsFolderLocation(), destinationFile)); + Log.Info($"A backup of the corrupted settings file has been saved under {destinationFile}"); + + // Initialize default application settings + Log.Info("Initialize default application settings..."); + + SettingsManager.Initialize(); + ConfigurationManager.Current.ShowSettingsResetNoteOnStartup = true; + } + private void DispatcherTimer_Tick(object sender, EventArgs e) { Log.Info("Run background job..."); From 03be70beea8f8ea9b983731b379fe14bac9b8fb5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 24 Dec 2025 00:01:53 +0000 Subject: [PATCH 6/8] Fix backup file copy to allow overwrite for same-timestamp scenarios Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- Source/NETworkManager.Settings/SettingsManager.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs index 6e3cd571f7..12fb6703b5 100644 --- a/Source/NETworkManager.Settings/SettingsManager.cs +++ b/Source/NETworkManager.Settings/SettingsManager.cs @@ -152,9 +152,11 @@ public static void Load() Save(); // Backup the old XML file with timestamp to avoid overwriting existing backups + // If a backup with the same timestamp exists (unlikely), it will be overwritten + // since it represents the same migration attempt var backupFilePath = Path.Combine(GetSettingsFolderLocation(), $"{SettingsFileName}_{TimestampHelper.GetTimestamp()}{LegacySettingsFileExtension}.backup"); - File.Copy(legacyFilePath, backupFilePath, false); + File.Copy(legacyFilePath, backupFilePath, true); Log.Info($"Legacy XML settings file backed up to: {backupFilePath}"); // Note: The original XML file is intentionally not deleted to allow users to revert if needed. From 68522663efa77d62fd4eecf9ef5b537119db9dd8 Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Wed, 24 Dec 2025 17:06:58 +0100 Subject: [PATCH 7/8] Feature: Migrate settings to json --- .../SettingsManager.cs | 69 ++++++++++++++----- Source/NETworkManager/App.xaml.cs | 12 ++-- 2 files changed, 56 insertions(+), 25 deletions(-) diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs index 12fb6703b5..1ce2e093d4 100644 --- a/Source/NETworkManager.Settings/SettingsManager.cs +++ b/Source/NETworkManager.Settings/SettingsManager.cs @@ -25,6 +25,11 @@ public static class SettingsManager /// private static string SettingsFolderName => "Settings"; + /// + /// Settings backups directory name. + /// + private static string BackupFolderName => "Backups"; + /// /// Settings file name. /// @@ -38,6 +43,7 @@ public static class SettingsManager /// /// Legacy XML settings file extension. /// + [Obsolete("Legacy XML settings are no longer used, but the extension is kept for migration purposes.")] private static string LegacySettingsFileExtension => ".xml"; /// @@ -77,6 +83,15 @@ public static string GetSettingsFolderLocation() AssemblyManager.Current.Name, SettingsFolderName); } + /// + /// Method to get the path of the settings backup folder. + /// + /// Path to the settings backup folder. + public static string GetSettingsBackupFolderLocation() + { + return Path.Combine(GetSettingsFolderLocation(), BackupFolderName); + } + /// /// Method to get the settings file name. /// @@ -86,6 +101,16 @@ public static string GetSettingsFileName() return $"{SettingsFileName}{SettingsFileExtension}"; } + /// + /// Method to get the legacy settings file name. + /// + /// Legacy settings file name. + [Obsolete("Legacy XML settings are no longer used, but the method is kept for migration purposes.")] + public static string GetLegacySettingsFileName() + { + return $"{SettingsFileName}{LegacySettingsFileExtension}"; + } + /// /// Method to get the settings file path. /// @@ -99,9 +124,10 @@ public static string GetSettingsFilePath() /// Method to get the legacy XML settings file path. /// /// Legacy XML settings file path. + [Obsolete("Legacy XML settings are no longer used, but the method is kept for migration purposes.")] private static string GetLegacySettingsFilePath() { - return Path.Combine(GetSettingsFolderLocation(), $"{SettingsFileName}{LegacySettingsFileExtension}"); + return Path.Combine(GetSettingsFolderLocation(), GetLegacySettingsFileName()); } #endregion @@ -151,16 +177,17 @@ public static void Load() // Save in new JSON format Save(); - // Backup the old XML file with timestamp to avoid overwriting existing backups - // If a backup with the same timestamp exists (unlikely), it will be overwritten - // since it represents the same migration attempt - var backupFilePath = Path.Combine(GetSettingsFolderLocation(), - $"{SettingsFileName}_{TimestampHelper.GetTimestamp()}{LegacySettingsFileExtension}.backup"); + // Create a backup of the legacy XML file and delete the original + Directory.CreateDirectory(GetSettingsBackupFolderLocation()); + + var backupFilePath = Path.Combine(GetSettingsBackupFolderLocation(), + $"{TimestampHelper.GetTimestamp()}_{GetLegacySettingsFileName()}"); + File.Copy(legacyFilePath, backupFilePath, true); - Log.Info($"Legacy XML settings file backed up to: {backupFilePath}"); - // Note: The original XML file is intentionally not deleted to allow users to revert if needed. - // Users can manually delete Settings.xml after verifying the migration was successful. + File.Delete(legacyFilePath); + + Log.Info($"Legacy XML settings file backed up to: {backupFilePath}"); Log.Info("Settings migration from XML to JSON completed successfully."); @@ -182,11 +209,6 @@ private static SettingsInfo DeserializeFromFile(string filePath) var settingsInfo = JsonSerializer.Deserialize(jsonString, JsonOptions); - if (settingsInfo == null) - { - throw new InvalidOperationException("Failed to deserialize settings from JSON file. The result was null."); - } - return settingsInfo; } @@ -195,6 +217,7 @@ private static SettingsInfo DeserializeFromFile(string filePath) /// /// Path to the XML settings file. /// Settings as . + [Obsolete("Legacy XML settings are no longer used, but the method is kept for migration purposes.")] private static SettingsInfo DeserializeFromXmlFile(string filePath) { var xmlSerializer = new XmlSerializer(typeof(SettingsInfo)); @@ -203,11 +226,6 @@ private static SettingsInfo DeserializeFromXmlFile(string filePath) var settingsInfo = xmlSerializer.Deserialize(fileStream) as SettingsInfo; - if (settingsInfo == null) - { - throw new InvalidOperationException("Failed to deserialize settings from XML file. The result was null."); - } - return settingsInfo; } @@ -239,6 +257,19 @@ private static void SerializeToFile(string filePath) #endregion + #region Backup + /* + private static void Backup() + { + Log.Info("Creating settings backup..."); + + // Create the backup directory if it does not exist + Directory.CreateDirectory(GetSettingsBackupFolderLocation()); + } + */ + + #endregion + #region Upgrade /// diff --git a/Source/NETworkManager/App.xaml.cs b/Source/NETworkManager/App.xaml.cs index b1d067e00e..ace2a1267f 100644 --- a/Source/NETworkManager/App.xaml.cs +++ b/Source/NETworkManager/App.xaml.cs @@ -93,15 +93,13 @@ by BornToBeRoot } catch (InvalidOperationException ex) { - Log.Error("Could not load application settings!"); - Log.Error(ex.Message + "-" + ex.StackTrace); - + Log.Error("Could not load application settings!", ex); + HandleCorruptedSettingsFile(); } catch (JsonException ex) { - Log.Error("Could not load application settings! JSON file is corrupted or invalid."); - Log.Error(ex.Message + "-" + ex.StackTrace); + Log.Error("Could not load application settings! JSON file is corrupted or invalid.", ex); HandleCorruptedSettingsFile(); } @@ -225,8 +223,10 @@ private void HandleCorruptedSettingsFile() // Create backup of corrupted file var destinationFile = $"{TimestampHelper.GetTimestamp()}_corrupted_" + SettingsManager.GetSettingsFileName(); + File.Copy(SettingsManager.GetSettingsFilePath(), Path.Combine(SettingsManager.GetSettingsFolderLocation(), destinationFile)); + Log.Info($"A backup of the corrupted settings file has been saved under {destinationFile}"); // Initialize default application settings @@ -283,4 +283,4 @@ private void Save() ProfileManager.Save(); } } -} \ No newline at end of file +} From a2d1f192a0d2ad9fd398dcd55854b9d42f290d31 Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Wed, 24 Dec 2025 17:12:01 +0100 Subject: [PATCH 8/8] Docs: #3282 --- Website/docs/changelog/next-release.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md index a06d9051ae..417fc79f9c 100644 --- a/Website/docs/changelog/next-release.md +++ b/Website/docs/changelog/next-release.md @@ -51,6 +51,10 @@ Release date: **xx.xx.2025** - Profile file dialog migrated to a child window to improve usability. [#3227](https://github.com/BornToBeRoot/NETworkManager/pull/3227) - Credential dialogs migrated to child windows to improve usability. [#3231](https://github.com/BornToBeRoot/NETworkManager/pull/3231) +**Settings** + +- Settings format migrated from `XML` to `JSON`. The settings file will be automatically converted on first start after the update. [#3282](https://github.com/BornToBeRoot/NETworkManager/pull/3282) + **DNS Lookup** - Allow hostname as server address in addition to IP address in the add/edit server dialog. [#3261](https://github.com/BornToBeRoot/NETworkManager/pull/3261)