diff --git a/Moonlight/App/Helpers/PropBinder.cs b/Moonlight/App/Helpers/PropBinder.cs index 52c41313..9d3d9865 100644 --- a/Moonlight/App/Helpers/PropBinder.cs +++ b/Moonlight/App/Helpers/PropBinder.cs @@ -24,13 +24,13 @@ public class PropBinder get => (int)PropertyInfo.GetValue(DataObject)!; set => PropertyInfo.SetValue(DataObject, value); } - + public long LongValue { get => (long)PropertyInfo.GetValue(DataObject)!; set => PropertyInfo.SetValue(DataObject, value); } - + public bool BoolValue { get => (bool)PropertyInfo.GetValue(DataObject)!; @@ -48,7 +48,7 @@ public class PropBinder get => (T)PropertyInfo.GetValue(DataObject)!; set => PropertyInfo.SetValue(DataObject, value); } - + public double DoubleValue { get => (double)PropertyInfo.GetValue(DataObject)!; diff --git a/Moonlight/App/Services/ConfigService.cs b/Moonlight/App/Services/ConfigService.cs index 7f74598d..322a4496 100644 --- a/Moonlight/App/Services/ConfigService.cs +++ b/Moonlight/App/Services/ConfigService.cs @@ -21,7 +21,12 @@ public class ConfigService var text = File.ReadAllText(Path); Data = JsonConvert.DeserializeObject(text) ?? new(); - text = JsonConvert.SerializeObject(Data, Formatting.Indented); + Save(); + } + + public void Save() + { + var text = JsonConvert.SerializeObject(Data, Formatting.Indented); File.WriteAllText(Path, text); } diff --git a/Moonlight/Shared/Components/Forms/AutoProperty.razor b/Moonlight/Shared/Components/Forms/AutoProperty.razor index 1bc407b7..ae7616dd 100644 --- a/Moonlight/Shared/Components/Forms/AutoProperty.razor +++ b/Moonlight/Shared/Components/Forms/AutoProperty.razor @@ -133,6 +133,11 @@ Binder = new(Property, Data); } + protected override void OnParametersSet() + { + Binder = new(Property, Data); + } + protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) diff --git a/Moonlight/Shared/Components/Navigations/AdminSysNavigation.razor b/Moonlight/Shared/Components/Navigations/AdminSysNavigation.razor new file mode 100644 index 00000000..13b17065 --- /dev/null +++ b/Moonlight/Shared/Components/Navigations/AdminSysNavigation.razor @@ -0,0 +1,22 @@ +
+ +
+ +@code +{ + [Parameter] + public int Index { get; set; } +} \ No newline at end of file diff --git a/Moonlight/Shared/Components/Partials/Sidebar.razor b/Moonlight/Shared/Components/Partials/Sidebar.razor index 65e27cca..c6e02021 100644 --- a/Moonlight/Shared/Components/Partials/Sidebar.razor +++ b/Moonlight/Shared/Components/Partials/Sidebar.razor @@ -105,6 +105,17 @@ + + } diff --git a/Moonlight/Shared/Views/Admin/Sys/Index.razor b/Moonlight/Shared/Views/Admin/Sys/Index.razor new file mode 100644 index 00000000..0559f6cd --- /dev/null +++ b/Moonlight/Shared/Views/Admin/Sys/Index.razor @@ -0,0 +1,8 @@ +@page "/admin/sys" + +@using Moonlight.App.Extensions.Attributes +@using Moonlight.App.Models.Enums + +@attribute [RequirePermission(Permission.AdminRoot)] + + \ No newline at end of file diff --git a/Moonlight/Shared/Views/Admin/Sys/Settings.razor b/Moonlight/Shared/Views/Admin/Sys/Settings.razor new file mode 100644 index 00000000..22f5399d --- /dev/null +++ b/Moonlight/Shared/Views/Admin/Sys/Settings.razor @@ -0,0 +1,190 @@ +@page "/admin/sys/settings" +@using Moonlight.App.Services +@using System.Reflection +@using Moonlight.App.Extensions.Attributes +@using Moonlight.App.Models.Enums + +@attribute [RequirePermission(Permission.AdminRoot)] + +@inject ConfigService ConfigService +@inject ToastService ToastService + + + +@if (ModelToShow == null) +{ + +} +else +{ +
+
+ @{ + string title; + + if (Path.Length == 0) + title = "Configuration"; + else + { + title = "Configuration - " + string.Join(" - ", Path); + } + } + +

@(title)

+
+ + + + + + +
+
+
+ + + Changes to these settings are live applied. The save button only make the changes persistently saved to disk + + +
+
+
+ @{ + var props = ModelToShow + .GetType() + .GetProperties() + .Where(x => x.PropertyType.Assembly.FullName!.Contains("Moonlight") && x.PropertyType.IsClass) + .ToArray(); + } + + @foreach (var prop in props) + { +
+ +
+ } + + @if (Path.Length != 0) + { +
+
+ Back +
+
+ } +
+
+
+
+
+ + @foreach (var prop in Properties) + { +
+ + + @{ + var typeToCreate = typeof(AutoProperty<>).MakeGenericType(prop.PropertyType); + } + + @ComponentHelper.FromType(typeToCreate) + + +
+ } +
+
+
+
+
+} + +@code +{ + [Parameter] + [SupplyParameterFromQuery] + public string? Section { get; set; } = ""; + + private object? ModelToShow; + private PropertyInfo[] Properties = Array.Empty(); + private string[] Path = Array.Empty(); + + private LazyLoader? LazyLoader; + + protected override async Task OnParametersSetAsync() + { + if (Section != null && Section.StartsWith("/")) + Section = Section.TrimStart('/'); + + Path = Section != null ? Section.Split("/") : Array.Empty(); + + ModelToShow = Resolve(ConfigService.Get(), Path, 0); + + if (ModelToShow != null) + { + Properties = ModelToShow + .GetType() + .GetProperties() + .Where(x => !x.PropertyType.Assembly.FullName!.Contains("Moonlight")) + .ToArray(); + } + else + { + Properties = Array.Empty(); + } + + await InvokeAsync(StateHasChanged); + + if (LazyLoader != null) + await LazyLoader.Reload(); + } + + private string GetBackPath() + { + if (Path.Length == 1) + return "settings"; + else + { + var path = string.Join('/', Path.Take(Path.Length - 1)).TrimEnd('/'); + return $"settings?section={path}"; + } + } + + private object? Resolve(object model, string[] path, int index) + { + if (path.Length == 0) + return model; + + if (path.Length == index) + return model; + + var prop = model + .GetType() + .GetProperties() + .FirstOrDefault(x => x.PropertyType.Assembly.FullName!.Contains("Moonlight") && x.Name == path[index]); + + if (prop == null) + return null; + + return Resolve(prop.GetValue(model)!, path, index + 1); + } + + private Task Load(LazyLoader arg) + { + return Task.CompletedTask; + } + + private async Task Save() + { + ConfigService.Save(); + await ToastService.Success("Successfully saved config to disk"); + } + + private async Task Reload() + { + ConfigService.Reload(); + await ToastService.Info("Reloaded configuration from disk"); + } +} \ No newline at end of file