finished list input + added proper prefix rendering
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AList_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fb7208b3f72528d22781d25fde9a55271bdf2b5aade4f03b1324579a25493cd8_003FList_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/Environment/AssemblyExplorer/XmlDocument/@EntryValue"><AssemblyExplorer>
|
<s:String x:Key="/Default/Environment/AssemblyExplorer/XmlDocument/@EntryValue"><AssemblyExplorer>
|
||||||
<Assembly Path="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\7.0.16\ref\net7.0\System.ComponentModel.Annotations.dll" />
|
<Assembly Path="C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\7.0.16\ref\net7.0\System.ComponentModel.Annotations.dll" />
|
||||||
<Assembly Path="C:\Users\Remote\.nuget\packages\blazorstrap\5.2.100.61524\lib\net7.0\BlazorStrap.dll" />
|
<Assembly Path="C:\Users\Remote\.nuget\packages\blazorstrap\5.2.100.61524\lib\net7.0\BlazorStrap.dll" />
|
||||||
|
|||||||
@@ -17,6 +17,6 @@ public class PermissionGroup : IPermissionOwner {
|
|||||||
[Required]
|
[Required]
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
public virtual IList<Permission> Permissions { get; set; }
|
public virtual List<Permission> Permissions { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -20,9 +20,9 @@ public class User : IPermissionOwner {
|
|||||||
[Required]
|
[Required]
|
||||||
public DateTime CreatedAt { get; set; }
|
public DateTime CreatedAt { get; set; }
|
||||||
|
|
||||||
public virtual IList<Permission> Permissions { get; set; }
|
public virtual List<Permission> Permissions { get; set; }
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public virtual IList<Token> Tokens { get; set; }
|
public virtual List<Token> Tokens { get; set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -17,6 +17,8 @@ public interface IAdminPropertyGenerator<TProperty> {
|
|||||||
IAdminPropertyGenerator<TProperty> Prefix(string prefix);
|
IAdminPropertyGenerator<TProperty> Prefix(string prefix);
|
||||||
IAdminPropertyGenerator<TProperty> Validator(Func<object, bool> validator);
|
IAdminPropertyGenerator<TProperty> Validator(Func<object, bool> validator);
|
||||||
IAdminPropertyGenerator<TProperty> IsSelector<TSelector>();
|
IAdminPropertyGenerator<TProperty> IsSelector<TSelector>();
|
||||||
|
IAdminPropertyGenerator<TProperty> Parser<TModel>(Func<TModel, string, TProperty> parser);
|
||||||
|
IAdminPropertyGenerator<TProperty> ParserForListType<TModel, TInnerProperty>(Func<TModel, string, TInnerProperty> parser);
|
||||||
IAdminPropertyGenerator<TProperty> DisplayProperty<TListingProperty>(Expression<Func<TProperty, TListingProperty>> propertyExpression);
|
IAdminPropertyGenerator<TProperty> DisplayProperty<TListingProperty>(Expression<Func<TProperty, TListingProperty>> propertyExpression);
|
||||||
IAdminPropertyGenerator<TProperty> DisplayPropertyForListType<TInnerProperty>(Expression<Func<TInnerProperty, object>> propertyExpression);
|
IAdminPropertyGenerator<TProperty> DisplayPropertyForListType<TInnerProperty>(Expression<Func<TInnerProperty, object>> propertyExpression);
|
||||||
|
|
||||||
|
|||||||
@@ -76,6 +76,16 @@ internal sealed class AdminPropertyGenerator<TProperty>(string name, Type type)
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IAdminPropertyGenerator<TProperty> Parser<TModel>(Func<TModel, string, TProperty> parser) {
|
||||||
|
_property.Parser = (o, s) => parser.Invoke((TModel)o, s);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAdminPropertyGenerator<TProperty> ParserForListType<TModel, TInnerProperty>(Func<TModel, string, TInnerProperty> parser) {
|
||||||
|
_property.Parser = (o, s) => parser.Invoke((TModel)o, s);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public IAdminPropertyGenerator<TProperty> DisplayProperty<TListingProperty>(Expression<Func<TProperty, TListingProperty>> propertyExpression) {
|
public IAdminPropertyGenerator<TProperty> DisplayProperty<TListingProperty>(Expression<Func<TProperty, TListingProperty>> propertyExpression) {
|
||||||
var property = AdminPageGenerator<object>.GetPropertyInfo(propertyExpression);
|
var property = AdminPageGenerator<object>.GetPropertyInfo(propertyExpression);
|
||||||
_property.DisplayPropertyName = property.Name;
|
_property.DisplayPropertyName = property.Name;
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ public sealed class AdminPageProperty {
|
|||||||
public Type SelectorType { get; set; }
|
public Type SelectorType { get; set; }
|
||||||
|
|
||||||
public Func<object, bool> Validator { get; set; }
|
public Func<object, bool> Validator { get; set; }
|
||||||
|
public Func<object, string, object> Parser { get; set; }
|
||||||
|
|
||||||
public object GetValue(object entry) {
|
public object GetValue(object entry) {
|
||||||
return entry.GetType().GetProperty(Name)?.GetValue(entry);
|
return entry.GetType().GetProperty(Name)?.GetValue(entry);
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
@using BlazorStrap.Shared.Components.Modal
|
@using BlazorStrap.Shared.Components.Modal
|
||||||
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||||
@using BlazorStrap.V5
|
@using BlazorStrap.V5
|
||||||
|
@using CurrieTechnologies.Razor.SweetAlert2
|
||||||
|
@using HopFrame.Database.Repositories
|
||||||
|
@using HopFrame.Security.Claims
|
||||||
@using HopFrame.Web.Admin
|
@using HopFrame.Web.Admin
|
||||||
@using HopFrame.Web.Admin.Models
|
@using HopFrame.Web.Admin.Models
|
||||||
@using HopFrame.Web.Admin.Providers
|
@using HopFrame.Web.Admin.Providers
|
||||||
@@ -22,7 +25,7 @@
|
|||||||
|
|
||||||
<BSModalContent>
|
<BSModalContent>
|
||||||
@foreach (var prop in GetEditableProperties()) {
|
@foreach (var prop in GetEditableProperties()) {
|
||||||
@if (!_isEdit && !prop.Editable) continue;
|
@if (!_isEdit && prop.Generated) continue;
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
@if (IsListType(prop)) {
|
@if (IsListType(prop)) {
|
||||||
@@ -42,10 +45,12 @@
|
|||||||
</BSListGroup>
|
</BSListGroup>
|
||||||
</BSListGroupItem>
|
</BSListGroupItem>
|
||||||
<BSListGroupItem>
|
<BSListGroupItem>
|
||||||
<div style="display: flex; gap: 20px">
|
<div>
|
||||||
@if (prop.SelectorType is null) {
|
@if (prop.SelectorType is null) {
|
||||||
<input type="text" class="form-control" @onchange="v => _inputValues[prop] = (string)v.Value"/>
|
<form style="display: flex; gap: 20px" @onsubmit="() => AddListItem(prop)">
|
||||||
<BSButton Color="BSColor.Secondary">Add</BSButton>
|
<input type="text" class="form-control" @onchange="v => _inputValues[prop] = (string)v.Value" required/>
|
||||||
|
<BSButton Color="BSColor.Secondary" IsSubmit="true">Add</BSButton>
|
||||||
|
</form>
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@*<BSInput InputType="InputType.Select"> TODO: implement selector
|
@*<BSInput InputType="InputType.Select"> TODO: implement selector
|
||||||
@@ -69,6 +74,12 @@
|
|||||||
<input class="form-check-input" type="checkbox" checked="@_values[prop]" @onchange="e => _values[prop] = Convert.ToBoolean(e.Value)">
|
<input class="form-check-input" type="checkbox" checked="@_values[prop]" @onchange="e => _values[prop] = Convert.ToBoolean(e.Value)">
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
else if (prop.Prefix is not null && !_isEdit) {
|
||||||
|
<BSInputGroup>
|
||||||
|
<span class="@BS.Input_Group_Text">@prop.Prefix</span>
|
||||||
|
<input type="text" class="form-control" disabled="@IsDisabled(prop)" required="@IsRequired(prop)" value="@GetPropertyValue(prop)" @onchange="e => _values[prop] = prop.Prefix + e.Value"/>
|
||||||
|
</BSInputGroup>
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
<BSLabel>@prop.DisplayName</BSLabel>
|
<BSLabel>@prop.DisplayName</BSLabel>
|
||||||
<input type="@GetInputType(prop)" class="form-control" disabled="@IsDisabled(prop)" required="@IsRequired(prop)" value="@GetPropertyValue(prop)" @onchange="e => _values[prop] = e.Value"/>
|
<input type="@GetInputType(prop)" class="form-control" disabled="@IsDisabled(prop)" required="@IsRequired(prop)" value="@GetPropertyValue(prop)" @onchange="e => _values[prop] = e.Value"/>
|
||||||
@@ -86,6 +97,9 @@
|
|||||||
|
|
||||||
@inject IServiceProvider Provider
|
@inject IServiceProvider Provider
|
||||||
@inject IAdminPagesProvider PageProvider
|
@inject IAdminPagesProvider PageProvider
|
||||||
|
@inject SweetAlertService Alerts
|
||||||
|
@inject IPermissionRepository Permissions
|
||||||
|
@inject ITokenContext Auth
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
[Parameter]
|
[Parameter]
|
||||||
@@ -129,15 +143,16 @@
|
|||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsDisabled(AdminPageProperty prop) => !prop.Editable;
|
private bool IsDisabled(AdminPageProperty prop) => (_isEdit && !prop.Editable) || prop.Generated;
|
||||||
private bool IsRequired(AdminPageProperty prop) => !_isEdit ? prop.Required : prop.Required && prop.EditDisplayValue;
|
private bool IsRequired(AdminPageProperty prop) => !_isEdit ? prop.Required : prop.Required && prop.EditDisplayValue;
|
||||||
private bool IsSwitch(AdminPageProperty prop) => prop.Type == typeof(bool);
|
private bool IsSwitch(AdminPageProperty prop) => prop.Type == typeof(bool);
|
||||||
|
|
||||||
private bool IsListType(AdminPageProperty prop) {
|
private bool IsListType(AdminPageProperty prop) {
|
||||||
if (!prop.Type.IsGenericType) return false;
|
if (!prop.Type.IsGenericType) return false;
|
||||||
var generic = prop.Type.GenericTypeArguments[0];
|
var generic = prop.Type.GenericTypeArguments[0];
|
||||||
var listType = typeof(IList<>).MakeGenericType(generic);
|
var gListType = typeof(IList<>).MakeGenericType(generic);
|
||||||
return prop.Type.IsAssignableFrom(listType);
|
var iListType = typeof(List<>).MakeGenericType(generic);
|
||||||
|
return prop.Type.IsAssignableFrom(gListType) || prop.Type.IsAssignableFrom(iListType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IList<string> GetListPropertyValues(AdminPageProperty prop) {
|
private IList<string> GetListPropertyValues(AdminPageProperty prop) {
|
||||||
@@ -178,13 +193,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (type.GetProperties().Any(p => p.GetCustomAttributes(false).Any(a => a is ListingPropertyAttribute))) {
|
|
||||||
var prop = type.GetProperties()
|
|
||||||
.SingleOrDefault(p => p.GetCustomAttributes(false).Any(a => a is ListingPropertyAttribute));
|
|
||||||
|
|
||||||
return MapPropertyValue(prop?.GetValue(value), property);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(property.DisplayPropertyName) && !isSubProperty) {
|
if (!string.IsNullOrEmpty(property.DisplayPropertyName) && !isSubProperty) {
|
||||||
var prop = type.GetProperties()
|
var prop = type.GetProperties()
|
||||||
.SingleOrDefault(p => p.Name == property.DisplayPropertyName);
|
.SingleOrDefault(p => p.Name == property.DisplayPropertyName);
|
||||||
@@ -213,25 +221,76 @@
|
|||||||
if (value.Key.Validator is null) continue;
|
if (value.Key.Validator is null) continue;
|
||||||
if (value.Key.Validator?.Invoke(value.Value) == true) continue;
|
if (value.Key.Validator?.Invoke(value.Value) == true) continue;
|
||||||
Console.WriteLine("INVALID");
|
Console.WriteLine("INVALID");
|
||||||
|
//TODO: implement validation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeleteListItem(AdminPageProperty prop, int index) {
|
private void DeleteListItem(AdminPageProperty prop, int index) {
|
||||||
Console.WriteLine(index);
|
|
||||||
var list = prop.GetValue<IList>(_entry);
|
var list = prop.GetValue<IList>(_entry);
|
||||||
list.RemoveAt(index);
|
list.RemoveAt(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AddListItem(AdminPageProperty prop) {
|
||||||
|
if (!_inputValues.TryGetValue(prop, out var input)) {
|
||||||
|
Alerts.FireAsync(new SweetAlertOptions {
|
||||||
|
Title = "Error!",
|
||||||
|
Text = "Please enter a value!",
|
||||||
|
Icon = SweetAlertIcon.Error
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var list = prop.GetValue<IList>(_entry);
|
||||||
|
var value = prop.Parser?.Invoke(_entry, input) ?? input;
|
||||||
|
list?.Add(value);
|
||||||
|
}
|
||||||
|
|
||||||
private async void Save() {
|
private async void Save() {
|
||||||
|
if (_isEdit && _currentPage.Permissions.Update is not null) {
|
||||||
|
if (!await Permissions.HasPermission(Auth.User, _currentPage.Permissions.Update)) {
|
||||||
|
await Alerts.FireAsync(new SweetAlertOptions {
|
||||||
|
Title = "Unauthorized!",
|
||||||
|
Text = "You don't have the required permissions to edit an entry!",
|
||||||
|
Icon = SweetAlertIcon.Error
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}else if (_currentPage.Permissions.Create is not null) {
|
||||||
|
if (!await Permissions.HasPermission(Auth.User, _currentPage.Permissions.Create)) {
|
||||||
|
await Alerts.FireAsync(new SweetAlertOptions {
|
||||||
|
Title = "Unauthorized!",
|
||||||
|
Text = "You don't have the required permissions to add an entry!",
|
||||||
|
Icon = SweetAlertIcon.Error
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var value in _values) {
|
foreach (var value in _values) {
|
||||||
value.Key.SetValue(_entry, value.Value);
|
if (IsListType(value.Key)) continue;
|
||||||
|
value.Key.SetValue(_entry, value.Key.Parser?.Invoke(_entry, (string)value.Value) ?? value.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_isEdit) {
|
if (!_isEdit) {
|
||||||
await _repository.CreateO(_entry);
|
await _repository.CreateO(_entry);
|
||||||
|
|
||||||
|
await Alerts.FireAsync(new SweetAlertOptions {
|
||||||
|
Title = "New entry added!",
|
||||||
|
Icon = SweetAlertIcon.Success,
|
||||||
|
ShowConfirmButton = false,
|
||||||
|
Timer = 1500
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
await _repository.UpdateO(_entry);
|
await _repository.UpdateO(_entry);
|
||||||
|
|
||||||
|
await Alerts.FireAsync(new SweetAlertOptions {
|
||||||
|
Title = "Entry updated!",
|
||||||
|
Icon = SweetAlertIcon.Success,
|
||||||
|
ShowConfirmButton = false,
|
||||||
|
Timer = 1500
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
await ReloadDelegate.Invoke();
|
await ReloadDelegate.Invoke();
|
||||||
|
|||||||
@@ -30,8 +30,18 @@ public class HopAdminContext : AdminPagesContext {
|
|||||||
|
|
||||||
generator.Page<User>().Property(u => u.Permissions)
|
generator.Page<User>().Property(u => u.Permissions)
|
||||||
.DisplayInListing(false)
|
.DisplayInListing(false)
|
||||||
.IsSelector<PermissionGroup>()
|
.DisplayPropertyForListType<Permission>(p => p.PermissionName)
|
||||||
.DisplayPropertyForListType<Permission>(p => p.PermissionName);
|
.ParserForListType<User, Permission>((user, perm) => new Permission {
|
||||||
|
GrantedAt = DateTime.Now,
|
||||||
|
PermissionName = perm,
|
||||||
|
User = user
|
||||||
|
});
|
||||||
|
|
||||||
|
generator.Page<User>().Property(u => u.CreatedAt)
|
||||||
|
.Generated();
|
||||||
|
|
||||||
|
generator.Page<User>().Property(u => u.Id)
|
||||||
|
.Generated();
|
||||||
|
|
||||||
generator.Page<User>().Property(u => u.Tokens)
|
generator.Page<User>().Property(u => u.Tokens)
|
||||||
.Ignore();
|
.Ignore();
|
||||||
@@ -49,13 +59,19 @@ public class HopAdminContext : AdminPagesContext {
|
|||||||
.Prefix("group.");
|
.Prefix("group.");
|
||||||
|
|
||||||
generator.Page<PermissionGroup>().Property(g => g.IsDefaultGroup)
|
generator.Page<PermissionGroup>().Property(g => g.IsDefaultGroup)
|
||||||
|
.DisplayName("Default Group")
|
||||||
.Sortable(false);
|
.Sortable(false);
|
||||||
|
|
||||||
generator.Page<PermissionGroup>().Property(g => g.CreatedAt)
|
generator.Page<PermissionGroup>().Property(g => g.CreatedAt)
|
||||||
.Editable(false);
|
.Generated();
|
||||||
|
|
||||||
generator.Page<PermissionGroup>().Property(g => g.Permissions)
|
generator.Page<PermissionGroup>().Property(g => g.Permissions)
|
||||||
.DisplayInListing(false)
|
.DisplayInListing(false)
|
||||||
.DisplayPropertyForListType<Permission>(p => p.PermissionName);
|
.DisplayPropertyForListType<Permission>(p => p.PermissionName)
|
||||||
|
.ParserForListType<PermissionGroup, Permission>((group, perm) => new Permission {
|
||||||
|
GrantedAt = DateTime.Now,
|
||||||
|
PermissionName = perm,
|
||||||
|
Group = group
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,9 +130,9 @@
|
|||||||
_currentSortProperty = _pageData.DefaultSortPropertyName;
|
_currentSortProperty = _pageData.DefaultSortPropertyName;
|
||||||
_currentSortDirection = _pageData.DefaultSortDirection;
|
_currentSortDirection = _pageData.DefaultSortDirection;
|
||||||
|
|
||||||
_modelRepository = Provider.GetService(_pageData.RepositoryProvider) as IModelRepository;
|
if (_pageData.RepositoryProvider is null)
|
||||||
if (_modelRepository is null)
|
|
||||||
throw new ArgumentException($"AdminPage '{_pageData.Title}' does not specify a model repository!'");
|
throw new ArgumentException($"AdminPage '{_pageData.Title}' does not specify a model repository!'");
|
||||||
|
_modelRepository = Provider.GetService(_pageData.RepositoryProvider) as IModelRepository;
|
||||||
|
|
||||||
_hasEditPermission = await Permissions.HasPermission(Auth.User, _pageData.Permissions.Update);
|
_hasEditPermission = await Permissions.HasPermission(Auth.User, _pageData.Permissions.Update);
|
||||||
_hasDeletePermission = await Permissions.HasPermission(Auth.User, _pageData.Permissions.Delete);
|
_hasDeletePermission = await Permissions.HasPermission(Auth.User, _pageData.Permissions.Delete);
|
||||||
|
|||||||
Reference in New Issue
Block a user