Disabled dynamic settings for now

This commit is contained in:
Marcel Baumgartner
2024-07-06 14:09:21 +02:00
parent a2a520e9fd
commit a56adfed8a
4 changed files with 99 additions and 82 deletions

View File

@@ -0,0 +1,78 @@
@using System.ComponentModel
@using System.Linq.Expressions
@using System.Reflection
@typeparam T
<FastForm TModel="T" Model="(T)Model" OnConfigure="OnFormConfigure"/>
@code
{
[Parameter] public object Model { get; set; }
private PropertyInfo[] Properties;
protected override async Task OnParametersSetAsync()
{
Properties = Model.GetType().GetProperties()
.Where(x =>
!x.PropertyType.Namespace.StartsWith("Moonlight") &&
DefaultComponentRegistry.Get(x.PropertyType) != null // Check if a component has been registered for that type
)
.ToArray();
}
private void OnFormConfigure(FastFormConfiguration<T> configuration)
{
if (Model == null) // This will technically never be true because of the ui logic
return;
foreach (var property in Properties)
{
var propertyFunc = GetType().GetMethod("CreatePropertyAccessExpression")!.MakeGenericMethod(property.PropertyType).Invoke(this, [property]);
var config = configuration.GetType().GetMethod("AddProperty")!.MakeGenericMethod(property.PropertyType).Invoke(configuration, [propertyFunc])!;
config.GetType().GetMethod("WithDefaultComponent")!.Invoke(config, []);
var attributes = property.GetCustomAttributes(true);
if (TryGetAttribute(attributes, out DisplayNameAttribute nameAttribute))
config.GetType().GetMethod("WithName")!.Invoke(config, [nameAttribute.DisplayName]);
if (TryGetAttribute(attributes, out DescriptionAttribute descriptionAttribute))
config.GetType().GetMethod("WithDescription")!.Invoke(config, [descriptionAttribute.Description]);
}
}
// Building lambda expressions at runtime using reflection is nice ;3
public static Expression<Func<T, TResult?>> CreatePropertyAccessExpression<TResult>(PropertyInfo property)
{
// Create a parameter expression for TData
var parameter = Expression.Parameter(typeof(T), "data");
// Access the property
var member = Expression.MakeMemberAccess(parameter, property);
// Create the lambda expression
var lambda = Expression.Lambda<Func<T, TResult?>>(member, parameter);
return lambda;
}
// From MoonCore. TODO: Maybe provide this and the above function as mooncore helper
private static bool TryGetAttribute<T>(object[] attributes, out T result) where T : Attribute
{
var searchType = typeof(T);
var attr = attributes
.FirstOrDefault(x => x.GetType() == searchType);
if (attr == null)
{
result = default!;
return false;
}
result = (attr as T)!;
return true;
}
}

View File

@@ -1,6 +1,4 @@
@page "/admin/sys/settings" @using System.ComponentModel
@using System.ComponentModel
@using System.Linq.Expressions @using System.Linq.Expressions
@using Moonlight.Core.UI.Components.Navigations @using Moonlight.Core.UI.Components.Navigations
@using System.Reflection @using System.Reflection
@@ -89,7 +87,7 @@ else
</div> </div>
<div class="col-md-9 col-12"> <div class="col-md-9 col-12">
<LazyLoader @ref="LazyLoader" Load="Load" UseDefaultValues="false" TimeUntilSpinnerIsShown="TimeSpan.Zero"> <LazyLoader @ref="LazyLoader" Load="Load" UseDefaultValues="false" TimeUntilSpinnerIsShown="TimeSpan.Zero">
<FastForm Model="CurrentModel" OnConfigure="OnFormConfigure"/> @Content
</LazyLoader> </LazyLoader>
</div> </div>
</div> </div>
@@ -102,9 +100,9 @@ else
private object? CurrentModel; private object? CurrentModel;
private string[] SidebarItems = []; private string[] SidebarItems = [];
private string[] Path = []; private string[] Path = [];
private PropertyInfo[] Properties = [];
private LazyLoader? LazyLoader; private LazyLoader? LazyLoader;
private RenderFragment Content;
protected override async Task OnParametersSetAsync() protected override async Task OnParametersSetAsync()
{ {
@@ -118,7 +116,6 @@ else
if (CurrentModel == null) if (CurrentModel == null)
{ {
SidebarItems = []; SidebarItems = [];
Properties = [];
} }
else else
{ {
@@ -134,13 +131,6 @@ else
) )
.Select(x => x.Name) .Select(x => x.Name)
.ToArray(); .ToArray();
Properties = props
.Where(x =>
!x.PropertyType.Namespace.StartsWith("Moonlight") &&
DefaultComponentRegistry.Get(x.PropertyType) != null // Check if a component has been registered for that type
)
.ToArray();
} }
await InvokeAsync(StateHasChanged); await InvokeAsync(StateHasChanged);
@@ -148,30 +138,6 @@ else
if (LazyLoader != null) if (LazyLoader != null)
await LazyLoader.Reload(); await LazyLoader.Reload();
} }
private void OnFormConfigure(FastFormConfiguration<object> configuration)
{
if(CurrentModel == null) // This will technically never be true because of the ui logic
return;
foreach (var property in Properties)
{
var propConfig = configuration
.AddProperty(CreatePropertyAccessExpression(property))
.WithDefaultComponent();
var customAttributes = property.GetCustomAttributes(false);
if(customAttributes.Length == 0)
continue;
if (TryGetAttribute(customAttributes, out DisplayNameAttribute nameAttribute))
propConfig.WithName(nameAttribute.DisplayName);
if (TryGetAttribute(customAttributes, out DescriptionAttribute descriptionAttribute))
propConfig.WithDescription(descriptionAttribute.Description);
}
}
private string GetBackPath() private string GetBackPath()
{ {
@@ -201,7 +167,15 @@ else
return Resolve(prop.GetValue(model)!, path, index + 1); return Resolve(prop.GetValue(model)!, path, index + 1);
} }
private Task Load(LazyLoader _) => Task.CompletedTask; // Seems useless, it more or less is, but it shows a nice loading ui while the form changes private Task Load(LazyLoader _)
{
Content = ComponentHelper.FromType(typeof(DynamicFormBuilder<>).MakeGenericType(CurrentModel.GetType()), parameters =>
{
parameters.Add("Model", CurrentModel);
});
return Task.CompletedTask;
}
private async Task Save() // Saves all changes to disk, all changes are live updated as the config service reference will be edited directly private async Task Save() // Saves all changes to disk, all changes are live updated as the config service reference will be edited directly
{ {
@@ -214,47 +188,4 @@ else
ConfigService.Reload(); ConfigService.Reload();
await ToastService.Info("Reloaded configuration from disk"); await ToastService.Info("Reloaded configuration from disk");
} }
// Building lambda expressions at runtime using reflection is nice ;3
public static Expression<Func<object, object?>> CreatePropertyAccessExpression(PropertyInfo property)
{
// Get the type that declares the property
Type declaringType = property.DeclaringType!;
// Create a parameter expression for the input object
ParameterExpression param = Expression.Parameter(typeof(object), "obj");
// Create an expression to cast the input object to the declaring type
UnaryExpression cast = Expression.Convert(param, declaringType);
// Create an expression to access the property
MemberExpression propertyAccess = Expression.Property(cast, property);
// Create an expression to cast the property value to object
UnaryExpression castResult = Expression.Convert(propertyAccess, typeof(object));
// Create the final lambda expression
Expression<Func<object, object?>> lambda = Expression.Lambda<Func<object, object?>>(
castResult, param);
return lambda;
}
// From MoonCore. TODO: Maybe provide this and the above function as mooncore helper
private bool TryGetAttribute<T>(object[] attributes, out T result) where T : Attribute
{
var searchType = typeof(T);
var attr = attributes
.FirstOrDefault(x => x.GetType() == searchType);
if (attr == null)
{
result = default!;
return false;
}
result = (attr as T)!;
return true;
}
} }

View File

@@ -0,0 +1,8 @@
@page "/admin/sys/settings"
@using Moonlight.Core.UI.Components.Navigations
@attribute [RequirePermission(9999)]
<AdminSysNavigation Index="1"/>
<NotImplementedAlert />

View File

@@ -180,7 +180,7 @@
configuration.AddProperty(x => x.AllocationsNeeded) configuration.AddProperty(x => x.AllocationsNeeded)
.WithDefaultComponent() .WithDefaultComponent()
.WithPage("Miscellaneous") .WithPage("Miscellaneous")
.WithValidation(x => x > 1 ? ValidationResult.Success : new ValidationResult("This specifies the amount of allocations needed for this image in order to create a server")); .WithValidation(x => x >= 1 ? ValidationResult.Success : new ValidationResult("This specifies the amount of allocations needed for this image in order to create a server"));
configuration.AddProperty(x => x.InstallDockerImage) configuration.AddProperty(x => x.InstallDockerImage)
.WithDefaultComponent() .WithDefaultComponent()