From 702f681a75472eb9cceef551d94be16e7bcad489 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 20:32:31 +0000 Subject: [PATCH 01/20] Initial plan From a8853bc68fcc257d1e75c2c955a2ea8b9c137a3d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 20:35:22 +0000 Subject: [PATCH 02/20] Add system-wide config feature to disable update checks Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- Source/NETworkManager.Settings/ConfigInfo.cs | 17 ++++ .../NETworkManager.Settings/ConfigManager.cs | 95 +++++++++++++++++++ .../SettingsManager.cs | 22 +++++ Source/NETworkManager/MainWindow.xaml.cs | 2 +- 4 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 Source/NETworkManager.Settings/ConfigInfo.cs create mode 100644 Source/NETworkManager.Settings/ConfigManager.cs diff --git a/Source/NETworkManager.Settings/ConfigInfo.cs b/Source/NETworkManager.Settings/ConfigInfo.cs new file mode 100644 index 0000000000..ae7a3882e2 --- /dev/null +++ b/Source/NETworkManager.Settings/ConfigInfo.cs @@ -0,0 +1,17 @@ +using System.Text.Json.Serialization; + +namespace NETworkManager.Settings; + +/// +/// Class that represents system-wide configuration that overrides user settings. +/// This configuration is loaded from a config.json file in the application directory. +/// +public class ConfigInfo +{ + /// + /// Disable update check for all users. When set to true, the application will not check for updates at startup. + /// This overrides the user's "Update_CheckForUpdatesAtStartup" setting. + /// + [JsonPropertyName("Update_DisableUpdateCheck")] + public bool? Update_DisableUpdateCheck { get; set; } +} diff --git a/Source/NETworkManager.Settings/ConfigManager.cs b/Source/NETworkManager.Settings/ConfigManager.cs new file mode 100644 index 0000000000..87e8af6011 --- /dev/null +++ b/Source/NETworkManager.Settings/ConfigManager.cs @@ -0,0 +1,95 @@ +using log4net; +using System; +using System.IO; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace NETworkManager.Settings; + +/// +/// Manager for system-wide configuration that is loaded from a config.json file +/// in the application directory. This configuration overrides user settings. +/// +public static class ConfigManager +{ + #region Variables + + /// + /// Logger for logging. + /// + private static readonly ILog Log = LogManager.GetLogger(typeof(ConfigManager)); + + /// + /// Config file name. + /// + private static string ConfigFileName => "config.json"; + + /// + /// System-wide configuration that is currently loaded. + /// + public static ConfigInfo Current { get; private set; } + + /// + /// JSON serializer options for consistent serialization/deserialization. + /// + private static readonly JsonSerializerOptions JsonOptions = new() + { + WriteIndented = true, + PropertyNameCaseInsensitive = true, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, + Converters = { new JsonStringEnumConverter() } + }; + + #endregion + + #region Methods + + /// + /// Method to get the config file path in the application directory. + /// + /// Config file path. + private static string GetConfigFilePath() + { + return Path.Combine(AssemblyManager.Current.Location, ConfigFileName); + } + + /// + /// Method to load the system-wide configuration from config.json file in the application directory. + /// + public static void Load() + { + var filePath = GetConfigFilePath(); + + // Check if config file exists + if (File.Exists(filePath)) + { + try + { + Log.Info($"Loading system-wide configuration from: {filePath}"); + + var jsonString = File.ReadAllText(filePath); + Current = JsonSerializer.Deserialize(jsonString, JsonOptions); + + Log.Info("System-wide configuration loaded successfully."); + + // Log enabled settings + if (Current.Update_DisableUpdateCheck.HasValue) + { + Log.Info($"System-wide setting - Update_DisableUpdateCheck: {Current.Update_DisableUpdateCheck.Value}"); + } + } + catch (Exception ex) + { + Log.Error($"Failed to load system-wide configuration from: {filePath}", ex); + Current = new ConfigInfo(); + } + } + else + { + Log.Debug($"No system-wide configuration file found at: {filePath}"); + Current = new ConfigInfo(); + } + } + + #endregion +} diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs index 34ff00a850..6223c83d1d 100644 --- a/Source/NETworkManager.Settings/SettingsManager.cs +++ b/Source/NETworkManager.Settings/SettingsManager.cs @@ -56,6 +56,25 @@ public static class SettingsManager /// public static bool HotKeysChanged { get; set; } + /// + /// Gets whether update check should be performed at startup. + /// This respects the system-wide configuration (config.json) which takes precedence over user settings. + /// + public static bool ShouldCheckForUpdatesAtStartup + { + get + { + // System-wide config takes precedence - if it explicitly disables updates, honor it + if (ConfigManager.Current?.Update_DisableUpdateCheck == true) + { + return false; + } + + // Otherwise, use the user's setting + return Current.Update_CheckForUpdatesAtStartup; + } + } + /// /// JSON serializer options for consistent serialization/deserialization. /// @@ -152,6 +171,9 @@ public static void Initialize() /// public static void Load() { + // Load system-wide configuration first (from app directory) + ConfigManager.Load(); + var filePath = GetSettingsFilePath(); var legacyFilePath = GetLegacySettingsFilePath(); diff --git a/Source/NETworkManager/MainWindow.xaml.cs b/Source/NETworkManager/MainWindow.xaml.cs index 6546c727be..ede6f0007c 100644 --- a/Source/NETworkManager/MainWindow.xaml.cs +++ b/Source/NETworkManager/MainWindow.xaml.cs @@ -561,7 +561,7 @@ private void Load() NetworkChange.NetworkAddressChanged += (_, _) => OnNetworkHasChanged(); // Search for updates... - if (SettingsManager.Current.Update_CheckForUpdatesAtStartup) + if (SettingsManager.ShouldCheckForUpdatesAtStartup) CheckForUpdates(); } From 83dc909bafdd11f27395af72fb094c880bbb3eae Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 20:36:32 +0000 Subject: [PATCH 03/20] Add documentation for system-wide config feature Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- Documentation/config/README.md | 41 ++++++++++++++++++++++++ Documentation/config/config.json.example | 3 ++ 2 files changed, 44 insertions(+) create mode 100644 Documentation/config/README.md create mode 100644 Documentation/config/config.json.example diff --git a/Documentation/config/README.md b/Documentation/config/README.md new file mode 100644 index 0000000000..2f61c5742f --- /dev/null +++ b/Documentation/config/README.md @@ -0,0 +1,41 @@ +# System-Wide Configuration + +This directory contains an example `config.json` file that can be placed in the application installation directory to override user settings for all users on a machine. + +## Usage + +1. Copy `config.json.example` to the NETworkManager installation directory (where `NETworkManager.exe` is located) +2. Rename it to `config.json` +3. Edit the settings as needed +4. Restart NETworkManager + +## Configuration Options + +### Update_DisableUpdateCheck + +When set to `true`, disables the automatic update check at startup for all users. + +**Example:** +```json +{ + "Update_DisableUpdateCheck": true +} +``` + +This is useful for enterprise deployments where you want to: +- Control software updates centrally +- Prevent users from being prompted about updates +- Disable update checks on multiple machines without user intervention + +## File Location + +The `config.json` file should be placed in: +- **Installed version**: `C:\Program Files\NETworkManager\` (or your custom installation path) +- **Portable version**: Same directory as `NETworkManager.exe` + +## Notes + +- System-wide configuration takes precedence over user settings +- If the file doesn't exist or contains invalid JSON, it will be ignored and default user settings will apply +- Changes to `config.json` require restarting the application to take effect +- The file is optional - if not present, user settings will be used as normal diff --git a/Documentation/config/config.json.example b/Documentation/config/config.json.example new file mode 100644 index 0000000000..17f2c6929e --- /dev/null +++ b/Documentation/config/config.json.example @@ -0,0 +1,3 @@ +{ + "Update_DisableUpdateCheck": true +} From 7dc158c72f7b50339d8fefd21df019174f73a842 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 20:37:11 +0000 Subject: [PATCH 04/20] Fix documentation formatting in config README Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- Documentation/config/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/config/README.md b/Documentation/config/README.md index 2f61c5742f..10d4d75fc7 100644 --- a/Documentation/config/README.md +++ b/Documentation/config/README.md @@ -4,8 +4,8 @@ This directory contains an example `config.json` file that can be placed in the ## Usage -1. Copy `config.json.example` to the NETworkManager installation directory (where `NETworkManager.exe` is located) -2. Rename it to `config.json` +1. Copy the example configuration file to the NETworkManager installation directory (where `NETworkManager.exe` is located) +2. Rename `config.json.example` to `config.json` 3. Edit the settings as needed 4. Restart NETworkManager From 36e595cfe7a70ed3de04ee0fe8a9b47e1c596038 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 1 Feb 2026 20:58:01 +0000 Subject: [PATCH 05/20] Rename ConfigManager to PolicyManager to avoid naming conflict Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- .../{ConfigInfo.cs => PolicyInfo.cs} | 4 +-- .../{ConfigManager.cs => PolicyManager.cs} | 30 +++++++++---------- .../SettingsManager.cs | 10 +++---- 3 files changed, 22 insertions(+), 22 deletions(-) rename Source/NETworkManager.Settings/{ConfigInfo.cs => PolicyInfo.cs} (83%) rename Source/NETworkManager.Settings/{ConfigManager.cs => PolicyManager.cs} (64%) diff --git a/Source/NETworkManager.Settings/ConfigInfo.cs b/Source/NETworkManager.Settings/PolicyInfo.cs similarity index 83% rename from Source/NETworkManager.Settings/ConfigInfo.cs rename to Source/NETworkManager.Settings/PolicyInfo.cs index ae7a3882e2..1e16581c8a 100644 --- a/Source/NETworkManager.Settings/ConfigInfo.cs +++ b/Source/NETworkManager.Settings/PolicyInfo.cs @@ -3,10 +3,10 @@ namespace NETworkManager.Settings; /// -/// Class that represents system-wide configuration that overrides user settings. +/// Class that represents system-wide policies that override user settings. /// This configuration is loaded from a config.json file in the application directory. /// -public class ConfigInfo +public class PolicyInfo { /// /// Disable update check for all users. When set to true, the application will not check for updates at startup. diff --git a/Source/NETworkManager.Settings/ConfigManager.cs b/Source/NETworkManager.Settings/PolicyManager.cs similarity index 64% rename from Source/NETworkManager.Settings/ConfigManager.cs rename to Source/NETworkManager.Settings/PolicyManager.cs index 87e8af6011..966c0a3905 100644 --- a/Source/NETworkManager.Settings/ConfigManager.cs +++ b/Source/NETworkManager.Settings/PolicyManager.cs @@ -7,17 +7,17 @@ namespace NETworkManager.Settings; /// -/// Manager for system-wide configuration that is loaded from a config.json file -/// in the application directory. This configuration overrides user settings. +/// Manager for system-wide policies that are loaded from a config.json file +/// in the application directory. These policies override user settings. /// -public static class ConfigManager +public static class PolicyManager { #region Variables /// /// Logger for logging. /// - private static readonly ILog Log = LogManager.GetLogger(typeof(ConfigManager)); + private static readonly ILog Log = LogManager.GetLogger(typeof(PolicyManager)); /// /// Config file name. @@ -25,9 +25,9 @@ public static class ConfigManager private static string ConfigFileName => "config.json"; /// - /// System-wide configuration that is currently loaded. + /// System-wide policies that are currently loaded. /// - public static ConfigInfo Current { get; private set; } + public static PolicyInfo Current { get; private set; } /// /// JSON serializer options for consistent serialization/deserialization. @@ -54,7 +54,7 @@ private static string GetConfigFilePath() } /// - /// Method to load the system-wide configuration from config.json file in the application directory. + /// Method to load the system-wide policies from config.json file in the application directory. /// public static void Load() { @@ -65,29 +65,29 @@ public static void Load() { try { - Log.Info($"Loading system-wide configuration from: {filePath}"); + Log.Info($"Loading system-wide policies from: {filePath}"); var jsonString = File.ReadAllText(filePath); - Current = JsonSerializer.Deserialize(jsonString, JsonOptions); + Current = JsonSerializer.Deserialize(jsonString, JsonOptions); - Log.Info("System-wide configuration loaded successfully."); + Log.Info("System-wide policies loaded successfully."); // Log enabled settings if (Current.Update_DisableUpdateCheck.HasValue) { - Log.Info($"System-wide setting - Update_DisableUpdateCheck: {Current.Update_DisableUpdateCheck.Value}"); + Log.Info($"System-wide policy - Update_DisableUpdateCheck: {Current.Update_DisableUpdateCheck.Value}"); } } catch (Exception ex) { - Log.Error($"Failed to load system-wide configuration from: {filePath}", ex); - Current = new ConfigInfo(); + Log.Error($"Failed to load system-wide policies from: {filePath}", ex); + Current = new PolicyInfo(); } } else { - Log.Debug($"No system-wide configuration file found at: {filePath}"); - Current = new ConfigInfo(); + Log.Debug($"No system-wide policy file found at: {filePath}"); + Current = new PolicyInfo(); } } diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs index 6223c83d1d..58737d0659 100644 --- a/Source/NETworkManager.Settings/SettingsManager.cs +++ b/Source/NETworkManager.Settings/SettingsManager.cs @@ -58,14 +58,14 @@ public static class SettingsManager /// /// Gets whether update check should be performed at startup. - /// This respects the system-wide configuration (config.json) which takes precedence over user settings. + /// This respects the system-wide policies (config.json) which take precedence over user settings. /// public static bool ShouldCheckForUpdatesAtStartup { get { - // System-wide config takes precedence - if it explicitly disables updates, honor it - if (ConfigManager.Current?.Update_DisableUpdateCheck == true) + // System-wide policy takes precedence - if it explicitly disables updates, honor it + if (PolicyManager.Current?.Update_DisableUpdateCheck == true) { return false; } @@ -171,8 +171,8 @@ public static void Initialize() /// public static void Load() { - // Load system-wide configuration first (from app directory) - ConfigManager.Load(); + // Load system-wide policies first (from app directory) + PolicyManager.Load(); var filePath = GetSettingsFilePath(); var legacyFilePath = GetLegacySettingsFilePath(); From 506e6bf2386f51235d38e4b7996f1d34721fbb67 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 23:45:38 +0000 Subject: [PATCH 06/20] Add config.json.example to installation and UI for policy-managed settings Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- Source/NETworkManager/NETworkManager.csproj | 4 ++++ .../ViewModels/SettingsUpdateViewModel.cs | 5 +++++ Source/NETworkManager/Views/SettingsUpdateView.xaml | 12 +++++++++++- Source/NETworkManager/config.json.example | 3 +++ 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 Source/NETworkManager/config.json.example diff --git a/Source/NETworkManager/NETworkManager.csproj b/Source/NETworkManager/NETworkManager.csproj index 3dee3d3535..aae5af3977 100644 --- a/Source/NETworkManager/NETworkManager.csproj +++ b/Source/NETworkManager/NETworkManager.csproj @@ -46,6 +46,7 @@ + @@ -57,6 +58,9 @@ PreserveNewest + + PreserveNewest + diff --git a/Source/NETworkManager/ViewModels/SettingsUpdateViewModel.cs b/Source/NETworkManager/ViewModels/SettingsUpdateViewModel.cs index b760064e6f..1e49ec57a4 100644 --- a/Source/NETworkManager/ViewModels/SettingsUpdateViewModel.cs +++ b/Source/NETworkManager/ViewModels/SettingsUpdateViewModel.cs @@ -26,6 +26,11 @@ public bool CheckForUpdatesAtStartup } } + /// + /// Gets whether the "Check for updates at startup" setting is managed by system-wide policy. + /// + public bool IsUpdateCheckManagedByPolicy => PolicyManager.Current?.Update_DisableUpdateCheck.HasValue == true; + private bool _checkForPreReleases; public bool CheckForPreReleases diff --git a/Source/NETworkManager/Views/SettingsUpdateView.xaml b/Source/NETworkManager/Views/SettingsUpdateView.xaml index 1b39084ef0..517fe20578 100644 --- a/Source/NETworkManager/Views/SettingsUpdateView.xaml +++ b/Source/NETworkManager/Views/SettingsUpdateView.xaml @@ -6,13 +6,19 @@ xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:localization="clr-namespace:NETworkManager.Localization.Resources;assembly=NETworkManager.Localization" xmlns:viewModels="clr-namespace:NETworkManager.ViewModels" + xmlns:converters="clr-namespace:NETworkManager.Converters;assembly=NETworkManager.Converters" mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:SettingsUpdateViewModel}"> + + + + + IsOn="{Binding CheckForUpdatesAtStartup}" + IsEnabled="{Binding IsUpdateCheckManagedByPolicy, Converter={StaticResource BooleanReverseConverter}}" /> + diff --git a/Source/NETworkManager/config.json.example b/Source/NETworkManager/config.json.example new file mode 100644 index 0000000000..17f2c6929e --- /dev/null +++ b/Source/NETworkManager/config.json.example @@ -0,0 +1,3 @@ +{ + "Update_DisableUpdateCheck": true +} From 1b12a866e742fdf137e0c775c3802bbaf178a1d6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 23:47:36 +0000 Subject: [PATCH 07/20] Add localization string for policy-managed setting message Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- .../Resources/Strings.Designer.cs | 9 +++++++++ .../NETworkManager.Localization/Resources/Strings.resx | 3 +++ Source/NETworkManager/Views/SettingsUpdateView.xaml | 2 +- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs index b57b12bff7..8fa04498df 100644 --- a/Source/NETworkManager.Localization/Resources/Strings.Designer.cs +++ b/Source/NETworkManager.Localization/Resources/Strings.Designer.cs @@ -9271,6 +9271,15 @@ public static string SettingsHaveBeenReset { } } + /// + /// Sucht eine lokalisierte Zeichenfolge, die This setting is managed by your administrator. ähnelt. + /// + public static string SettingManagedByAdministrator { + get { + return ResourceManager.GetString("SettingManagedByAdministrator", resourceCulture); + } + } + /// /// Sucht eine lokalisierte Zeichenfolge, die Appearance ähnelt. /// diff --git a/Source/NETworkManager.Localization/Resources/Strings.resx b/Source/NETworkManager.Localization/Resources/Strings.resx index 3dd4967eaf..e4f0fef96e 100644 --- a/Source/NETworkManager.Localization/Resources/Strings.resx +++ b/Source/NETworkManager.Localization/Resources/Strings.resx @@ -3960,4 +3960,7 @@ If you click Cancel, the profile file will remain unencrypted. Number of backups that are retained before the oldest one is deleted. + + This setting is managed by your administrator. + \ No newline at end of file diff --git a/Source/NETworkManager/Views/SettingsUpdateView.xaml b/Source/NETworkManager/Views/SettingsUpdateView.xaml index 517fe20578..2b2abfecae 100644 --- a/Source/NETworkManager/Views/SettingsUpdateView.xaml +++ b/Source/NETworkManager/Views/SettingsUpdateView.xaml @@ -30,7 +30,7 @@ - From 9ed5c23f051e8d6495addceab0950c66580fe423 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 7 Feb 2026 23:49:09 +0000 Subject: [PATCH 08/20] Improve accessibility with icon and add documentation to config example Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- .../NETworkManager/Views/SettingsUpdateView.xaml | 16 ++++++++++++---- Source/NETworkManager/config.json.example | 11 +++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Source/NETworkManager/Views/SettingsUpdateView.xaml b/Source/NETworkManager/Views/SettingsUpdateView.xaml index 2b2abfecae..0a12914d09 100644 --- a/Source/NETworkManager/Views/SettingsUpdateView.xaml +++ b/Source/NETworkManager/Views/SettingsUpdateView.xaml @@ -7,6 +7,7 @@ xmlns:localization="clr-namespace:NETworkManager.Localization.Resources;assembly=NETworkManager.Localization" xmlns:viewModels="clr-namespace:NETworkManager.ViewModels" xmlns:converters="clr-namespace:NETworkManager.Converters;assembly=NETworkManager.Converters" + xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" mc:Ignorable="d" d:DataContext="{d:DesignInstance viewModels:SettingsUpdateViewModel}"> @@ -30,10 +31,17 @@ - + + + + + + + + diff --git a/Source/NETworkManager/config.json.example b/Source/NETworkManager/config.json.example index 17f2c6929e..71e705773c 100644 --- a/Source/NETworkManager/config.json.example +++ b/Source/NETworkManager/config.json.example @@ -1,3 +1,14 @@ { "Update_DisableUpdateCheck": true } + +NOTE: This is an example configuration file for system-wide policies. +To use it: +1. Rename this file from config.json.example to config.json +2. Adjust the settings as needed +3. Place it in the same directory as NETworkManager.exe +4. Restart NETworkManager + +Setting "Update_DisableUpdateCheck" to true will disable the automatic update check +at startup for all users on this machine. Users will see a message in the settings +that this option is managed by the administrator. From 509ede8f5d41086535ee4a3f7b8f19cf6a715869 Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Sun, 8 Feb 2026 02:15:05 +0100 Subject: [PATCH 09/20] Chore: Move config file to settings namespace --- .../NETworkManager.Settings.csproj | 3 +++ Source/NETworkManager.Settings/config.json.example | 3 +++ Source/NETworkManager/NETworkManager.csproj | 4 ---- Source/NETworkManager/config.json.example | 14 -------------- 4 files changed, 6 insertions(+), 18 deletions(-) create mode 100644 Source/NETworkManager.Settings/config.json.example delete mode 100644 Source/NETworkManager/config.json.example diff --git a/Source/NETworkManager.Settings/NETworkManager.Settings.csproj b/Source/NETworkManager.Settings/NETworkManager.Settings.csproj index eb78d87f4d..9d4f289bd3 100644 --- a/Source/NETworkManager.Settings/NETworkManager.Settings.csproj +++ b/Source/NETworkManager.Settings/NETworkManager.Settings.csproj @@ -22,6 +22,9 @@ + + PreserveNewest + PreserveNewest Designer diff --git a/Source/NETworkManager.Settings/config.json.example b/Source/NETworkManager.Settings/config.json.example new file mode 100644 index 0000000000..22f7d24062 --- /dev/null +++ b/Source/NETworkManager.Settings/config.json.example @@ -0,0 +1,3 @@ +{ + "Update_DisableUpdateCheck": true +} \ No newline at end of file diff --git a/Source/NETworkManager/NETworkManager.csproj b/Source/NETworkManager/NETworkManager.csproj index aae5af3977..3dee3d3535 100644 --- a/Source/NETworkManager/NETworkManager.csproj +++ b/Source/NETworkManager/NETworkManager.csproj @@ -46,7 +46,6 @@ - @@ -58,9 +57,6 @@ PreserveNewest - - PreserveNewest - diff --git a/Source/NETworkManager/config.json.example b/Source/NETworkManager/config.json.example deleted file mode 100644 index 71e705773c..0000000000 --- a/Source/NETworkManager/config.json.example +++ /dev/null @@ -1,14 +0,0 @@ -{ - "Update_DisableUpdateCheck": true -} - -NOTE: This is an example configuration file for system-wide policies. -To use it: -1. Rename this file from config.json.example to config.json -2. Adjust the settings as needed -3. Place it in the same directory as NETworkManager.exe -4. Restart NETworkManager - -Setting "Update_DisableUpdateCheck" to true will disable the automatic update check -at startup for all users on this machine. Users will see a message in the settings -that this option is managed by the administrator. From 247c4c532f11bdc4237642ff7124417bca53a318 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 01:17:49 +0000 Subject: [PATCH 10/20] Rename policy property to Update_CheckForUpdatesAtStartup and allow enabling/disabling Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- Documentation/config/README.md | 26 ++++++++++++++----- Documentation/config/config.json.example | 2 +- Source/NETworkManager.Settings/PolicyInfo.cs | 9 ++++--- .../NETworkManager.Settings/PolicyManager.cs | 4 +-- .../SettingsManager.cs | 6 ++--- .../config.json.example | 2 +- .../ViewModels/SettingsUpdateViewModel.cs | 6 +++-- 7 files changed, 35 insertions(+), 20 deletions(-) diff --git a/Documentation/config/README.md b/Documentation/config/README.md index 10d4d75fc7..522f3c86eb 100644 --- a/Documentation/config/README.md +++ b/Documentation/config/README.md @@ -11,21 +11,32 @@ This directory contains an example `config.json` file that can be placed in the ## Configuration Options -### Update_DisableUpdateCheck +### Update_CheckForUpdatesAtStartup -When set to `true`, disables the automatic update check at startup for all users. +Controls whether the application checks for updates at startup for all users. This overrides the user's personal setting. -**Example:** +- Set to `true` to enable automatic update checks at startup +- Set to `false` to disable automatic update checks at startup +- Omit the property to allow users to control this setting themselves + +**Example (disable updates):** +```json +{ + "Update_CheckForUpdatesAtStartup": false +} +``` + +**Example (enable updates):** ```json { - "Update_DisableUpdateCheck": true + "Update_CheckForUpdatesAtStartup": true } ``` This is useful for enterprise deployments where you want to: -- Control software updates centrally -- Prevent users from being prompted about updates -- Disable update checks on multiple machines without user intervention +- Control software update checking behavior centrally +- Ensure consistent update check behavior across all users +- Either enforce update checks or prevent them system-wide ## File Location @@ -36,6 +47,7 @@ The `config.json` file should be placed in: ## Notes - System-wide configuration takes precedence over user settings +- Users will see a message in the UI indicating when a setting is managed by the administrator - If the file doesn't exist or contains invalid JSON, it will be ignored and default user settings will apply - Changes to `config.json` require restarting the application to take effect - The file is optional - if not present, user settings will be used as normal diff --git a/Documentation/config/config.json.example b/Documentation/config/config.json.example index 17f2c6929e..50de761ec7 100644 --- a/Documentation/config/config.json.example +++ b/Documentation/config/config.json.example @@ -1,3 +1,3 @@ { - "Update_DisableUpdateCheck": true + "Update_CheckForUpdatesAtStartup": false } diff --git a/Source/NETworkManager.Settings/PolicyInfo.cs b/Source/NETworkManager.Settings/PolicyInfo.cs index 1e16581c8a..56b02c3787 100644 --- a/Source/NETworkManager.Settings/PolicyInfo.cs +++ b/Source/NETworkManager.Settings/PolicyInfo.cs @@ -9,9 +9,10 @@ namespace NETworkManager.Settings; public class PolicyInfo { /// - /// Disable update check for all users. When set to true, the application will not check for updates at startup. - /// This overrides the user's "Update_CheckForUpdatesAtStartup" setting. + /// Controls the "Check for updates at startup" setting for all users. + /// When set, this value overrides the user's "Update_CheckForUpdatesAtStartup" setting. + /// Set to true to enable update checks, false to disable them. /// - [JsonPropertyName("Update_DisableUpdateCheck")] - public bool? Update_DisableUpdateCheck { get; set; } + [JsonPropertyName("Update_CheckForUpdatesAtStartup")] + public bool? Update_CheckForUpdatesAtStartup { get; set; } } diff --git a/Source/NETworkManager.Settings/PolicyManager.cs b/Source/NETworkManager.Settings/PolicyManager.cs index 966c0a3905..180489a7d0 100644 --- a/Source/NETworkManager.Settings/PolicyManager.cs +++ b/Source/NETworkManager.Settings/PolicyManager.cs @@ -73,9 +73,9 @@ public static void Load() Log.Info("System-wide policies loaded successfully."); // Log enabled settings - if (Current.Update_DisableUpdateCheck.HasValue) + if (Current.Update_CheckForUpdatesAtStartup.HasValue) { - Log.Info($"System-wide policy - Update_DisableUpdateCheck: {Current.Update_DisableUpdateCheck.Value}"); + Log.Info($"System-wide policy - Update_CheckForUpdatesAtStartup: {Current.Update_CheckForUpdatesAtStartup.Value}"); } } catch (Exception ex) diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs index 58737d0659..a1a9cd491b 100644 --- a/Source/NETworkManager.Settings/SettingsManager.cs +++ b/Source/NETworkManager.Settings/SettingsManager.cs @@ -64,10 +64,10 @@ public static bool ShouldCheckForUpdatesAtStartup { get { - // System-wide policy takes precedence - if it explicitly disables updates, honor it - if (PolicyManager.Current?.Update_DisableUpdateCheck == true) + // System-wide policy takes precedence - if set, use the policy value + if (PolicyManager.Current?.Update_CheckForUpdatesAtStartup.HasValue == true) { - return false; + return PolicyManager.Current.Update_CheckForUpdatesAtStartup.Value; } // Otherwise, use the user's setting diff --git a/Source/NETworkManager.Settings/config.json.example b/Source/NETworkManager.Settings/config.json.example index 22f7d24062..8ca2bf05b3 100644 --- a/Source/NETworkManager.Settings/config.json.example +++ b/Source/NETworkManager.Settings/config.json.example @@ -1,3 +1,3 @@ { - "Update_DisableUpdateCheck": true + "Update_CheckForUpdatesAtStartup": false } \ No newline at end of file diff --git a/Source/NETworkManager/ViewModels/SettingsUpdateViewModel.cs b/Source/NETworkManager/ViewModels/SettingsUpdateViewModel.cs index 1e49ec57a4..8530469e7a 100644 --- a/Source/NETworkManager/ViewModels/SettingsUpdateViewModel.cs +++ b/Source/NETworkManager/ViewModels/SettingsUpdateViewModel.cs @@ -29,7 +29,7 @@ public bool CheckForUpdatesAtStartup /// /// Gets whether the "Check for updates at startup" setting is managed by system-wide policy. /// - public bool IsUpdateCheckManagedByPolicy => PolicyManager.Current?.Update_DisableUpdateCheck.HasValue == true; + public bool IsUpdateCheckManagedByPolicy => PolicyManager.Current?.Update_CheckForUpdatesAtStartup.HasValue == true; private bool _checkForPreReleases; @@ -83,7 +83,9 @@ public SettingsUpdateViewModel() private void LoadSettings() { - CheckForUpdatesAtStartup = SettingsManager.Current.Update_CheckForUpdatesAtStartup; + // If policy is set, show the policy value; otherwise show the user's setting + CheckForUpdatesAtStartup = PolicyManager.Current?.Update_CheckForUpdatesAtStartup + ?? SettingsManager.Current.Update_CheckForUpdatesAtStartup; CheckForPreReleases = SettingsManager.Current.Update_CheckForPreReleases; EnableExperimentalFeatures = SettingsManager.Current.Experimental_EnableExperimentalFeatures; } From 5180ca0542454c468e7606abe4877da2c64c80e8 Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Sun, 8 Feb 2026 02:47:34 +0100 Subject: [PATCH 11/20] Chore: Minor color adjustments --- Source/NETworkManager.Settings/PolicyInfo.cs | 7 +------ Source/NETworkManager.Settings/PolicyManager.cs | 11 ++++------- Source/NETworkManager/Views/SettingsUpdateView.xaml | 6 +++--- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/Source/NETworkManager.Settings/PolicyInfo.cs b/Source/NETworkManager.Settings/PolicyInfo.cs index 56b02c3787..a337c2e32c 100644 --- a/Source/NETworkManager.Settings/PolicyInfo.cs +++ b/Source/NETworkManager.Settings/PolicyInfo.cs @@ -7,12 +7,7 @@ namespace NETworkManager.Settings; /// This configuration is loaded from a config.json file in the application directory. /// public class PolicyInfo -{ - /// - /// Controls the "Check for updates at startup" setting for all users. - /// When set, this value overrides the user's "Update_CheckForUpdatesAtStartup" setting. - /// Set to true to enable update checks, false to disable them. - /// +{ [JsonPropertyName("Update_CheckForUpdatesAtStartup")] public bool? Update_CheckForUpdatesAtStartup { get; set; } } diff --git a/Source/NETworkManager.Settings/PolicyManager.cs b/Source/NETworkManager.Settings/PolicyManager.cs index 180489a7d0..2f50940c88 100644 --- a/Source/NETworkManager.Settings/PolicyManager.cs +++ b/Source/NETworkManager.Settings/PolicyManager.cs @@ -66,17 +66,14 @@ public static void Load() try { Log.Info($"Loading system-wide policies from: {filePath}"); - + var jsonString = File.ReadAllText(filePath); Current = JsonSerializer.Deserialize(jsonString, JsonOptions); - + Log.Info("System-wide policies loaded successfully."); - + // Log enabled settings - if (Current.Update_CheckForUpdatesAtStartup.HasValue) - { - Log.Info($"System-wide policy - Update_CheckForUpdatesAtStartup: {Current.Update_CheckForUpdatesAtStartup.Value}"); - } + Log.Info($"System-wide policy - Update_CheckForUpdatesAtStartup: {Current.Update_CheckForUpdatesAtStartup?.ToString() ?? "Not set"}"); } catch (Exception ex) { diff --git a/Source/NETworkManager/Views/SettingsUpdateView.xaml b/Source/NETworkManager/Views/SettingsUpdateView.xaml index 0a12914d09..5f6530f909 100644 --- a/Source/NETworkManager/Views/SettingsUpdateView.xaml +++ b/Source/NETworkManager/Views/SettingsUpdateView.xaml @@ -33,13 +33,13 @@ - + - Date: Sun, 8 Feb 2026 01:53:18 +0000 Subject: [PATCH 12/20] Use direct pattern for policy check and remove helper property Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- .../SettingsManager.cs | 19 ------------------- Source/NETworkManager/MainWindow.xaml.cs | 3 ++- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/Source/NETworkManager.Settings/SettingsManager.cs b/Source/NETworkManager.Settings/SettingsManager.cs index a1a9cd491b..f1b7247265 100644 --- a/Source/NETworkManager.Settings/SettingsManager.cs +++ b/Source/NETworkManager.Settings/SettingsManager.cs @@ -56,25 +56,6 @@ public static class SettingsManager /// public static bool HotKeysChanged { get; set; } - /// - /// Gets whether update check should be performed at startup. - /// This respects the system-wide policies (config.json) which take precedence over user settings. - /// - public static bool ShouldCheckForUpdatesAtStartup - { - get - { - // System-wide policy takes precedence - if set, use the policy value - if (PolicyManager.Current?.Update_CheckForUpdatesAtStartup.HasValue == true) - { - return PolicyManager.Current.Update_CheckForUpdatesAtStartup.Value; - } - - // Otherwise, use the user's setting - return Current.Update_CheckForUpdatesAtStartup; - } - } - /// /// JSON serializer options for consistent serialization/deserialization. /// diff --git a/Source/NETworkManager/MainWindow.xaml.cs b/Source/NETworkManager/MainWindow.xaml.cs index ede6f0007c..3768c69687 100644 --- a/Source/NETworkManager/MainWindow.xaml.cs +++ b/Source/NETworkManager/MainWindow.xaml.cs @@ -561,7 +561,8 @@ private void Load() NetworkChange.NetworkAddressChanged += (_, _) => OnNetworkHasChanged(); // Search for updates... - if (SettingsManager.ShouldCheckForUpdatesAtStartup) + if (PolicyManager.Current?.Update_CheckForUpdatesAtStartup + ?? SettingsManager.Current.Update_CheckForUpdatesAtStartup) CheckForUpdates(); } From a83ee1d223f30fa43a358d1cf0b95e4b028d3ebb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 02:03:50 +0000 Subject: [PATCH 13/20] Add Docusaurus documentation for system-wide policies and remove old docs Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- Documentation/config/README.md | 53 --------- Documentation/config/config.json.example | 3 - Website/docs/changelog/next-release.md | 1 + Website/docs/settings/update.md | 6 + Website/docs/system-wide-policies.md | 141 +++++++++++++++++++++++ 5 files changed, 148 insertions(+), 56 deletions(-) delete mode 100644 Documentation/config/README.md delete mode 100644 Documentation/config/config.json.example create mode 100644 Website/docs/system-wide-policies.md diff --git a/Documentation/config/README.md b/Documentation/config/README.md deleted file mode 100644 index 522f3c86eb..0000000000 --- a/Documentation/config/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# System-Wide Configuration - -This directory contains an example `config.json` file that can be placed in the application installation directory to override user settings for all users on a machine. - -## Usage - -1. Copy the example configuration file to the NETworkManager installation directory (where `NETworkManager.exe` is located) -2. Rename `config.json.example` to `config.json` -3. Edit the settings as needed -4. Restart NETworkManager - -## Configuration Options - -### Update_CheckForUpdatesAtStartup - -Controls whether the application checks for updates at startup for all users. This overrides the user's personal setting. - -- Set to `true` to enable automatic update checks at startup -- Set to `false` to disable automatic update checks at startup -- Omit the property to allow users to control this setting themselves - -**Example (disable updates):** -```json -{ - "Update_CheckForUpdatesAtStartup": false -} -``` - -**Example (enable updates):** -```json -{ - "Update_CheckForUpdatesAtStartup": true -} -``` - -This is useful for enterprise deployments where you want to: -- Control software update checking behavior centrally -- Ensure consistent update check behavior across all users -- Either enforce update checks or prevent them system-wide - -## File Location - -The `config.json` file should be placed in: -- **Installed version**: `C:\Program Files\NETworkManager\` (or your custom installation path) -- **Portable version**: Same directory as `NETworkManager.exe` - -## Notes - -- System-wide configuration takes precedence over user settings -- Users will see a message in the UI indicating when a setting is managed by the administrator -- If the file doesn't exist or contains invalid JSON, it will be ignored and default user settings will apply -- Changes to `config.json` require restarting the application to take effect -- The file is optional - if not present, user settings will be used as normal diff --git a/Documentation/config/config.json.example b/Documentation/config/config.json.example deleted file mode 100644 index 50de761ec7..0000000000 --- a/Documentation/config/config.json.example +++ /dev/null @@ -1,3 +0,0 @@ -{ - "Update_CheckForUpdatesAtStartup": false -} diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md index c477c766ae..216393d5ac 100644 --- a/Website/docs/changelog/next-release.md +++ b/Website/docs/changelog/next-release.md @@ -45,6 +45,7 @@ Release date: **xx.xx.2025** - New language Ukrainian (`uk-UA`) has been added. Thanks to [@vadickkt](https://github.com/vadickkt) [#3240](https://github.com/BornToBeRoot/NETworkManager/pull/3240) - Migrated all dialogs to child windows for improved usability and accessibility. [#3271](https://github.com/BornToBeRoot/NETworkManager/pull/3271) +- System-wide policies can now be configured via a `config.json` file in the application directory to control settings for all users. Currently supports controlling the "Check for updates at startup" setting. This is useful for enterprise deployments where administrators need centralized control over update behavior. See [System-Wide Policies](../system-wide-policies.md) documentation for more information. [#PRLINK](https://github.com/BornToBeRoot/NETworkManager/pull/PRLINK) **DNS Lookup** diff --git a/Website/docs/settings/update.md b/Website/docs/settings/update.md index 565a74fefe..36a8e66ce1 100644 --- a/Website/docs/settings/update.md +++ b/Website/docs/settings/update.md @@ -12,6 +12,12 @@ Check for new program versions on GitHub when the application is launched. **Default:** `Enabled` +:::info System-Wide Policy + +This setting can be controlled by administrators using a system-wide policy. See [System-Wide Policies](../system-wide-policies.md) for more information on how to configure the `Update_CheckForUpdatesAtStartup` policy. + +::: + :::note The URL `https://api.github.com/` must be reachable to check for updates. diff --git a/Website/docs/system-wide-policies.md b/Website/docs/system-wide-policies.md new file mode 100644 index 0000000000..7f1db70184 --- /dev/null +++ b/Website/docs/system-wide-policies.md @@ -0,0 +1,141 @@ +--- +sidebar_position: 6 +--- + +# System-Wide Policies + +System-wide policies allow administrators to enforce specific settings for all users on a machine. These policies override user-specific settings and provide centralized control over application behavior in enterprise environments. + +## Overview + +Policies are defined in a `config.json` file placed in the application installation directory (the same folder as `NETworkManager.exe`). When this file exists, the application loads the policies at startup and applies them with precedence over user settings. + +Users will see a visual indicator in the Settings UI when a setting is controlled by a system-wide policy, showing them the administrator-enforced value and preventing them from changing it. + +![System-wide policy indicator](./img/system-wide-policy-indicator.png) + +## Configuration File + +The `config.json` file uses a simple JSON structure to define policy values. An example file (`config.json.example`) is included in the application installation directory for reference. + +**File Location:** +- **Installed version**: `C:\Program Files\NETworkManager\config.json` (or your custom installation path) +- **Portable version**: Same directory as `NETworkManager.exe` + +**File Format:** + +```json +{ + "Update_CheckForUpdatesAtStartup": false +} +``` + +:::note + +- The file must be named exactly `config.json` (case-sensitive) +- The file must contain valid JSON syntax +- Changes to the file require restarting the application to take effect +- If the file doesn't exist or contains invalid JSON, it will be ignored and user settings will apply + +::: + +## Available Policies + +### Update_CheckForUpdatesAtStartup + +Controls whether the application checks for updates at startup for all users. + +**Type:** `Boolean` (true/false) + +**Default:** Not set (users control this setting) + +**Values:** +- `true` - Force enable automatic update checks at startup for all users +- `false` - Force disable automatic update checks at startup for all users +- Omit the property - Allow users to control this setting themselves + +**Example (disable updates):** + +```json +{ + "Update_CheckForUpdatesAtStartup": false +} +``` + +**Example (enable updates):** + +```json +{ + "Update_CheckForUpdatesAtStartup": true +} +``` + +:::tip Use Case + +This is particularly useful for enterprise deployments where you want to: +- Ensure consistent update check behavior across all users +- Prevent users from being prompted about updates when you manage updates centrally +- Enforce update checks to ensure users are notified of important security updates + +::: + +## User Experience + +When a setting is controlled by a system-wide policy: + +1. **Settings UI**: The toggle/control for the setting is disabled +2. **Visual Indicator**: An orange shield icon appears next to the setting +3. **Administrator Message**: The text "This setting is managed by your administrator" is displayed +4. **Value Display**: The UI shows the value set by the administrator (enabled or disabled) + +This provides clear feedback to users about which settings are under administrative control and what values are being enforced. + +## Deployment + +For enterprise deployments: + +1. **Create the configuration file**: + - Use the `config.json.example` as a template + - Rename it to `config.json` + - Set your desired policy values + +2. **Deploy to installation directory**: + - Place the `config.json` file in the same directory as `NETworkManager.exe` + - For MSI installations, this is typically `C:\Program Files\NETworkManager\` + - For portable installations, place it next to the executable + +3. **Deploy methods**: + - Group Policy (copy file to installation directory) + - Configuration management tools (Ansible, SCCM, etc.) + - MSI deployment scripts + - Manual deployment for small-scale rollouts + +4. **Verification**: + - Launch the application + - Navigate to Settings > Update + - Verify the shield icon and administrator message appear + - Confirm the toggle reflects the policy value and is disabled + +:::warning + +Ensure the `config.json` file has appropriate permissions so that regular users cannot modify it. On standard installations in `Program Files`, this is automatically enforced by Windows file permissions. + +::: + +## Troubleshooting + +**Policy not being applied:** +- Verify the file is named exactly `config.json` (not `config.json.txt`) +- Check that the JSON syntax is valid (use a JSON validator) +- Confirm the file is in the correct directory (same as `NETworkManager.exe`) +- Restart the application after creating or modifying the file +- Check the application logs for any error messages related to policy loading + +**Policy values not showing in UI:** +- Ensure the property name matches exactly: `Update_CheckForUpdatesAtStartup` +- Verify the value is a boolean (`true` or `false`), not a string (`"true"` or `"false"`) +- Check that there are no syntax errors in the JSON file + +## Future Policies + +Additional policy options will be added in future releases to provide more granular control over application behavior. If you have specific requirements for system-wide policies in your organization, please submit a feature request via the [GitHub issue tracker](https://github.com/BornToBeRoot/NETworkManager/issues/new/choose). From 65134b07f88b462ab0bc9d058b7b48f92f83618d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 02:04:39 +0000 Subject: [PATCH 14/20] Fix changelog PR number placeholder Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- Website/docs/changelog/next-release.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md index 216393d5ac..5a97e289bd 100644 --- a/Website/docs/changelog/next-release.md +++ b/Website/docs/changelog/next-release.md @@ -45,7 +45,7 @@ Release date: **xx.xx.2025** - New language Ukrainian (`uk-UA`) has been added. Thanks to [@vadickkt](https://github.com/vadickkt) [#3240](https://github.com/BornToBeRoot/NETworkManager/pull/3240) - Migrated all dialogs to child windows for improved usability and accessibility. [#3271](https://github.com/BornToBeRoot/NETworkManager/pull/3271) -- System-wide policies can now be configured via a `config.json` file in the application directory to control settings for all users. Currently supports controlling the "Check for updates at startup" setting. This is useful for enterprise deployments where administrators need centralized control over update behavior. See [System-Wide Policies](../system-wide-policies.md) documentation for more information. [#PRLINK](https://github.com/BornToBeRoot/NETworkManager/pull/PRLINK) +- System-wide policies can now be configured via a `config.json` file in the application directory to control settings for all users. Currently supports controlling the "Check for updates at startup" setting. This is useful for enterprise deployments where administrators need centralized control over update behavior. See [System-Wide Policies](../system-wide-policies.md) documentation for more information. [#TODO_PR_NUMBER](https://github.com/BornToBeRoot/NETworkManager/pull/TODO_PR_NUMBER) **DNS Lookup** From dbe56fe2bd4856b6644811e82ae99bad5d87f1c3 Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Sun, 8 Feb 2026 03:18:15 +0100 Subject: [PATCH 15/20] Update system-wide-policies.md --- Website/docs/system-wide-policies.md | 55 +++++++--------------------- 1 file changed, 14 insertions(+), 41 deletions(-) diff --git a/Website/docs/system-wide-policies.md b/Website/docs/system-wide-policies.md index 7f1db70184..c9b7a60df9 100644 --- a/Website/docs/system-wide-policies.md +++ b/Website/docs/system-wide-policies.md @@ -24,6 +24,16 @@ The `config.json` file uses a simple JSON structure to define policy values. An **File Format:** +```json +{ + "Policy_Name1": true, + "Policy_Name2": "ExampleValue" +} +``` + + +**Example:** + ```json { "Update_CheckForUpdatesAtStartup": false @@ -54,42 +64,6 @@ Controls whether the application checks for updates at startup for all users. - `false` - Force disable automatic update checks at startup for all users - Omit the property - Allow users to control this setting themselves -**Example (disable updates):** - -```json -{ - "Update_CheckForUpdatesAtStartup": false -} -``` - -**Example (enable updates):** - -```json -{ - "Update_CheckForUpdatesAtStartup": true -} -``` - -:::tip Use Case - -This is particularly useful for enterprise deployments where you want to: -- Ensure consistent update check behavior across all users -- Prevent users from being prompted about updates when you manage updates centrally -- Enforce update checks to ensure users are notified of important security updates - -::: - -## User Experience - -When a setting is controlled by a system-wide policy: - -1. **Settings UI**: The toggle/control for the setting is disabled -2. **Visual Indicator**: An orange shield icon appears next to the setting -3. **Administrator Message**: The text "This setting is managed by your administrator" is displayed -4. **Value Display**: The UI shows the value set by the administrator (enabled or disabled) - -This provides clear feedback to users about which settings are under administrative control and what values are being enforced. - ## Deployment For enterprise deployments: @@ -97,7 +71,7 @@ For enterprise deployments: 1. **Create the configuration file**: - Use the `config.json.example` as a template - Rename it to `config.json` - - Set your desired policy values + - Set your desired policy values (you find them in the corresponding setting's documentation) 2. **Deploy to installation directory**: - Place the `config.json` file in the same directory as `NETworkManager.exe` @@ -106,13 +80,12 @@ For enterprise deployments: 3. **Deploy methods**: - Group Policy (copy file to installation directory) - - Configuration management tools (Ansible, SCCM, etc.) - - MSI deployment scripts - - Manual deployment for small-scale rollouts + - Configuration management tools (SCCM, Intune, etc.) + - Scripts/Deployment tools (PowerShell, PSAppDeployToolkit, etc.) 4. **Verification**: - Launch the application - - Navigate to Settings > Update + - Navigate to a setting that is controlled by the policy (e.g., "Check for updates at startup") - Verify the shield icon and administrator message appear - Confirm the toggle reflects the policy value and is disabled From 3100ee9c62ba5fa5662111d047bc915aca59c877 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 02:21:48 +0000 Subject: [PATCH 16/20] Move policy property details to settings/update.md to avoid duplication Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- Website/docs/settings/update.md | 17 ++++++++++++++++- Website/docs/system-wide-policies.md | 17 +---------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Website/docs/settings/update.md b/Website/docs/settings/update.md index 36a8e66ce1..9c006a108b 100644 --- a/Website/docs/settings/update.md +++ b/Website/docs/settings/update.md @@ -14,7 +14,22 @@ Check for new program versions on GitHub when the application is launched. :::info System-Wide Policy -This setting can be controlled by administrators using a system-wide policy. See [System-Wide Policies](../system-wide-policies.md) for more information on how to configure the `Update_CheckForUpdatesAtStartup` policy. +This setting can be controlled by administrators using a system-wide policy. See [System-Wide Policies](../system-wide-policies.md) for more information. + +**Policy Property:** `Update_CheckForUpdatesAtStartup` + +**Values:** +- `true` - Force enable automatic update checks at startup for all users +- `false` - Force disable automatic update checks at startup for all users +- Omit the property - Allow users to control this setting themselves + +**Example:** + +```json +{ + "Update_CheckForUpdatesAtStartup": false +} +``` ::: diff --git a/Website/docs/system-wide-policies.md b/Website/docs/system-wide-policies.md index c9b7a60df9..dece2ba999 100644 --- a/Website/docs/system-wide-policies.md +++ b/Website/docs/system-wide-policies.md @@ -49,21 +49,6 @@ The `config.json` file uses a simple JSON structure to define policy values. An ::: -## Available Policies - -### Update_CheckForUpdatesAtStartup - -Controls whether the application checks for updates at startup for all users. - -**Type:** `Boolean` (true/false) - -**Default:** Not set (users control this setting) - -**Values:** -- `true` - Force enable automatic update checks at startup for all users -- `false` - Force disable automatic update checks at startup for all users -- Omit the property - Allow users to control this setting themselves - ## Deployment For enterprise deployments: @@ -105,7 +90,7 @@ Ensure the `config.json` file has appropriate permissions so that regular users - Check the application logs for any error messages related to policy loading **Policy values not showing in UI:** -- Ensure the property name matches exactly: `Update_CheckForUpdatesAtStartup` +- Ensure the property name matches exactly (see the corresponding setting's documentation for the property name) - Verify the value is a boolean (`true` or `false`), not a string (`"true"` or `"false"`) - Check that there are no syntax errors in the JSON file From c5840c6db656d30eaea0d7cdb9d3e0b7f0fc05c5 Mon Sep 17 00:00:00 2001 From: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> Date: Sun, 8 Feb 2026 03:31:25 +0100 Subject: [PATCH 17/20] Feature: System wide policy --- Website/docs/changelog/next-release.md | 2 +- .../docs/img/system-wide-policy-indicator.png | Bin 0 -> 54792 bytes Website/docs/system-wide-policies.md | 17 ++++++++++------- 3 files changed, 11 insertions(+), 8 deletions(-) create mode 100644 Website/docs/img/system-wide-policy-indicator.png diff --git a/Website/docs/changelog/next-release.md b/Website/docs/changelog/next-release.md index 5a97e289bd..6fdd01caf2 100644 --- a/Website/docs/changelog/next-release.md +++ b/Website/docs/changelog/next-release.md @@ -45,7 +45,7 @@ Release date: **xx.xx.2025** - New language Ukrainian (`uk-UA`) has been added. Thanks to [@vadickkt](https://github.com/vadickkt) [#3240](https://github.com/BornToBeRoot/NETworkManager/pull/3240) - Migrated all dialogs to child windows for improved usability and accessibility. [#3271](https://github.com/BornToBeRoot/NETworkManager/pull/3271) -- System-wide policies can now be configured via a `config.json` file in the application directory to control settings for all users. Currently supports controlling the "Check for updates at startup" setting. This is useful for enterprise deployments where administrators need centralized control over update behavior. See [System-Wide Policies](../system-wide-policies.md) documentation for more information. [#TODO_PR_NUMBER](https://github.com/BornToBeRoot/NETworkManager/pull/TODO_PR_NUMBER) +- System-wide policies can now be configured via a `config.json` file in the application directory to control settings for all users. Currently supports controlling the "Check for updates at startup" setting. This is useful for enterprise deployments where administrators need centralized control over update behavior. See [System-Wide Policies](../system-wide-policies.md) documentation for more information. [#3313](https://github.com/BornToBeRoot/NETworkManager/pull/3313) **DNS Lookup** diff --git a/Website/docs/img/system-wide-policy-indicator.png b/Website/docs/img/system-wide-policy-indicator.png new file mode 100644 index 0000000000000000000000000000000000000000..36da34f9202574a160192a64941d8c344fda5be5 GIT binary patch literal 54792 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 literal 0 HcmV?d00001 diff --git a/Website/docs/system-wide-policies.md b/Website/docs/system-wide-policies.md index dece2ba999..d8ef644453 100644 --- a/Website/docs/system-wide-policies.md +++ b/Website/docs/system-wide-policies.md @@ -40,9 +40,11 @@ The `config.json` file uses a simple JSON structure to define policy values. An } ``` +Property names generally follow the pattern `Section_SettingName` (see each setting's documentation). Ensure values use the correct JSON type (boolean, string, number, etc.). + :::note -- The file must be named exactly `config.json` (case-sensitive) +- The file must be named exactly `config.json` - The file must contain valid JSON syntax - Changes to the file require restarting the application to take effect - If the file doesn't exist or contains invalid JSON, it will be ignored and user settings will apply @@ -64,15 +66,16 @@ For enterprise deployments: - For portable installations, place it next to the executable 3. **Deploy methods**: - - Group Policy (copy file to installation directory) - - Configuration management tools (SCCM, Intune, etc.) - - Scripts/Deployment tools (PowerShell, PSAppDeployToolkit, etc.) + - Group Policy — copy the `config.json` file to the installation directory (use Group Policy preferences or a startup script) + - Configuration management tools — SCCM/ConfigMgr, Microsoft Intune, Ansible, etc. + - Scripts and deployment toolkits — PowerShell scripts, PSAppDeployToolkit (recommended for scripted MSI/App deployments) + - Manual deployment — hand-copy for small-scale rollouts 4. **Verification**: - Launch the application - - Navigate to a setting that is controlled by the policy (e.g., "Check for updates at startup") - - Verify the shield icon and administrator message appear - - Confirm the toggle reflects the policy value and is disabled + - Navigate to Settings > Update (e.g., "Check for updates at startup") + - Verify the shield icon and the administrator message appear and that the control is disabled + - Confirm the displayed value matches the policy :::warning From f02c7be6743c4506c5bf480420b6738706497394 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 02:35:53 +0000 Subject: [PATCH 18/20] Fix Docusaurus build error with react-image-gallery CSS import Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- Website/src/css/custom.css | 3 +++ Website/src/pages/index.js | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Website/src/css/custom.css b/Website/src/css/custom.css index f55bc3482a..233f8814d9 100644 --- a/Website/src/css/custom.css +++ b/Website/src/css/custom.css @@ -4,6 +4,9 @@ * work well for content-centric websites. */ +/* Import react-image-gallery styles */ +@import 'react-image-gallery/styles/css/image-gallery.css'; + /* You can override the default Infima variables here. */ :root { --ifm-color-primary: #00d4aa; diff --git a/Website/src/pages/index.js b/Website/src/pages/index.js index 60778377f6..870d02fc96 100644 --- a/Website/src/pages/index.js +++ b/Website/src/pages/index.js @@ -5,7 +5,6 @@ import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import Layout from "@theme/Layout"; import HomepageFeatures from "@site/src/components/HomepageFeatures"; import ImageGallery from "react-image-gallery"; -import "react-image-gallery/styles/css/image-gallery.css"; import ImageGalleryDashboard from "@site/docs/img/dashboard.png"; import ImageGalleryNetworkInterfaceInformation from "@site/docs/img/network-interface--information.png"; From bafdcf31fb8feea98c183650090d92e40b2365c5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 02:39:26 +0000 Subject: [PATCH 19/20] Update browserslist database to latest version Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- Website/yarn.lock | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Website/yarn.lock b/Website/yarn.lock index 57722cbb93..dd9a2f7d44 100644 --- a/Website/yarn.lock +++ b/Website/yarn.lock @@ -3238,12 +3238,7 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001718: - version "1.0.30001721" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz#36b90cd96901f8c98dd6698bf5c8af7d4c6872d7" - integrity sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ== - -caniuse-lite@^1.0.30001759: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001702, caniuse-lite@^1.0.30001718, caniuse-lite@^1.0.30001759: version "1.0.30001769" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz#1ad91594fad7dc233777c2781879ab5409f7d9c2" integrity sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg== From 6bd67c09ded21bf1fffc45659745807bc981280d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 8 Feb 2026 02:43:11 +0000 Subject: [PATCH 20/20] Add null-safety checks for PolicyManager deserialization Co-authored-by: BornToBeRoot <16019165+BornToBeRoot@users.noreply.github.com> --- .../NETworkManager.Settings/PolicyManager.cs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Source/NETworkManager.Settings/PolicyManager.cs b/Source/NETworkManager.Settings/PolicyManager.cs index 2f50940c88..f97aa95376 100644 --- a/Source/NETworkManager.Settings/PolicyManager.cs +++ b/Source/NETworkManager.Settings/PolicyManager.cs @@ -68,12 +68,22 @@ public static void Load() Log.Info($"Loading system-wide policies from: {filePath}"); var jsonString = File.ReadAllText(filePath); - Current = JsonSerializer.Deserialize(jsonString, JsonOptions); + + // Treat empty or JSON "null" as "no policies" instead of crashing + if (string.IsNullOrWhiteSpace(jsonString)) + { + Current = new PolicyInfo(); + Log.Info("Config file is empty, no system-wide policies loaded."); + } + else + { + Current = JsonSerializer.Deserialize(jsonString, JsonOptions) ?? new PolicyInfo(); + + Log.Info("System-wide policies loaded successfully."); - Log.Info("System-wide policies loaded successfully."); - - // Log enabled settings - Log.Info($"System-wide policy - Update_CheckForUpdatesAtStartup: {Current.Update_CheckForUpdatesAtStartup?.ToString() ?? "Not set"}"); + // Log enabled settings + Log.Info($"System-wide policy - Update_CheckForUpdatesAtStartup: {Current.Update_CheckForUpdatesAtStartup?.ToString() ?? "Not set"}"); + } } catch (Exception ex) {