From 7fa5f4a4051623151d5292bc4d34073244930734 Mon Sep 17 00:00:00 2001
From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
Date: Sun, 11 Jan 2026 22:01:50 +0100
Subject: [PATCH 1/3] Feature: Configure backup retention
---
.../Resources/Strings.Designer.cs | 22 +++++++++++++
.../Resources/Strings.resx | 10 ++++++
.../Network/NetworkInterface.cs | 1 -
.../GlobalStaticConfiguration.cs | 16 +++++-----
.../NETworkManager.Settings/SettingsInfo.cs | 31 +++++++++++++++++++
.../SettingsManager.cs | 12 ++++++-
.../ViewModels/SettingsProfilesViewModel.cs | 24 ++++++++++++++
.../ViewModels/SettingsSettingsViewModel.cs | 30 ++++++++++++++++--
.../Views/SettingsSettingsView.xaml | 18 ++++++++++-
9 files changed, 150 insertions(+), 14 deletions(-)
diff --git a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs
index fbd0f19ec1..4e7e0aca64 100644
--- a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs
+++ b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs
@@ -4552,6 +4552,19 @@ public static string HelpMessage_SaveCredentials {
}
}
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die The number of settings backups that are retained before the oldest one is deleted.
+ ///
+ ///An automatic backup is only created once a day, before saving a change.
+ ///
+ ///The value 0 disables the creation of automatic backups. Backups that have already been created are not deleted. ähnelt.
+ ///
+ public static string HelpMessage_SettingsMaximumNumberOfBackups {
+ get {
+ return ResourceManager.GetString("HelpMessage_SettingsMaximumNumberOfBackups", resourceCulture);
+ }
+ }
+
///
/// Sucht eine lokalisierte Zeichenfolge, die Displays the status bar in the bottom-left of the WebView when hovering over a link. ähnelt.
///
@@ -5783,6 +5796,15 @@ public static string MaximumHops {
}
}
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Maximum Number of Backups ähnelt.
+ ///
+ public static string MaximumNumberOfBackups {
+ get {
+ return ResourceManager.GetString("MaximumNumberOfBackups", resourceCulture);
+ }
+ }
+
///
/// Sucht eine lokalisierte Zeichenfolge, die Maximum number ({0}) of hops/router reached! ähnelt.
///
diff --git a/Source/NETworkManager.Localization/Resources/Strings.resx b/Source/NETworkManager.Localization/Resources/Strings.resx
index 28ccf1c004..14ca461f78 100644
--- a/Source/NETworkManager.Localization/Resources/Strings.resx
+++ b/Source/NETworkManager.Localization/Resources/Strings.resx
@@ -3951,4 +3951,14 @@ If you click Cancel, the profile file will remain unencrypted.
Could not parse "{0}".
+
+ Maximum Number of Backups
+
+
+ The number of settings backups that are retained before the oldest one is deleted.
+
+An automatic backup is only created once a day, before saving a change.
+
+The value 0 disables the creation of automatic backups. Backups that have already been created are not deleted.
+
\ No newline at end of file
diff --git a/Source/NETworkManager.Models/Network/NetworkInterface.cs b/Source/NETworkManager.Models/Network/NetworkInterface.cs
index d7662f6704..7cd8c34038 100644
--- a/Source/NETworkManager.Models/Network/NetworkInterface.cs
+++ b/Source/NETworkManager.Models/Network/NetworkInterface.cs
@@ -527,7 +527,6 @@ private static void RemoveIPAddressFromNetworkInterface(NetworkInterfaceConfig c
#endregion
-
#region Events
///
diff --git a/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs b/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs
index af7ea9117d..28c92928a6 100644
--- a/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs
+++ b/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs
@@ -46,9 +46,6 @@ public static class GlobalStaticConfiguration
public static string ZipFileExtensionFilter => "ZIP Archive (*.zip)|*.zip";
public static string XmlFileExtensionFilter => "XML-File (*.xml)|*.xml";
- // Backup settings
- public static int Backup_MaximumNumberOfBackups => 10;
-
#endregion
#region Default settings
@@ -74,18 +71,21 @@ public static class GlobalStaticConfiguration
public static bool Status_ShowWindowOnNetworkChange => true;
public static int Status_WindowCloseTime => 10;
- // HotKey
+ // Settings: HotKey
public static int HotKey_ShowWindowKey => 79;
public static int HotKey_ShowWindowModifier => 3;
- // Update
+ // Settings: Update
public static bool Update_CheckForUpdatesAtStartup => true;
-
public static bool Update_CheckForPreReleases => false;
-
- // Experimental
public static bool Experimental_EnableExperimentalFeatures => false;
+ // Settings: Profiles
+ public static int Profiles_MaximumNumberOfBackups => 10;
+
+ // Settings: Settings
+ public static int Settings_MaximumNumberOfBackups => 10;
+
// Application: Dashboard
public static string Dashboard_PublicIPv4Address => "1.1.1.1";
public static string Dashboard_PublicIPv6Address => "2606:4700:4700::1111";
diff --git a/Source/NETworkManager.Settings/SettingsInfo.cs b/Source/NETworkManager.Settings/SettingsInfo.cs
index 4a41e94680..b8f993cff0 100644
--- a/Source/NETworkManager.Settings/SettingsInfo.cs
+++ b/Source/NETworkManager.Settings/SettingsInfo.cs
@@ -582,6 +582,37 @@ public string Profiles_LastSelected
}
}
+ private int _profiles_MaximumNumberOfBackups = GlobalStaticConfiguration.Profiles_MaximumNumberOfBackups;
+
+ public int Profiles_MaximumNumberOfBackups
+ {
+ get => _profiles_MaximumNumberOfBackups;
+ set
+ {
+ if (value == _profiles_MaximumNumberOfBackups)
+ return;
+
+ _profiles_MaximumNumberOfBackups = value;
+ OnPropertyChanged();
+ }
+ }
+
+ // Settings
+ private int _settings_MaximumNumberOfBackups = GlobalStaticConfiguration.Settings_MaximumNumberOfBackups;
+
+ public int Settings_MaximumNumberOfBackups
+ {
+ get => _settings_MaximumNumberOfBackups;
+ set
+ {
+ if (value == _settings_MaximumNumberOfBackups)
+ return;
+
+ _settings_MaximumNumberOfBackups = value;
+ OnPropertyChanged();
+ }
+ }
+
#endregion
#region Others
diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs
index 7c0041f063..6aeb6b9a96 100644
--- a/Source/NETworkManager.Settings/SettingsManager.cs
+++ b/Source/NETworkManager.Settings/SettingsManager.cs
@@ -265,6 +265,16 @@ private static void SerializeToFile(string filePath)
/// called as part of a daily maintenance routine.
private static void CreateDailyBackupIfNeeded()
{
+ var maxBackups = Current.Settings_MaximumNumberOfBackups;
+
+ // Check if backups are disabled
+ if (maxBackups == 0)
+ {
+ Log.Debug("Daily backups are disabled. Skipping backup creation...");
+
+ return;
+ }
+
var currentDate = DateTime.Now.Date;
if (Current.LastBackup < currentDate)
@@ -284,7 +294,7 @@ private static void CreateDailyBackupIfNeeded()
// Cleanup old backups
CleanupBackups(GetSettingsBackupFolderLocation(),
GetSettingsFileName(),
- GlobalStaticConfiguration.Backup_MaximumNumberOfBackups);
+ maxBackups);
Current.LastBackup = currentDate;
}
diff --git a/Source/NETworkManager/ViewModels/SettingsProfilesViewModel.cs b/Source/NETworkManager/ViewModels/SettingsProfilesViewModel.cs
index fd42c76821..04f4b7fcb1 100644
--- a/Source/NETworkManager/ViewModels/SettingsProfilesViewModel.cs
+++ b/Source/NETworkManager/ViewModels/SettingsProfilesViewModel.cs
@@ -22,6 +22,8 @@ public class SettingsProfilesViewModel : ViewModelBase
public Action CloseAction { get; set; }
+ private readonly bool _isLoading;
+
private string _location;
public string Location
@@ -67,12 +69,31 @@ public ProfileFileInfo SelectedProfileFile
}
}
+ private int _maximumNumberOfBackups;
+
+ public int MaximumNumberOfBackups
+ {
+ get => _maximumNumberOfBackups;
+ set
+ {
+ if (value == _maximumNumberOfBackups)
+ return;
+
+ if (!_isLoading)
+ SettingsManager.Current.Profiles_MaximumNumberOfBackups = value;
+
+ _maximumNumberOfBackups = value;
+ OnPropertyChanged();
+ }
+ }
#endregion
#region Constructor, LoadSettings
public SettingsProfilesViewModel()
{
+ _isLoading = true;
+
ProfileFiles = new CollectionViewSource { Source = ProfileManager.ProfileFiles }.View;
ProfileFiles.SortDescriptions.Add(
new SortDescription(nameof(ProfileFileInfo.Name), ListSortDirection.Ascending));
@@ -80,11 +101,14 @@ public SettingsProfilesViewModel()
SelectedProfileFile = ProfileFiles.Cast().FirstOrDefault();
LoadSettings();
+
+ _isLoading = false;
}
private void LoadSettings()
{
Location = ProfileManager.GetProfilesFolderLocation();
+ MaximumNumberOfBackups = SettingsManager.Current.Profiles_MaximumNumberOfBackups;
}
#endregion
diff --git a/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs b/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs
index 399ffb1e02..fbe8f3be3f 100644
--- a/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs
+++ b/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs
@@ -1,8 +1,6 @@
-using MahApps.Metro.SimpleChildWindow;
-using NETworkManager.Localization.Resources;
+using NETworkManager.Localization.Resources;
using NETworkManager.Settings;
using NETworkManager.Utilities;
-using NETworkManager.Views;
using System;
using System.Diagnostics;
using System.Threading.Tasks;
@@ -16,6 +14,8 @@ public class SettingsSettingsViewModel : ViewModelBase
#region Variables
public Action CloseAction { get; set; }
+ private readonly bool _isLoading;
+
private string _location;
public string Location
@@ -30,18 +30,42 @@ public string Location
OnPropertyChanged();
}
}
+
+ private int _maximumNumberOfBackups;
+
+ public int MaximumNumberOfBackups
+ {
+ get => _maximumNumberOfBackups;
+ set
+ {
+ if (value == _maximumNumberOfBackups)
+ return;
+
+ if (!_isLoading)
+ SettingsManager.Current.Settings_MaximumNumberOfBackups = value;
+
+ _maximumNumberOfBackups = value;
+ OnPropertyChanged();
+ }
+ }
+
#endregion
#region Constructor, LoadSettings
public SettingsSettingsViewModel()
{
+ _isLoading = true;
+
LoadSettings();
+
+ _isLoading = false;
}
private void LoadSettings()
{
Location = SettingsManager.GetSettingsFolderLocation();
+ MaximumNumberOfBackups = SettingsManager.Current.Settings_MaximumNumberOfBackups;
}
#endregion
diff --git a/Source/NETworkManager/Views/SettingsSettingsView.xaml b/Source/NETworkManager/Views/SettingsSettingsView.xaml
index 7f91995927..c97e846d8a 100644
--- a/Source/NETworkManager/Views/SettingsSettingsView.xaml
+++ b/Source/NETworkManager/Views/SettingsSettingsView.xaml
@@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:viewModels="clr-namespace:NETworkManager.ViewModels"
xmlns:localization="clr-namespace:NETworkManager.Localization.Resources;assembly=NETworkManager.Localization"
@@ -30,8 +31,23 @@
+
+
+
+
+
+
+
+
+
+
+ Style="{StaticResource DefaultButton}" HorizontalAlignment="Left"
+ />
\ No newline at end of file
From 4b0f349d3bd682513712f4b7145218bf6693472b Mon Sep 17 00:00:00 2001
From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
Date: Sun, 11 Jan 2026 22:32:49 +0100
Subject: [PATCH 2/3] Feature: Daily Backup
---
.../Resources/Strings.Designer.cs | 33 ++++++++-------
.../Resources/Strings.resx | 13 +++---
.../GlobalStaticConfiguration.cs | 2 +
.../NETworkManager.Settings/SettingsInfo.cs | 30 +++++++++++++
.../SettingsManager.cs | 6 +--
.../ViewModels/SettingsProfilesViewModel.cs | 19 +++++++++
.../ViewModels/SettingsSettingsViewModel.cs | 19 +++++++++
.../Views/SettingsProfilesView.xaml | 24 ++++++++++-
.../Views/SettingsSettingsView.xaml | 16 ++++---
Website/docs/changelog/next-release.md | 2 +-
Website/docs/settings/profiles.md | 42 +++++++++++++++++--
Website/docs/settings/settings.md | 32 ++++++++++++--
12 files changed, 197 insertions(+), 41 deletions(-)
diff --git a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs
index 4e7e0aca64..b57b12bff7 100644
--- a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs
+++ b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs
@@ -2220,6 +2220,15 @@ public static string Country {
}
}
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Create daily backup ähnelt.
+ ///
+ public static string CreateDailyBackup {
+ get {
+ return ResourceManager.GetString("CreateDailyBackup", resourceCulture);
+ }
+ }
+
///
/// Sucht eine lokalisierte Zeichenfolge, die Credential ähnelt.
///
@@ -4450,6 +4459,15 @@ public static string HelpMessage_ExperimentalFeatures {
}
}
+ ///
+ /// Sucht eine lokalisierte Zeichenfolge, die Number of backups that are retained before the oldest one is deleted. ähnelt.
+ ///
+ public static string HelpMessage_MaximumNumberOfBackups {
+ get {
+ return ResourceManager.GetString("HelpMessage_MaximumNumberOfBackups", resourceCulture);
+ }
+ }
+
///
/// Sucht eine lokalisierte Zeichenfolge, die Application that is displayed at startup. ähnelt.
///
@@ -4552,19 +4570,6 @@ public static string HelpMessage_SaveCredentials {
}
}
- ///
- /// Sucht eine lokalisierte Zeichenfolge, die The number of settings backups that are retained before the oldest one is deleted.
- ///
- ///An automatic backup is only created once a day, before saving a change.
- ///
- ///The value 0 disables the creation of automatic backups. Backups that have already been created are not deleted. ähnelt.
- ///
- public static string HelpMessage_SettingsMaximumNumberOfBackups {
- get {
- return ResourceManager.GetString("HelpMessage_SettingsMaximumNumberOfBackups", resourceCulture);
- }
- }
-
///
/// Sucht eine lokalisierte Zeichenfolge, die Displays the status bar in the bottom-left of the WebView when hovering over a link. ähnelt.
///
@@ -5797,7 +5802,7 @@ public static string MaximumHops {
}
///
- /// Sucht eine lokalisierte Zeichenfolge, die Maximum Number of Backups ähnelt.
+ /// Sucht eine lokalisierte Zeichenfolge, die Maximum number of backups ähnelt.
///
public static string MaximumNumberOfBackups {
get {
diff --git a/Source/NETworkManager.Localization/Resources/Strings.resx b/Source/NETworkManager.Localization/Resources/Strings.resx
index 14ca461f78..3dd4967eaf 100644
--- a/Source/NETworkManager.Localization/Resources/Strings.resx
+++ b/Source/NETworkManager.Localization/Resources/Strings.resx
@@ -3952,13 +3952,12 @@ If you click Cancel, the profile file will remain unencrypted.
Could not parse "{0}".
- Maximum Number of Backups
+ Maximum number of backups
-
- The number of settings backups that are retained before the oldest one is deleted.
-
-An automatic backup is only created once a day, before saving a change.
-
-The value 0 disables the creation of automatic backups. Backups that have already been created are not deleted.
+
+ Create daily backup
+
+
+ Number of backups that are retained before the oldest one is deleted.
\ No newline at end of file
diff --git a/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs b/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs
index 28c92928a6..851a5c233c 100644
--- a/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs
+++ b/Source/NETworkManager.Settings/GlobalStaticConfiguration.cs
@@ -81,9 +81,11 @@ public static class GlobalStaticConfiguration
public static bool Experimental_EnableExperimentalFeatures => false;
// Settings: Profiles
+ public static bool Profiles_IsDailyBackupEnabled => true;
public static int Profiles_MaximumNumberOfBackups => 10;
// Settings: Settings
+ public static bool Settings_IsDailyBackupEnabled => true;
public static int Settings_MaximumNumberOfBackups => 10;
// Application: Dashboard
diff --git a/Source/NETworkManager.Settings/SettingsInfo.cs b/Source/NETworkManager.Settings/SettingsInfo.cs
index b8f993cff0..97834d7515 100644
--- a/Source/NETworkManager.Settings/SettingsInfo.cs
+++ b/Source/NETworkManager.Settings/SettingsInfo.cs
@@ -582,6 +582,21 @@ public string Profiles_LastSelected
}
}
+ private bool _profiles_IsDailyBackupEnabled = GlobalStaticConfiguration.Profiles_IsDailyBackupEnabled;
+
+ public bool Profiles_IsDailyBackupEnabled
+ {
+ get => _profiles_IsDailyBackupEnabled;
+ set
+ {
+ if (value == _profiles_IsDailyBackupEnabled)
+ return;
+
+ _profiles_IsDailyBackupEnabled = value;
+ OnPropertyChanged();
+ }
+ }
+
private int _profiles_MaximumNumberOfBackups = GlobalStaticConfiguration.Profiles_MaximumNumberOfBackups;
public int Profiles_MaximumNumberOfBackups
@@ -598,6 +613,21 @@ public int Profiles_MaximumNumberOfBackups
}
// Settings
+ private bool _settings_IsDailyBackupEnabled = GlobalStaticConfiguration.Settings_IsDailyBackupEnabled;
+
+ public bool Settings_IsDailyBackupEnabled
+ {
+ get => _settings_IsDailyBackupEnabled;
+ set
+ {
+ if (value == _settings_IsDailyBackupEnabled)
+ return;
+
+ _settings_IsDailyBackupEnabled = value;
+ OnPropertyChanged();
+ }
+ }
+
private int _settings_MaximumNumberOfBackups = GlobalStaticConfiguration.Settings_MaximumNumberOfBackups;
public int Settings_MaximumNumberOfBackups
diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs
index 6aeb6b9a96..a0c5c9c1ca 100644
--- a/Source/NETworkManager.Settings/SettingsManager.cs
+++ b/Source/NETworkManager.Settings/SettingsManager.cs
@@ -265,10 +265,8 @@ private static void SerializeToFile(string filePath)
/// called as part of a daily maintenance routine.
private static void CreateDailyBackupIfNeeded()
{
- var maxBackups = Current.Settings_MaximumNumberOfBackups;
-
// Check if backups are disabled
- if (maxBackups == 0)
+ if (!Current.Settings_IsDailyBackupEnabled)
{
Log.Debug("Daily backups are disabled. Skipping backup creation...");
@@ -294,7 +292,7 @@ private static void CreateDailyBackupIfNeeded()
// Cleanup old backups
CleanupBackups(GetSettingsBackupFolderLocation(),
GetSettingsFileName(),
- maxBackups);
+ Current.Settings_MaximumNumberOfBackups);
Current.LastBackup = currentDate;
}
diff --git a/Source/NETworkManager/ViewModels/SettingsProfilesViewModel.cs b/Source/NETworkManager/ViewModels/SettingsProfilesViewModel.cs
index 04f4b7fcb1..7dd0e17546 100644
--- a/Source/NETworkManager/ViewModels/SettingsProfilesViewModel.cs
+++ b/Source/NETworkManager/ViewModels/SettingsProfilesViewModel.cs
@@ -69,6 +69,24 @@ public ProfileFileInfo SelectedProfileFile
}
}
+ private bool _isDailyBackupEnabled;
+
+ public bool IsDailyBackupEnabled
+ {
+ get => _isDailyBackupEnabled;
+ set
+ {
+ if (value == _isDailyBackupEnabled)
+ return;
+
+ if (!_isLoading)
+ SettingsManager.Current.Profiles_IsDailyBackupEnabled = value;
+
+ _isDailyBackupEnabled = value;
+ OnPropertyChanged();
+ }
+ }
+
private int _maximumNumberOfBackups;
public int MaximumNumberOfBackups
@@ -108,6 +126,7 @@ public SettingsProfilesViewModel()
private void LoadSettings()
{
Location = ProfileManager.GetProfilesFolderLocation();
+ IsDailyBackupEnabled = SettingsManager.Current.Profiles_IsDailyBackupEnabled;
MaximumNumberOfBackups = SettingsManager.Current.Profiles_MaximumNumberOfBackups;
}
diff --git a/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs b/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs
index fbe8f3be3f..dc1d7d95b1 100644
--- a/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs
+++ b/Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs
@@ -31,6 +31,24 @@ public string Location
}
}
+ private bool _isDailyBackupEnabled;
+
+ public bool IsDailyBackupEnabled
+ {
+ get => _isDailyBackupEnabled;
+ set
+ {
+ if (value == _isDailyBackupEnabled)
+ return;
+
+ if (!_isLoading)
+ SettingsManager.Current.Settings_IsDailyBackupEnabled = value;
+
+ _isDailyBackupEnabled = value;
+ OnPropertyChanged();
+ }
+ }
+
private int _maximumNumberOfBackups;
public int MaximumNumberOfBackups
@@ -65,6 +83,7 @@ public SettingsSettingsViewModel()
private void LoadSettings()
{
Location = SettingsManager.GetSettingsFolderLocation();
+ IsDailyBackupEnabled = SettingsManager.Current.Settings_IsDailyBackupEnabled;
MaximumNumberOfBackups = SettingsManager.Current.Settings_MaximumNumberOfBackups;
}
diff --git a/Source/NETworkManager/Views/SettingsProfilesView.xaml b/Source/NETworkManager/Views/SettingsProfilesView.xaml
index d73f2640c8..0989c4a24d 100644
--- a/Source/NETworkManager/Views/SettingsProfilesView.xaml
+++ b/Source/NETworkManager/Views/SettingsProfilesView.xaml
@@ -3,6 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:converters="clr-namespace:NETworkManager.Converters;assembly=NETworkManager.Converters"
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:wpfHelpers="clr-namespace:NETworkManager.Utilities.WPF;assembly=NETworkManager.Utilities.WPF"
@@ -144,7 +145,8 @@
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/Source/NETworkManager/Views/SettingsSettingsView.xaml b/Source/NETworkManager/Views/SettingsSettingsView.xaml
index c97e846d8a..c4880b397e 100644
--- a/Source/NETworkManager/Views/SettingsSettingsView.xaml
+++ b/Source/NETworkManager/Views/SettingsSettingsView.xaml
@@ -32,13 +32,17 @@
-
-
-
+
+
+
+
diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md
index 28bae845be..bf65f5504a 100644
--- a/Website/docs/changelog/next-release.md
+++ b/Website/docs/changelog/next-release.md
@@ -65,7 +65,7 @@ Release date: **xx.xx.2025**
**Settings**
- Settings file format migrated from `XML` to `JSON`. The settings file will be automatically converted on first load after the update. [#3282](https://github.com/BornToBeRoot/NETworkManager/pull/3282)
-- Create a daily backup of the settings file before saving changes. Up to `10` backup files are kept in the `Backups` subfolder of the settings directory. [#3283](https://github.com/BornToBeRoot/NETworkManager/pull/3283)
+- Create a daily backup of the settings file before saving changes. By default, up to `10` backup files are kept in the `Backups` subfolder of the settings directory. [#3283](https://github.com/BornToBeRoot/NETworkManager/pull/3283) [#3302](https://github.com/BornToBeRoot/NETworkManager/pull/3302)
**Dashboard**
diff --git a/Website/docs/settings/profiles.md b/Website/docs/settings/profiles.md
index 5789f625fb..186924aa4b 100644
--- a/Website/docs/settings/profiles.md
+++ b/Website/docs/settings/profiles.md
@@ -19,9 +19,21 @@ Folder where the application profiles are stored.
:::note
-It is recommended to backup the above files on a regular basis.
-
-To restore the profiles, close the application and copy the files from the backup to the above location.
+**Recommendation**
+It is strongly recommended to regularly back up your profile files.
+
+**Automatic backups**
+NETworkManager automatically creates a backup of the profile file before applying any changes. See [Create daily backup](#create-daily-backup) and [Maximum number of backups](#maximum-number-of-backups) for configuration options.
+- Location: `Profiles\Backups` subfolder (relative to the main configuration directory)
+- Naming: timestamped (e.g. `yyyyMMddHHmmss_.json`)
+- Frequency: **once per day** at most (even if multiple changes occur)
+- Retention: keeps the **10 most recent backups** (default)
+
+**Restoring profiles**
+1. Completely close NETworkManager
+2. Locate the desired backup in `Profiles\Backups`
+3. Copy the file(s) back to the original folder (overwrite existing files or copy them under a different name)
+4. Restart the application
:::
@@ -44,3 +56,27 @@ Profile files can be encrypted with a master password. See [FAQ > How to enable
At least one profile is required and must exist.
:::
+
+### Create daily backup
+
+Create a daily backup of the profile file before applying any changes.
+
+**Type**: `Boolean`
+
+**Default:** `Enabled`
+
+:::note
+
+Backups are stored in the `Profiles\Backups` subfolder. See [Location](#location) for more details.
+
+Backups are created at most once per day, even if multiple changes occur.
+
+:::
+
+### Maximum number of backups
+
+Maximum number of backups to keep. Older backups will be deleted automatically once a new backup is created.
+
+**Type:** `Integer` [Min `1`, Max `365`]
+
+**Default:** `10`
diff --git a/Website/docs/settings/settings.md b/Website/docs/settings/settings.md
index f772085232..32342b3d6e 100644
--- a/Website/docs/settings/settings.md
+++ b/Website/docs/settings/settings.md
@@ -23,20 +23,44 @@ Folder where the application settings are stored.
It is strongly recommended to regularly back up your settings files.
**Automatic backups**
-NETworkManager automatically creates a backup of the settings files before applying any changes.
-- Location: `Settings\Backups` subfolder (relative to the main configuration directory)
+NETworkManager automatically creates a backup of the settings files before applying any changes. See [Create daily backup](#create-daily-backup) and [Maximum number of backups](#maximum-number-of-backups) for configuration options.
+- Location: `Settings\Backups` subfolder
- Naming: timestamped (e.g. `yyyyMMddHHmmss_Settings.json`)
- Frequency: **once per day** at most (even if multiple changes occur)
-- Retention: keeps the **10 most recent backups**
+- Retention: keeps the **10 most recent backups** (default)
**Restoring settings**
1. Completely close NETworkManager
2. Locate the desired backup in `Settings\Backups`
-3. Copy the file(s) back to the original configuration folder (overwriting existing files)
+3. Copy the file(s) back to the original folder (overwriting existing files)
4. Restart the application
:::
+### Create daily backup
+
+Create a daily backup of the application settings before applying any changes.
+
+**Type**: `Boolean`
+
+**Default:** `Enabled`
+
+:::note
+
+Backups are stored in the `Settings\Backups` subfolder. See [Location](#location) for more details.
+
+Backups are created at most once per day, even if multiple changes occur.
+
+:::
+
+### Maximum number of backups
+
+Maximum number of backups to keep. Older backups will be deleted automatically once a new backup is created.
+
+**Type:** `Integer` [Min `1`, Max `365`]
+
+**Default:** `10`
+
### Reset
Button to reset all application settings to their default values.
From 88928b298669af8a25a30c0b0666c186d78c8787 Mon Sep 17 00:00:00 2001
From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com>
Date: Sun, 11 Jan 2026 23:01:01 +0100
Subject: [PATCH 3/3] Feature: Add more backups before important operations
---
.../NETworkManager.Profiles/ProfileManager.cs | 60 +++++++++++++------
1 file changed, 42 insertions(+), 18 deletions(-)
diff --git a/Source/NETworkManager.Profiles/ProfileManager.cs b/Source/NETworkManager.Profiles/ProfileManager.cs
index e7cdb73390..c236eab1ac 100644
--- a/Source/NETworkManager.Profiles/ProfileManager.cs
+++ b/Source/NETworkManager.Profiles/ProfileManager.cs
@@ -25,14 +25,14 @@ public static class ProfileManager
private const string ProfilesFolderName = "Profiles";
///
- /// Default profile name.
+ /// Profiles backups directory name.
///
- private const string ProfilesDefaultFileName = "Default";
+ private static string BackupFolderName => "Backups";
///
- /// Profiles backups directory name.
+ /// Default profile name.
///
- private static string BackupFolderName => "Backups";
+ private const string ProfilesDefaultFileName = "Default";
///
/// Profile file extension.
@@ -290,14 +290,21 @@ public static void CreateEmptyProfileFile(string profileName)
/// New of the profile file.
public static void RenameProfileFile(ProfileFileInfo profileFileInfo, string newProfileName)
{
+ // Check if the profile is currently in use
var switchProfile = false;
-
+
if (LoadedProfileFile != null && LoadedProfileFile.Equals(profileFileInfo))
{
Save();
switchProfile = true;
}
+ // Create backup
+ Backup(profileFileInfo.Path,
+ GetProfilesBackupFolderLocation(),
+ TimestampHelper.GetTimestampFilename(Path.GetFileName(profileFileInfo.Path)));
+
+ // Create new profile info with the new name
ProfileFileInfo newProfileFileInfo = new(newProfileName,
Path.Combine(GetProfilesFolderLocation(), $"{newProfileName}{Path.GetExtension(profileFileInfo.Path)}"),
profileFileInfo.IsEncrypted)
@@ -306,15 +313,18 @@ public static void RenameProfileFile(ProfileFileInfo profileFileInfo, string new
IsPasswordValid = profileFileInfo.IsPasswordValid
};
+ // Copy the profile file to the new location
File.Copy(profileFileInfo.Path, newProfileFileInfo.Path);
ProfileFiles.Add(newProfileFileInfo);
+ // Switch profile, if it was previously loaded
if (switchProfile)
{
Switch(newProfileFileInfo, false);
LoadedProfileFileChanged(LoadedProfileFile, true);
}
+ // Remove the old profile file
File.Delete(profileFileInfo.Path);
ProfileFiles.Remove(profileFileInfo);
}
@@ -353,6 +363,11 @@ public static void EnableEncryption(ProfileFileInfo profileFileInfo, SecureStrin
switchProfile = true;
}
+ // Create backup
+ Backup(profileFileInfo.Path,
+ GetProfilesBackupFolderLocation(),
+ TimestampHelper.GetTimestampFilename(Path.GetFileName(profileFileInfo.Path)));
+
// Create a new profile info with the encryption infos
var newProfileFileInfo = new ProfileFileInfo(profileFileInfo.Name,
Path.ChangeExtension(profileFileInfo.Path, ProfileFileExtensionEncrypted), true)
@@ -361,9 +376,9 @@ public static void EnableEncryption(ProfileFileInfo profileFileInfo, SecureStrin
IsPasswordValid = true
};
- List profiles = Path.GetExtension(profileFileInfo.Path) == LegacyProfileFileExtension
- ? DeserializeFromXmlFile(profileFileInfo.Path)
- : DeserializeFromFile(profileFileInfo.Path);
+ List profiles = Path.GetExtension(profileFileInfo.Path) == LegacyProfileFileExtension ?
+ DeserializeFromXmlFile(profileFileInfo.Path) :
+ DeserializeFromFile(profileFileInfo.Path);
// Save the encrypted file
var decryptedBytes = SerializeToByteArray(profiles);
@@ -409,7 +424,12 @@ public static void ChangeMasterPassword(ProfileFileInfo profileFileInfo, SecureS
switchProfile = true;
}
- // Create a new profile info with the encryption infos
+ // Create backup
+ Backup(profileFileInfo.Path,
+ GetProfilesBackupFolderLocation(),
+ TimestampHelper.GetTimestampFilename(Path.GetFileName(profileFileInfo.Path)));
+
+ // Create new profile info with the encryption infos
var newProfileFileInfo = new ProfileFileInfo(profileFileInfo.Name,
Path.ChangeExtension(profileFileInfo.Path, ProfileFileExtensionEncrypted), true)
{
@@ -423,11 +443,9 @@ public static void ChangeMasterPassword(ProfileFileInfo profileFileInfo, SecureS
GlobalStaticConfiguration.Profile_EncryptionKeySize,
GlobalStaticConfiguration.Profile_EncryptionIterations);
- List profiles;
-
- profiles = IsXmlContent(decryptedBytes)
- ? DeserializeFromXmlByteArray(decryptedBytes)
- : DeserializeFromByteArray(decryptedBytes);
+ List profiles = IsXmlContent(decryptedBytes) ?
+ DeserializeFromXmlByteArray(decryptedBytes) :
+ DeserializeFromByteArray(decryptedBytes);
// Save the encrypted file
decryptedBytes = SerializeToByteArray(profiles);
@@ -468,7 +486,12 @@ public static void DisableEncryption(ProfileFileInfo profileFileInfo, SecureStri
switchProfile = true;
}
- // Create a new profile info
+ // Create backup
+ Backup(profileFileInfo.Path,
+ GetProfilesBackupFolderLocation(),
+ TimestampHelper.GetTimestampFilename(Path.GetFileName(profileFileInfo.Path)));
+
+ // Create new profile info
var newProfileFileInfo = new ProfileFileInfo(profileFileInfo.Name,
Path.ChangeExtension(profileFileInfo.Path, ProfileFileExtension));
@@ -478,9 +501,10 @@ public static void DisableEncryption(ProfileFileInfo profileFileInfo, SecureStri
GlobalStaticConfiguration.Profile_EncryptionKeySize,
GlobalStaticConfiguration.Profile_EncryptionIterations);
- List profiles = IsXmlContent(decryptedBytes)
- ? DeserializeFromXmlByteArray(decryptedBytes)
- : DeserializeFromByteArray(decryptedBytes);
+ List profiles = IsXmlContent(decryptedBytes) ?
+ DeserializeFromXmlByteArray(decryptedBytes) :
+ DeserializeFromByteArray(decryptedBytes);
+
// Save the decrypted profiles to the profile file
SerializeToFile(newProfileFileInfo.Path, profiles);