diff --git a/Moonlight/Core/UI/Components/DynamicFormBuilder.razor b/Moonlight/Core/UI/Components/DynamicFormBuilder.razor
new file mode 100644
index 00000000..8195af4f
--- /dev/null
+++ b/Moonlight/Core/UI/Components/DynamicFormBuilder.razor
@@ -0,0 +1,78 @@
+@using System.ComponentModel
+@using System.Linq.Expressions
+@using System.Reflection
+@typeparam T
+
+
+
+@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 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> CreatePropertyAccessExpression(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>(member, parameter);
+
+ return lambda;
+ }
+
+ // From MoonCore. TODO: Maybe provide this and the above function as mooncore helper
+ private static bool TryGetAttribute(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;
+ }
+}
\ No newline at end of file
diff --git a/Moonlight/Core/UI/Views/Admin/Sys/Settings.razor b/Moonlight/Core/UI/Views/Admin/Sys/Settings.razor
index 11a925dc..5027387d 100644
--- a/Moonlight/Core/UI/Views/Admin/Sys/Settings.razor
+++ b/Moonlight/Core/UI/Views/Admin/Sys/Settings.razor
@@ -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
-
+ @Content
@@ -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);
@@ -148,30 +138,6 @@ else
if (LazyLoader != null)
await LazyLoader.Reload();
}
-
- private void OnFormConfigure(FastFormConfiguration