Skip to content
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

Settings - Implement Settings Backend #396

Closed
Tracked by #1182
erri120 opened this issue Jul 5, 2023 · 13 comments · Fixed by #1187
Closed
Tracked by #1182

Settings - Implement Settings Backend #396

erri120 opened this issue Jul 5, 2023 · 13 comments · Fixed by #1187
Assignees

Comments

@erri120
Copy link
Member

erri120 commented Jul 5, 2023

Using the modern Configuration approach, components in our DI system can require IOption<MyOptions> or IOptionMonitor<MyOptions> to access component-specific configuration without having to deal with loading, saving and updating them. The monitor is especially useful as it's fully reactive and allows for changes to be applied immediately (see #362 for an example).

These settings/options should be saved to disk as JSON to be persistent, but should also be presented to the user in some capacity. Such a system would provide implementations of IOptionMonitor<T> and serve as a configuration provider.

@erri120 erri120 added complexity-medium Design UI/UX This is related to the UI. labels Jul 5, 2023
@Greg-Nexus Greg-Nexus modified the milestone: v0.2 Jul 27, 2023
@erri120
Copy link
Member Author

erri120 commented Oct 2, 2023

Related: #308

@erri120
Copy link
Member Author

erri120 commented Oct 2, 2023

Should use source generators instead of reflection to auto-generate the settings panel.

@Al12rs
Copy link
Contributor

Al12rs commented Oct 2, 2023

From discussion in meeting:

  • We want to have a standard list of settings types (checkbox, dropdown, path selector, string, color, number, range etc) and UI needs to have a standard way to represent these.
  • We want to add settings programmatically.
  • UI should have a Search bar
  • Each setting has a parent section, that ui can decide how to show.
  • Settings can be inside a Panel
  • Apply button so that it's clear when stuff is actually getting changed.
  • Some settings can require a restart to get applied, ui should have an indication of this.
  • All settings need a description that isn't easy to miss for confused users.

I'll add a list of setting types below, might not be exhaustive, so please contribute to it if you see something missing or something that is excessive.

@Al12rs
Copy link
Contributor

Al12rs commented Oct 2, 2023

Types of settings that I can think of and possible ui:

  • Boolean (Yes/No checkbox).
  • Exclusive multiple option choice (Dropdown)
  • Integer Number (input field with up down arrows)
  • Integer Number in Range (Slider)
  • Decimal Number (input field)
  • Decimal Number in range (Slider)
  • Percentage (Same as either Decimal or Integer range?)
  • FilePath (path picker)
  • FolderPath (path picker)
  • Color (color picker)
  • String (Text input)
  • List of Strings (e.g. excluded file extensions) (Comma separated text input, something better?)
  • Version number (semantic forced or not)
  • Password field?
  • Image picker?
  • Buttons that do something (Associate with Nexus links, reset something).
  • Buttons that open other dedicated configuration Panel/windows. ?

Additional info for each setting:

  • Name
  • Description (Should support links)
  • Type
  • Default value
  • Apply requirements (Restart, some smaller refresh)
  • Extremes (for ranges)
  • Extremes labels (Small, Large, ...)
  • Type suffix (MB/s, %, cores, something...)
@Al12rs
Copy link
Contributor

Al12rs commented Oct 2, 2023

Other Design question:

  • How to visualize settings for a specific game.
  • Settings for a specific extension plugins (! some of these extension plugins are pretty core to the App, like Fomod installer or Manual Installer).

An extension could add a setting that semantically goes into a specific section (e.g. Downloads) but it's from an Extension which could be it's own section.

VS Code does this by having a separate section for each extension, under which there are nested sections for the actual sections (e.g. SomeExtensionSection > Downloads > actualSetting).

I don't know if this is the best idea, but potentially we might need nested sections (more than just one level).

@erri120 erri120 added this to the v0.3 milestone Oct 10, 2023
@Greg-Nexus
Copy link
Contributor

Settings that need adding:

  • Language
  • Data Gathering Opt-in/out
@captainsandypants
Copy link
Collaborator

Settings that need adding:

  • Language
  • Data Gathering Opt-in/out

@Greg-Nexus for this ticket, is it just the above two settings?

@captainsandypants captainsandypants removed their assignment Nov 23, 2023
@Greg-Nexus Greg-Nexus assigned Al12rs and unassigned erri120 and Al12rs Nov 27, 2023
@halgari
Copy link
Collaborator

halgari commented Jan 23, 2024

We should try to simplify paths to KnownPaths + relative path.

c:\User\billyg\AppData\Local\Foo.bar

<AppDataLocal>\Foo.bar

Also we probably want validators around config options.

@Greg-Nexus Greg-Nexus removed this from the v0.3 milestone Feb 5, 2024
@Al12rs
Copy link
Contributor

Al12rs commented Feb 5, 2024

@captainsandypants We need Design for displaying settings with a Warning, such as Experimental or Not Recommended.

This came up in the context of offering an option to not Backup the game files when managing the game for the first time, which exposes the users to potential issues if the game updates, since we don't have the backups of the old files if the user wants to rollback.

@Al12rs Al12rs changed the title Add a settings page Feb 7, 2024
@Al12rs Al12rs changed the title Implement sandardized settings backend Feb 7, 2024
@Al12rs Al12rs removed the Design UI/UX This is related to the UI. label Feb 7, 2024
@Al12rs Al12rs mentioned this issue Feb 7, 2024
18 tasks
@Al12rs
Copy link
Contributor

Al12rs commented Feb 7, 2024

Changed this issue to refer only to the backend part of the Settings, UI is in #920.

Implementing backend for settings will allow us to have a standard way to add configuration as we build various components.

Without this, if we need to add a setting as we develop components, we would ether:

  • use a stop gap solution that will need to be replaced later,
  • roll out a different custom solution for that configuration point,
  • completely skip having the option altogether, making it much harder to go back and these later.

Allowing users to access and change the values from the UI can come at a later point.

@erri120
Copy link
Member Author

erri120 commented Apr 8, 2024

@Al12rs @Sewer56 thoughts on using a builder pattern for configuring how settings are displayed and how they behave?

file record MySettings : ISettings
{
    public required string Name { get; init; } = "Placeholder";

    public required bool EnableCoolFeature { get; init; } = true;

    public ISettingsBuilder Configure(ISettingsBuilder settingsBuilder)
    {
        var sectionId = SectionId.From(Guid.Parse("33dd8d48-124b-4d59-839c-249caed881ea"));
        settingsBuilder = settingsBuilder.AddSection(sectionId, "General");

        return settingsBuilder.AddSettings<MySettings>(builder => builder
            .WithSection(sectionId)
            .ConfigureField(x => x.Name, fieldBuilder => fieldBuilder
                .WithName("Name")
                .WithDescription("This is a cool name that you can change.")
                .WithValidation(ValidateName)
            )
            .ConfigureField(x => x.EnableCoolFeature, fieldBuilder => fieldBuilder
                .WithName("Cool Feature")
                .WithDescription("This is a very cool feature that you can enable.")
                .RequiresRestart("Toggling this cool feature requires a restart!")
            )
            .Finish()
        );
    }

    private static ValidationResult ValidateName(string name)
    {
        const int minLength = 5;
        const int maxLength = 50;

        if (string.IsNullOrWhiteSpace(name))
            return ValidationResult.CreateFailed("Name cannot be empty!");

        if (name.Length < minLength)
            return ValidationResult.CreateFailed($"Name must be at least {minLength} characters long!");

        if (name.Length > maxLength)
            return ValidationResult.CreateFailed($"Name must be less than {minLength} characters long!");

        return ValidationResult.CreateSuccessful();
    }
}
@erri120
Copy link
Member Author

erri120 commented Apr 9, 2024

I refactored the API to be easier to understand:

return settingsBuilder.AddToUI<MySettings>(uiBuilder => uiBuilder
    .AddToSection(SectionId.DefaultValue)
    .AddPropertyToUI(x => x.Name, propertyBuilder => propertyBuilder
        .WithDisplayName("Cool Name")
        .WithDescription("This is a very cool name that you can change!")
        .WithValidation(ValidateName)
        .RequiresRestart("Changing this very cool name requires a restart!")
    )
);
@LukeNexusMods LukeNexusMods changed the title Implement Settings Backend Apr 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
6 participants