-
Notifications
You must be signed in to change notification settings - Fork 797
Add SettingsFolderLocation policy for centralized settings path control #3324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
mergify
merged 27 commits into
main
from
copilot/add-policy-to-override-settings-folder-location
Feb 18, 2026
+1,000
−168
Merged
Changes from all commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
24ad9e1
Initial plan
Copilot 1225587
Add policy to override SettingsFolder Location
Copilot bf0c78e
Add validation for policy-provided SettingsFolderLocation
Copilot 65e9732
Improve exception handling and documentation structure
Copilot 114f86c
Add SecurityException handling and fix documentation formatting
Copilot 92530c7
Fix using statement and clarify path format documentation
Copilot 41633bf
Use consistent example path in documentation
Copilot a58b7e0
Address review feedback: validate directory, update docs, add admin i…
Copilot 3264291
Update system-wide policies documentation
BornToBeRoot 712a05d
Update SettingsSettingsView.xaml
BornToBeRoot 6cdf525
Chore: Handle user settings location
BornToBeRoot 26410ca
Feature: UI change settings
BornToBeRoot 4b3010b
Feature: UI
BornToBeRoot 7ed0538
Feature: UI
BornToBeRoot 360ad30
Feature: Env var for folder
BornToBeRoot fedc544
Docs: Add some docs
BornToBeRoot 47de748
Merge branch 'main' into copilot/add-policy-to-override-settings-fold…
BornToBeRoot 8d83d18
Chore: Update packages
BornToBeRoot fc9b9ee
Merge branch 'copilot/add-policy-to-override-settings-folder-location…
BornToBeRoot 257efe9
Update Source/NETworkManager.Settings/SettingsManager.cs
BornToBeRoot c7c743a
Update Source/NETworkManager/ViewModels/SettingsSettingsViewModel.cs
BornToBeRoot 2bcae6e
Update Source/NETworkManager.Settings/SettingsManager.cs
BornToBeRoot ae6fe1f
Update Source/NETworkManager.Settings/LocalSettingsManager.cs
BornToBeRoot 3dae961
Fix: Handle LocalSettingsManager.Load() gracefully
BornToBeRoot 85952da
Fix exception handling for LocalSettingsManager and path validation
Copilot 66a6ca7
Fix: Minor improvements
BornToBeRoot e344ae6
Feature: Improve settings load
BornToBeRoot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
85 changes: 76 additions & 9 deletions
85
Source/NETworkManager.Localization/Resources/Strings.Designer.cs
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,58 @@ | ||||||
| using System.ComponentModel; | ||||||
| using System.Runtime.CompilerServices; | ||||||
| using System.Text.Json.Serialization; | ||||||
|
|
||||||
| namespace NETworkManager.Settings; | ||||||
|
|
||||||
| /// <summary> | ||||||
| /// Class contains local settings that are stored outside the main settings file. | ||||||
| /// These settings control where the main settings file is located. | ||||||
| /// </summary> | ||||||
| public class LocalSettingsInfo | ||||||
| { | ||||||
| /// <summary> | ||||||
| /// Occurs when a property value changes. | ||||||
| /// </summary> | ||||||
| /// <remarks>This event is typically used to notify subscribers that a property value has been updated. It | ||||||
| /// is commonly implemented in classes that support data binding or need to signal changes to property | ||||||
| /// values.</remarks> | ||||||
| public event PropertyChangedEventHandler PropertyChanged; | ||||||
|
|
||||||
| /// <summary> | ||||||
| /// Helper method to raise the <see cref="PropertyChanged" /> event. | ||||||
| /// </summary> | ||||||
| /// <param name="propertyName">Name of the property that changed.</param> | ||||||
| private void OnPropertyChanged([CallerMemberName] string propertyName = null) | ||||||
| { | ||||||
| SettingsChanged = true; | ||||||
|
|
||||||
| PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); | ||||||
| } | ||||||
|
|
||||||
| #region Variables | ||||||
|
|
||||||
| [JsonIgnore] public bool SettingsChanged { get; set; } | ||||||
|
|
||||||
| /// <summary> | ||||||
| /// Private field for the <see cref="SettingsFolderLocation" /> property." | ||||||
|
||||||
| /// Private field for the <see cref="SettingsFolderLocation" /> property." | |
| /// Private field for the <see cref="SettingsFolderLocation" /> property. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| using log4net; | ||
| using System; | ||
| using System.IO; | ||
| using System.Text.Json; | ||
| using System.Text.Json.Serialization; | ||
|
|
||
| namespace NETworkManager.Settings; | ||
|
|
||
| /// <summary> | ||
| /// Manages local application settings that are stored outside the main settings file. | ||
| /// This is used for settings that control where the main settings file is located. | ||
| /// </summary> | ||
| public static class LocalSettingsManager | ||
| { | ||
| #region Variables | ||
|
|
||
| /// <summary> | ||
| /// Logger for logging. | ||
| /// </summary> | ||
| private static readonly ILog Log = LogManager.GetLogger(typeof(LocalSettingsManager)); | ||
|
|
||
| /// <summary> | ||
| /// Settings file name. | ||
| /// </summary> | ||
| private static string SettingsFileName => "Settings.json"; | ||
|
|
||
| /// <summary> | ||
| /// Settings that are currently loaded. | ||
| /// </summary> | ||
| public static LocalSettingsInfo Current { get; private set; } | ||
|
|
||
| /// <summary> | ||
| /// JSON serializer options for consistent serialization/deserialization. | ||
| /// </summary> | ||
| private static readonly JsonSerializerOptions JsonOptions = new() | ||
| { | ||
| WriteIndented = true, | ||
| PropertyNameCaseInsensitive = true, | ||
| DefaultIgnoreCondition = JsonIgnoreCondition.Never, | ||
| Converters = { new JsonStringEnumConverter() } | ||
| }; | ||
| #endregion | ||
|
|
||
| #region Methods | ||
|
|
||
| /// <summary> | ||
| /// Method to get the path of the settings folder. | ||
| /// </summary> | ||
| /// <returns>Path to the settings folder.</returns> | ||
| private static string GetSettingsFolderLocation() | ||
| { | ||
| return Path.Combine( | ||
| Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), | ||
| AssemblyManager.Current.Name); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Method to get the settings file path | ||
| /// </summary> | ||
| /// <returns>Settings file path.</returns> | ||
| private static string GetSettingsFilePath() | ||
| { | ||
| return Path.Combine( | ||
| GetSettingsFolderLocation(), | ||
| SettingsFileName); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Initialize new settings (<see cref="SettingsInfo" />) and save them (to a file). | ||
| /// </summary> | ||
| private static void Initialize() | ||
| { | ||
| Log.Info("Initializing new local settings."); | ||
|
|
||
| Current = new LocalSettingsInfo(); | ||
|
|
||
| Save(); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Method to load the settings from a file. | ||
| /// </summary> | ||
| public static void Load() | ||
| { | ||
| var filePath = GetSettingsFilePath(); | ||
|
|
||
| if (File.Exists(filePath)) | ||
| { | ||
| try | ||
| { | ||
| Log.Info($"Loading local settings from: {filePath}"); | ||
|
|
||
| var jsonString = File.ReadAllText(filePath); | ||
|
|
||
| // Treat empty or JSON "null" as "no settings" instead of crashing | ||
| if (string.IsNullOrWhiteSpace(jsonString)) | ||
| { | ||
| Log.Info("Local settings file is empty, initializing new local settings."); | ||
| } | ||
| else | ||
| { | ||
| Current = JsonSerializer.Deserialize<LocalSettingsInfo>(jsonString, JsonOptions) ?? new LocalSettingsInfo(); | ||
|
|
||
| Log.Info("Local settings loaded successfully."); | ||
|
|
||
| // Reset change tracking | ||
| Current.SettingsChanged = false; | ||
|
|
||
| return; | ||
| } | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Log.Error($"Failed to load local settings from: {filePath}", ex); | ||
| } | ||
| } | ||
|
|
||
| // Initialize new local settings if file does not exist or loading failed | ||
| Initialize(); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Method to save the current settings to a file. | ||
| /// </summary> | ||
| public static void Save() | ||
| { | ||
| // Create the directory if it does not exist | ||
| Directory.CreateDirectory(GetSettingsFolderLocation()); | ||
|
|
||
| // Serialize to file | ||
| var filePath = GetSettingsFilePath(); | ||
|
|
||
| var jsonString = JsonSerializer.Serialize(Current, JsonOptions); | ||
| File.WriteAllText(filePath, jsonString); | ||
|
|
||
| Log.Info($"Local settings saved to {filePath}"); | ||
|
|
||
| // Reset change tracking | ||
| Current.SettingsChanged = false; | ||
| } | ||
| #endregion | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The LocalSettingsInfo class declares a PropertyChanged event and OnPropertyChanged method consistent with INotifyPropertyChanged pattern, but does not explicitly implement the INotifyPropertyChanged interface. This is inconsistent with the similar SettingsInfo class pattern. Consider adding
: INotifyPropertyChangedto the class declaration for clarity and consistency.