Disabled dynamic settings for now
This commit is contained in:
78
Moonlight/Core/UI/Components/DynamicFormBuilder.razor
Normal file
78
Moonlight/Core/UI/Components/DynamicFormBuilder.razor
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
@page "/admin/sys/settings"
|
||||
|
||||
@using System.ComponentModel
|
||||
@using System.ComponentModel
|
||||
@using System.Linq.Expressions
|
||||
@using Moonlight.Core.UI.Components.Navigations
|
||||
@using System.Reflection
|
||||
@@ -89,7 +87,7 @@ else
|
||||
</div>
|
||||
<div class="col-md-9 col-12">
|
||||
<LazyLoader @ref="LazyLoader" Load="Load" UseDefaultValues="false" TimeUntilSpinnerIsShown="TimeSpan.Zero">
|
||||
<FastForm Model="CurrentModel" OnConfigure="OnFormConfigure"/>
|
||||
@Content
|
||||
</LazyLoader>
|
||||
</div>
|
||||
</div>
|
||||
@@ -102,9 +100,9 @@ else
|
||||
private object? CurrentModel;
|
||||
private string[] SidebarItems = [];
|
||||
private string[] Path = [];
|
||||
private PropertyInfo[] Properties = [];
|
||||
|
||||
private LazyLoader? LazyLoader;
|
||||
private RenderFragment Content;
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
@@ -118,7 +116,6 @@ else
|
||||
if (CurrentModel == null)
|
||||
{
|
||||
SidebarItems = [];
|
||||
Properties = [];
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -134,13 +131,6 @@ else
|
||||
)
|
||||
.Select(x => x.Name)
|
||||
.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);
|
||||
@@ -149,30 +139,6 @@ else
|
||||
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()
|
||||
{
|
||||
if (Path.Length == 1)
|
||||
@@ -201,7 +167,15 @@ else
|
||||
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
|
||||
{
|
||||
@@ -214,47 +188,4 @@ else
|
||||
ConfigService.Reload();
|
||||
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;
|
||||
}
|
||||
}
|
||||
8
Moonlight/Core/UI/Views/Admin/Sys/SettingsDisabled.razor
Normal file
8
Moonlight/Core/UI/Views/Admin/Sys/SettingsDisabled.razor
Normal file
@@ -0,0 +1,8 @@
|
||||
@page "/admin/sys/settings"
|
||||
@using Moonlight.Core.UI.Components.Navigations
|
||||
|
||||
@attribute [RequirePermission(9999)]
|
||||
|
||||
<AdminSysNavigation Index="1"/>
|
||||
|
||||
<NotImplementedAlert />
|
||||
@@ -180,7 +180,7 @@
|
||||
configuration.AddProperty(x => x.AllocationsNeeded)
|
||||
.WithDefaultComponent()
|
||||
.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)
|
||||
.WithDefaultComponent()
|
||||
|
||||
Reference in New Issue
Block a user