Improved developer experience for AdminContext's

This commit is contained in:
2024-11-09 10:39:17 +01:00
parent 0cc4eb44da
commit 601b502c8c
6 changed files with 53 additions and 59 deletions

View File

@@ -22,7 +22,7 @@ public interface IAdminPageGenerator<TModel> {
IAdminPageGenerator<TModel> ConfigureRepository<TRepository>() where TRepository : ModelRepository<TModel>; IAdminPageGenerator<TModel> ConfigureRepository<TRepository>() where TRepository : ModelRepository<TModel>;
IAdminPropertyGenerator<TProperty> Property<TProperty>(Expression<Func<TModel, TProperty>> propertyExpression); IAdminPropertyGenerator<TProperty, TModel> Property<TProperty>(Expression<Func<TModel, TProperty>> propertyExpression);
IAdminPageGenerator<TModel> ListingProperty<TProperty>(Expression<Func<TModel, TProperty>> propertyExpression); IAdminPageGenerator<TModel> ListingProperty<TProperty>(Expression<Func<TModel, TProperty>> propertyExpression);
} }

View File

@@ -2,28 +2,27 @@ using System.Linq.Expressions;
namespace HopFrame.Web.Admin.Generators; namespace HopFrame.Web.Admin.Generators;
public interface IAdminPropertyGenerator<TProperty> { public interface IAdminPropertyGenerator<TProperty, TModel> {
IAdminPropertyGenerator<TProperty> Sortable(bool sortable); IAdminPropertyGenerator<TProperty, TModel> Sortable(bool sortable);
IAdminPropertyGenerator<TProperty> Editable(bool editable); IAdminPropertyGenerator<TProperty, TModel> Editable(bool editable);
IAdminPropertyGenerator<TProperty> DisplayValueWhileEditing(bool display); IAdminPropertyGenerator<TProperty, TModel> DisplayValueWhileEditing(bool display);
IAdminPropertyGenerator<TProperty> DisplayInListing(bool display = true); IAdminPropertyGenerator<TProperty, TModel> DisplayInListing(bool display = true);
IAdminPropertyGenerator<TProperty> Ignore(bool ignore = true); IAdminPropertyGenerator<TProperty, TModel> Ignore(bool ignore = true);
IAdminPropertyGenerator<TProperty> Generated(bool generated = true); IAdminPropertyGenerator<TProperty, TModel> Generated(bool generated = true);
IAdminPropertyGenerator<TProperty> Bold(bool bold = true); IAdminPropertyGenerator<TProperty, TModel> Bold(bool bold = true);
IAdminPropertyGenerator<TProperty> Unique(bool unique = true); IAdminPropertyGenerator<TProperty, TModel> Unique(bool unique = true);
IAdminPropertyGenerator<TProperty> DisplayName(string displayName); IAdminPropertyGenerator<TProperty, TModel> DisplayName(string displayName);
IAdminPropertyGenerator<TProperty> Description(string description); IAdminPropertyGenerator<TProperty, TModel> Description(string description);
IAdminPropertyGenerator<TProperty> Prefix(string prefix); IAdminPropertyGenerator<TProperty, TModel> Prefix(string prefix);
IAdminPropertyGenerator<TProperty> Validator(Func<TProperty, string> validator); IAdminPropertyGenerator<TProperty, TModel> Validator(Func<TProperty, string> validator);
IAdminPropertyGenerator<TProperty> IsSelector(bool selector = true); IAdminPropertyGenerator<TProperty, TModel> IsSelector(bool selector = true);
IAdminPropertyGenerator<TProperty> IsSelector<TSelectorType>(bool selector = true); IAdminPropertyGenerator<TProperty, TModel> IsSelector<TSelectorType>(bool selector = true);
IAdminPropertyGenerator<TProperty> Parser<TModel>(Func<TModel, string, TProperty> parser); IAdminPropertyGenerator<TProperty, TModel> Parser(Func<TModel, string, TProperty> parser);
IAdminPropertyGenerator<TProperty> Parser<TModel, TInput>(Func<TModel, TInput, TProperty> parser); IAdminPropertyGenerator<TProperty, TModel> Parser<TInput>(Func<TModel, TInput, TProperty> parser);
IAdminPropertyGenerator<TProperty> ParserForListType<TModel, TInnerProperty>(Func<TModel, string, TInnerProperty> parser); IAdminPropertyGenerator<TProperty, TModel> Parser<TInput, TInnerProperty>(Func<TModel, TInput, TInnerProperty> parser);
IAdminPropertyGenerator<TProperty> ParserForListType<TModel, TInnerProperty, TInput>(Func<TModel, TInput, TInnerProperty> parser); IAdminPropertyGenerator<TProperty, TModel> DisplayProperty(Expression<Func<TProperty, object>> propertyExpression);
IAdminPropertyGenerator<TProperty> DisplayProperty<TListingProperty>(Expression<Func<TProperty, TListingProperty>> propertyExpression); IAdminPropertyGenerator<TProperty, TModel> DisplayProperty<TInnerProperty>(Expression<Func<TInnerProperty, object>> propertyExpression);
IAdminPropertyGenerator<TProperty> DisplayPropertyForListType<TInnerProperty>(Expression<Func<TInnerProperty, object>> propertyExpression);
} }

View File

@@ -21,16 +21,16 @@ internal sealed class AdminPageGenerator<TModel> : IAdminPageGenerator<TModel>,
var type = typeof(TModel); var type = typeof(TModel);
var properties = type.GetProperties(); var properties = type.GetProperties();
var generatorType = typeof(AdminPropertyGenerator<>); var generatorType = typeof(AdminPropertyGenerator<,>);
foreach (var property in properties) { foreach (var property in properties) {
var attributes = property.GetCustomAttributes(false); var attributes = property.GetCustomAttributes(false);
var genericType = generatorType.MakeGenericType(property.PropertyType); var genericType = generatorType.MakeGenericType(property.PropertyType, type);
var generator = Activator.CreateInstance(genericType, [property.Name, property.PropertyType]); var generator = Activator.CreateInstance(genericType, [property.Name, property.PropertyType]);
var method = genericType var method = genericType
.GetMethod(nameof(AdminPropertyGenerator<object>.ApplyConfigurationFromAttributes))? .GetMethod(nameof(AdminPropertyGenerator<object, object>.ApplyConfigurationFromAttributes))?
.MakeGenericMethod(type); .MakeGenericMethod(type);
method?.Invoke(generator, [this, attributes, property]); method?.Invoke(generator, [this, attributes, property]);
@@ -102,13 +102,13 @@ internal sealed class AdminPageGenerator<TModel> : IAdminPageGenerator<TModel>,
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> Property<TProperty>(Expression<Func<TModel, TProperty>> propertyExpression) { public IAdminPropertyGenerator<TProperty, TModel> Property<TProperty>(Expression<Func<TModel, TProperty>> propertyExpression) {
var property = GetPropertyInfo(propertyExpression); var property = GetPropertyInfo(propertyExpression);
if (_propertyGenerators.TryGetValue(property.Name, out var propertyGenerator)) if (_propertyGenerators.TryGetValue(property.Name, out var propertyGenerator))
return propertyGenerator as AdminPropertyGenerator<TProperty>; return propertyGenerator as AdminPropertyGenerator<TProperty, TModel>;
var generator = Activator.CreateInstance(typeof(AdminPropertyGenerator<TProperty>), new { property.Name, property.PropertyType }) as AdminPropertyGenerator<TProperty>; var generator = Activator.CreateInstance(typeof(AdminPropertyGenerator<TProperty, TModel>), new { property.Name, property.PropertyType }) as AdminPropertyGenerator<TProperty, TModel>;
generator?.ApplyConfigurationFromAttributes(this, property.GetCustomAttributes(false), property); generator?.ApplyConfigurationFromAttributes(this, property.GetCustomAttributes(false), property);
_propertyGenerators.Add(property.Name, generator); _propertyGenerators.Add(property.Name, generator);
@@ -125,7 +125,7 @@ internal sealed class AdminPageGenerator<TModel> : IAdminPageGenerator<TModel>,
var properties = new List<AdminPageProperty>(); var properties = new List<AdminPageProperty>();
foreach (var generator in _propertyGenerators.Values) { foreach (var generator in _propertyGenerators.Values) {
var method = generator.GetType().GetMethod(nameof(AdminPropertyGenerator<object>.Compile)); var method = generator.GetType().GetMethod(nameof(AdminPropertyGenerator<object, object>.Compile));
var prop = method?.Invoke(generator, []) as AdminPageProperty; var prop = method?.Invoke(generator, []) as AdminPageProperty;
properties.Add(prop); properties.Add(prop);
} }

View File

@@ -8,112 +8,107 @@ using HopFrame.Web.Admin.Models;
namespace HopFrame.Web.Admin.Generators.Implementation; namespace HopFrame.Web.Admin.Generators.Implementation;
internal sealed class AdminPropertyGenerator<TProperty>(string name, Type type) : IAdminPropertyGenerator<TProperty>, IGenerator<AdminPageProperty> { internal sealed class AdminPropertyGenerator<TProperty, TModel>(string name, Type type) : IAdminPropertyGenerator<TProperty, TModel>, IGenerator<AdminPageProperty> {
private readonly AdminPageProperty _property = new() { private readonly AdminPageProperty _property = new() {
Name = name, Name = name,
Type = type Type = type
}; };
public IAdminPropertyGenerator<TProperty> Sortable(bool sortable) { public IAdminPropertyGenerator<TProperty, TModel> Sortable(bool sortable) {
_property.Sortable = sortable; _property.Sortable = sortable;
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> Editable(bool editable) { public IAdminPropertyGenerator<TProperty, TModel> Editable(bool editable) {
_property.Editable = editable; _property.Editable = editable;
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> DisplayValueWhileEditing(bool display) { public IAdminPropertyGenerator<TProperty, TModel> DisplayValueWhileEditing(bool display) {
_property.EditDisplayValue = display; _property.EditDisplayValue = display;
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> DisplayInListing(bool display = true) { public IAdminPropertyGenerator<TProperty, TModel> DisplayInListing(bool display = true) {
_property.DisplayInListing = display; _property.DisplayInListing = display;
_property.Sortable = false; _property.Sortable = false;
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> Ignore(bool ignore = false) { public IAdminPropertyGenerator<TProperty, TModel> Ignore(bool ignore = false) {
_property.Ignore = ignore; _property.Ignore = ignore;
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> Generated(bool generated = true) { public IAdminPropertyGenerator<TProperty, TModel> Generated(bool generated = true) {
_property.Generated = generated; _property.Generated = generated;
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> Bold(bool bold = true) { public IAdminPropertyGenerator<TProperty, TModel> Bold(bool bold = true) {
_property.Bold = bold; _property.Bold = bold;
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> Unique(bool unique = true) { public IAdminPropertyGenerator<TProperty, TModel> Unique(bool unique = true) {
_property.Unique = unique; _property.Unique = unique;
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> DisplayName(string displayName) { public IAdminPropertyGenerator<TProperty, TModel> DisplayName(string displayName) {
_property.DisplayName = displayName; _property.DisplayName = displayName;
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> Description(string description) { public IAdminPropertyGenerator<TProperty, TModel> Description(string description) {
_property.Description = description; _property.Description = description;
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> Prefix(string prefix) { public IAdminPropertyGenerator<TProperty, TModel> Prefix(string prefix) {
_property.Prefix = prefix; _property.Prefix = prefix;
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> Validator(Func<TProperty, string> validator) { public IAdminPropertyGenerator<TProperty, TModel> Validator(Func<TProperty, string> validator) {
_property.Validator = o => validator.Invoke((TProperty)o); _property.Validator = o => validator.Invoke((TProperty)o);
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> IsSelector(bool selector = true) { public IAdminPropertyGenerator<TProperty, TModel> IsSelector(bool selector = true) {
_property.Selector = selector; _property.Selector = selector;
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> IsSelector<TSelectorType>(bool selector = true) { public IAdminPropertyGenerator<TProperty, TModel> IsSelector<TSelectorType>(bool selector = true) {
_property.Selector = true; _property.Selector = true;
_property.SelectorType = typeof(TSelectorType); _property.SelectorType = typeof(TSelectorType);
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> Parser<TModel>(Func<TModel, string, TProperty> parser) { public IAdminPropertyGenerator<TProperty, TModel> Parser(Func<TModel, string, TProperty> parser) {
_property.Parser = (o, s) => parser.Invoke((TModel)o, s.ToString()); _property.Parser = (o, s) => parser.Invoke((TModel)o, s.ToString());
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> Parser<TModel, TInput>(Func<TModel, TInput, TProperty> parser) { public IAdminPropertyGenerator<TProperty, TModel> Parser<TInput>(Func<TModel, TInput, TProperty> parser) {
_property.Parser = (o, s) => parser.Invoke((TModel)o, (TInput)s); _property.Parser = (o, s) => parser.Invoke((TModel)o, (TInput)s);
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> ParserForListType<TModel, TInnerProperty>(Func<TModel, string, TInnerProperty> parser) { public IAdminPropertyGenerator<TProperty, TModel> Parser<TInput, TInnerProperty>(Func<TModel, TInput, TInnerProperty> parser) {
_property.Parser = (o, s) => parser.Invoke((TModel)o, s.ToString());
return this;
}
public IAdminPropertyGenerator<TProperty> ParserForListType<TModel, TInnerProperty, TInput>(Func<TModel, TInput, TInnerProperty> parser) {
_property.Parser = (o, s) => parser.Invoke((TModel)o, (TInput)s); _property.Parser = (o, s) => parser.Invoke((TModel)o, (TInput)s);
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> DisplayProperty<TListingProperty>(Expression<Func<TProperty, TListingProperty>> propertyExpression) { public IAdminPropertyGenerator<TProperty, TModel> DisplayProperty(Expression<Func<TProperty, object>> propertyExpression) {
var property = AdminPageGenerator<object>.GetPropertyInfo(propertyExpression); var property = AdminPageGenerator<object>.GetPropertyInfo(propertyExpression);
_property.DisplayPropertyName = property.Name; _property.DisplayPropertyName = property.Name;
return this; return this;
} }
public IAdminPropertyGenerator<TProperty> DisplayPropertyForListType<TInnerProperty>(Expression<Func<TInnerProperty, object>> propertyExpression) { public IAdminPropertyGenerator<TProperty, TModel> DisplayProperty<TInnerProperty>(Expression<Func<TInnerProperty, object>> propertyExpression) {
var property = AdminPageGenerator<object>.GetPropertyInfo(propertyExpression); var property = AdminPageGenerator<object>.GetPropertyInfo(propertyExpression);
_property.DisplayPropertyName = property.Name; _property.DisplayPropertyName = property.Name;
return this; return this;

View File

@@ -40,8 +40,8 @@ public class HopAdminContext : AdminPagesContext {
generator.Page<User>().Property(u => u.Permissions) generator.Page<User>().Property(u => u.Permissions)
.DisplayInListing(false) .DisplayInListing(false)
.DisplayPropertyForListType<Permission>(p => p.PermissionName) .DisplayProperty<Permission>(p => p.PermissionName)
.ParserForListType<User, Permission>((user, perm) => new Permission { .Parser<string, Permission>((user, perm) => new Permission {
GrantedAt = DateTime.Now, GrantedAt = DateTime.Now,
PermissionName = perm, PermissionName = perm,
User = user User = user
@@ -78,8 +78,8 @@ public class HopAdminContext : AdminPagesContext {
generator.Page<PermissionGroup>().Property(g => g.Permissions) generator.Page<PermissionGroup>().Property(g => g.Permissions)
.DisplayInListing(false) .DisplayInListing(false)
.DisplayPropertyForListType<Permission>(p => p.PermissionName) .DisplayProperty<Permission>(p => p.PermissionName)
.ParserForListType<PermissionGroup, Permission>((group, perm) => new Permission { .Parser<string, Permission>((group, perm) => new Permission {
GrantedAt = DateTime.Now, GrantedAt = DateTime.Now,
PermissionName = perm, PermissionName = perm,
Group = group Group = group

View File

@@ -25,7 +25,7 @@ public class AdminContext : AdminPagesContext {
generator.Page<Address>() generator.Page<Address>()
.Property(a => a.AddressId) .Property(a => a.AddressId)
.IsSelector<Employee>() .IsSelector<Employee>()
.Parser<Address, Employee>((model, e) => model.AddressId = e.EmployeeId); .Parser<Employee>((model, e) => model.AddressId = e.EmployeeId);
generator.Page<Employee>() generator.Page<Employee>()
.ConfigureRepository<EmployeeProvider>() .ConfigureRepository<EmployeeProvider>()