Started working on admin page modal
This commit is contained in:
@@ -13,5 +13,6 @@ public interface IAdminPropertyGenerator {
|
|||||||
IAdminPropertyGenerator DisplayName(string displayName);
|
IAdminPropertyGenerator DisplayName(string displayName);
|
||||||
IAdminPropertyGenerator Description(string description);
|
IAdminPropertyGenerator Description(string description);
|
||||||
IAdminPropertyGenerator Prefix(string prefix);
|
IAdminPropertyGenerator Prefix(string prefix);
|
||||||
|
IAdminPropertyGenerator Validator(Func<object, bool> validator);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -14,7 +14,8 @@ internal sealed class AdminPageGenerator<TModel> : IAdminPageGenerator<TModel>,
|
|||||||
|
|
||||||
public AdminPageGenerator() {
|
public AdminPageGenerator() {
|
||||||
Page = new AdminPage<TModel> {
|
Page = new AdminPage<TModel> {
|
||||||
Permissions = new AdminPagePermissions()
|
Permissions = new AdminPagePermissions(),
|
||||||
|
ModelType = typeof(TModel)
|
||||||
};
|
};
|
||||||
_propertyGenerators = new Dictionary<string, AdminPropertyGenerator>();
|
_propertyGenerators = new Dictionary<string, AdminPropertyGenerator>();
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,11 @@ internal sealed class AdminPropertyGenerator(string name, Type type) : IAdminPro
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IAdminPropertyGenerator Validator(Func<object, bool> validator) {
|
||||||
|
_property.Validator = validator;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public AdminPageProperty Compile() {
|
public AdminPageProperty Compile() {
|
||||||
_property.DisplayName ??= _property.Name;
|
_property.DisplayName ??= _property.Name;
|
||||||
return _property;
|
return _property;
|
||||||
@@ -111,6 +116,10 @@ internal sealed class AdminPropertyGenerator(string name, Type type) : IAdminPro
|
|||||||
Bold(attribute?.Bold == true);
|
Bold(attribute?.Bold == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attributes.Any(a => a is RequiredAttribute)) {
|
||||||
|
_property.Required = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (attributes.Any(a => a is AdminPrefixAttribute)) {
|
if (attributes.Any(a => a is AdminPrefixAttribute)) {
|
||||||
var attribute = attributes.Single(a => a is AdminPrefixAttribute) as AdminPrefixAttribute;
|
var attribute = attributes.Single(a => a is AdminPrefixAttribute) as AdminPrefixAttribute;
|
||||||
Prefix(attribute?.Prefix);
|
Prefix(attribute?.Prefix);
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ public class AdminPage {
|
|||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public Type RepositoryProvider { get; set; }
|
public Type RepositoryProvider { get; set; }
|
||||||
|
|
||||||
|
public Type ModelType { get; set; }
|
||||||
|
|
||||||
public string DefaultSortPropertyName { get; set; }
|
public string DefaultSortPropertyName { get; set; }
|
||||||
public ListSortDirection DefaultSortDirection { get; set; }
|
public ListSortDirection DefaultSortDirection { get; set; }
|
||||||
|
|||||||
@@ -13,8 +13,23 @@ public sealed class AdminPageProperty {
|
|||||||
public bool Editable { get; set; } = true;
|
public bool Editable { get; set; } = true;
|
||||||
public bool EditDisplayValue { get; set; } = true;
|
public bool EditDisplayValue { get; set; } = true;
|
||||||
public bool Generated { get; set; }
|
public bool Generated { get; set; }
|
||||||
public bool Bold { get; set; } = false;
|
public bool Bold { get; set; }
|
||||||
|
public bool Required { get; set; }
|
||||||
public bool Ignore { get; set; }
|
public bool Ignore { get; set; }
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
public Type Type { get; set; }
|
public Type Type { get; set; }
|
||||||
|
|
||||||
|
public Func<object, bool> Validator { get; set; }
|
||||||
|
|
||||||
|
public object GetValue(object entry) {
|
||||||
|
return entry.GetType().GetProperty(Name)?.GetValue(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T GetValue<T>(object entry) {
|
||||||
|
return (T)entry.GetType().GetProperty(Name)?.GetValue(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetValue(object entry, object value) {
|
||||||
|
entry.GetType().GetProperty(Name)?.SetValue(entry, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
119
src/HopFrame.Web/Components/Administration/AdminPageModal.razor
Normal file
119
src/HopFrame.Web/Components/Administration/AdminPageModal.razor
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
@rendermode InteractiveServer
|
||||||
|
|
||||||
|
@using BlazorStrap
|
||||||
|
@using BlazorStrap.Shared.Components.Modal
|
||||||
|
@using static Microsoft.AspNetCore.Components.Web.RenderMode
|
||||||
|
@using BlazorStrap.V5
|
||||||
|
@using HopFrame.Web.Admin
|
||||||
|
@using HopFrame.Web.Admin.Models
|
||||||
|
@using Microsoft.AspNetCore.Components.Forms
|
||||||
|
@using Microsoft.AspNetCore.Components.Web
|
||||||
|
|
||||||
|
<BSModal DataId="admin-page-modal" HideOnValidSubmit="true" IsStaticBackdrop="true" @ref="_modal">
|
||||||
|
<BSForm TValue="object" EditContext="_context" OnValidSubmit="Save">
|
||||||
|
@if (!_isEdit) {
|
||||||
|
<BSModalHeader>Create entry</BSModalHeader>
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
<BSModalHeader>Edit entry</BSModalHeader>
|
||||||
|
}
|
||||||
|
|
||||||
|
<BSModalContent>
|
||||||
|
@foreach (var prop in GetEditableProperties()) {
|
||||||
|
@if (!_isEdit && !prop.Editable) continue;
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<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"/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</BSModalContent>
|
||||||
|
|
||||||
|
<BSModalFooter>
|
||||||
|
<BSButton Target="admin-page-modal">Cancel</BSButton>
|
||||||
|
<BSButton IsSubmit="true" Color="BSColor.Primary">Save</BSButton>
|
||||||
|
</BSModalFooter>
|
||||||
|
</BSForm>
|
||||||
|
</BSModal>
|
||||||
|
|
||||||
|
@inject IServiceProvider Provider
|
||||||
|
|
||||||
|
@code {
|
||||||
|
[Parameter]
|
||||||
|
public Func<Task> ReloadDelegate { get; set; }
|
||||||
|
|
||||||
|
private BSModalBase _modal;
|
||||||
|
private EditContext _context;
|
||||||
|
private IDictionary<AdminPageProperty, object> _values;
|
||||||
|
private IModelRepository _repository;
|
||||||
|
|
||||||
|
private AdminPage _currentPage;
|
||||||
|
private object _entry;
|
||||||
|
private bool _isEdit;
|
||||||
|
|
||||||
|
public async Task Show(AdminPage page, object entryToEdit = null) {
|
||||||
|
_entry = null;
|
||||||
|
|
||||||
|
_currentPage = page;
|
||||||
|
_entry = entryToEdit;
|
||||||
|
_isEdit = entryToEdit is not null;
|
||||||
|
_repository = Provider.GetService(_currentPage.RepositoryProvider) as IModelRepository;
|
||||||
|
|
||||||
|
_entry ??= Activator.CreateInstance(_currentPage.ModelType);
|
||||||
|
_context = new EditContext(_entry);
|
||||||
|
_context.OnValidationRequested += Validate;
|
||||||
|
|
||||||
|
_values = new Dictionary<AdminPageProperty, object>();
|
||||||
|
foreach (var property in _currentPage.Properties) {
|
||||||
|
_values.Add(property, property.GetValue(_entry));
|
||||||
|
}
|
||||||
|
|
||||||
|
await _modal.ShowAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private IList<AdminPageProperty> GetEditableProperties() {
|
||||||
|
return _currentPage.Properties
|
||||||
|
.Where(p => !p.Ignore)
|
||||||
|
.OrderBy(p => p.Editable)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsDisabled(AdminPageProperty prop) => !prop.Editable;
|
||||||
|
private bool IsRequired(AdminPageProperty prop) => !_isEdit ? prop.Required : prop.Required && prop.EditDisplayValue;
|
||||||
|
|
||||||
|
private string GetPropertyValue(AdminPageProperty property) {
|
||||||
|
if (!_isEdit) return "";
|
||||||
|
if (!property.EditDisplayValue) return "";
|
||||||
|
return property.GetValue(_entry)?.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetInputType(AdminPageProperty property) {
|
||||||
|
if (!property.EditDisplayValue)
|
||||||
|
return "password";
|
||||||
|
|
||||||
|
return "text";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Validate(object sender, ValidationRequestedEventArgs e) {
|
||||||
|
foreach (var value in _values) {
|
||||||
|
if (value.Key.Validator?.Invoke(value.Value) == true) continue;
|
||||||
|
Console.WriteLine("INVALID");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Save() {
|
||||||
|
foreach (var value in _values) {
|
||||||
|
value.Key.SetValue(_entry, value.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_isEdit) {
|
||||||
|
await _repository.CreateO(_entry);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await _repository.UpdateO(_entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReloadDelegate.Invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,8 @@
|
|||||||
<PageTitle>@_pageData.Title</PageTitle>
|
<PageTitle>@_pageData.Title</PageTitle>
|
||||||
<AuthorizedView Permission="@_pageData.Permissions.View" RedirectIfUnauthorized="administration/login" />
|
<AuthorizedView Permission="@_pageData.Permissions.View" RedirectIfUnauthorized="administration/login" />
|
||||||
|
|
||||||
|
<AdminPageModal ReloadDelegate="Reload" @ref="_modal"/>
|
||||||
|
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<h3>
|
<h3>
|
||||||
@_pageData.Title administration
|
@_pageData.Title administration
|
||||||
@@ -63,9 +65,16 @@
|
|||||||
@foreach (var entry in _displayedModels) {
|
@foreach (var entry in _displayedModels) {
|
||||||
<BSTR>
|
<BSTR>
|
||||||
@foreach (var prop in GetListingProperties()) {
|
@foreach (var prop in GetListingProperties()) {
|
||||||
<BSTD Class="@GetClass(prop)">
|
@if (prop.Bold) {
|
||||||
@GetValue(entry, prop)
|
<BSTD Class="bold">
|
||||||
</BSTD>
|
@GetPrintableValue(entry, prop)
|
||||||
|
</BSTD>
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
<BSTD>
|
||||||
|
@GetPrintableValue(entry, prop)
|
||||||
|
</BSTD>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (_hasEditPermission || _hasDeletePermission) {
|
@if (_hasEditPermission || _hasDeletePermission) {
|
||||||
@@ -105,6 +114,7 @@
|
|||||||
private AdminPage _pageData;
|
private AdminPage _pageData;
|
||||||
private IModelRepository _modelRepository;
|
private IModelRepository _modelRepository;
|
||||||
private IEnumerable<object> _modelBuffer;
|
private IEnumerable<object> _modelBuffer;
|
||||||
|
private AdminPageModal _modal;
|
||||||
|
|
||||||
private bool _hasEditPermission;
|
private bool _hasEditPermission;
|
||||||
private bool _hasDeletePermission;
|
private bool _hasDeletePermission;
|
||||||
@@ -114,14 +124,12 @@
|
|||||||
private DateTime _lastSearch;
|
private DateTime _lastSearch;
|
||||||
private IList<object> _displayedModels;
|
private IList<object> _displayedModels;
|
||||||
|
|
||||||
protected override void OnInitialized() {
|
protected override async Task OnInitializedAsync() {
|
||||||
_pageData = Pages.LoadAdminPage(Url);
|
_pageData = Pages.LoadAdminPage(Url);
|
||||||
|
|
||||||
_currentSortProperty = _pageData.DefaultSortPropertyName;
|
_currentSortProperty = _pageData.DefaultSortPropertyName;
|
||||||
_currentSortDirection = _pageData.DefaultSortDirection;
|
_currentSortDirection = _pageData.DefaultSortDirection;
|
||||||
}
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync() {
|
|
||||||
_modelRepository = Provider.GetService(_pageData.RepositoryProvider) as IModelRepository;
|
_modelRepository = Provider.GetService(_pageData.RepositoryProvider) as IModelRepository;
|
||||||
if (_modelRepository 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!'");
|
||||||
@@ -129,7 +137,7 @@
|
|||||||
_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);
|
||||||
|
|
||||||
Reload();
|
await Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
private IList<AdminPageProperty> GetListingProperties() {
|
private IList<AdminPageProperty> GetListingProperties() {
|
||||||
@@ -139,7 +147,7 @@
|
|||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Reload() {
|
private async Task Reload() {
|
||||||
_modelBuffer = await _modelRepository.ReadAllO();
|
_modelBuffer = await _modelRepository.ReadAllO();
|
||||||
_displayedModels = _modelBuffer.ToList();
|
_displayedModels = _modelBuffer.ToList();
|
||||||
|
|
||||||
@@ -157,15 +165,15 @@
|
|||||||
var prop = GetListingProperties()
|
var prop = GetListingProperties()
|
||||||
.SingleOrDefault(p => p.Name == property);
|
.SingleOrDefault(p => p.Name == property);
|
||||||
var comparer = Comparer<object>.Create((x, y) => {
|
var comparer = Comparer<object>.Create((x, y) => {
|
||||||
if (prop.Type == typeof(DateTime)) {
|
if (prop?.Type == typeof(DateTime)) {
|
||||||
DateTime dateX = (DateTime) x.GetType().GetProperty(prop.Name)?.GetValue(x)!;
|
DateTime dateX = (DateTime) x.GetType().GetProperty(prop.Name)?.GetValue(x)!;
|
||||||
DateTime dateY = (DateTime) y.GetType().GetProperty(prop.Name)?.GetValue(y)!;
|
DateTime dateY = (DateTime) y.GetType().GetProperty(prop.Name)?.GetValue(y)!;
|
||||||
|
|
||||||
return DateTime.Compare(dateX, dateY);
|
return DateTime.Compare(dateX, dateY);
|
||||||
}
|
}
|
||||||
|
|
||||||
var propX = GetValue(x, prop);
|
var propX = GetPrintableValue(x, prop);
|
||||||
var propY = GetValue(y, prop);
|
var propY = GetPrintableValue(y, prop);
|
||||||
|
|
||||||
return String.CompareOrdinal(propX, propY);
|
return String.CompareOrdinal(propX, propY);
|
||||||
});
|
});
|
||||||
@@ -198,7 +206,7 @@
|
|||||||
var props = GetListingProperties();
|
var props = GetListingProperties();
|
||||||
|
|
||||||
_displayedModels = _modelBuffer
|
_displayedModels = _modelBuffer
|
||||||
.Where(model => props.Any(prop => GetValue(model, prop).Contains(search)))
|
.Where(model => props.Any(prop => GetPrintableValue(model, prop).Contains(search)))
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,29 +214,25 @@
|
|||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetValue(object entry, AdminPageProperty property) {
|
private static string GetPrintableValue(object element, AdminPageProperty prop) {
|
||||||
object propValue = entry.GetType().GetProperty(property.Name)?.GetValue(entry);
|
var entry = prop.GetValue(element);
|
||||||
|
|
||||||
|
//TODO: convert relational types
|
||||||
|
|
||||||
return propValue?.ToString();
|
return entry?.ToString();
|
||||||
}
|
|
||||||
|
|
||||||
private string GetClass(AdminPageProperty property) {
|
|
||||||
if (property.Bold)
|
|
||||||
return "bold";
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Create() {
|
private async void Create() {
|
||||||
//TODO: Open create modal
|
await _modal.Show(_pageData);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Edit(object entry) {
|
private async void Edit(object entry) {
|
||||||
//TODO: Open edit modal
|
await _modal.Show(_pageData, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Delete(object entry) {
|
private async void Delete(object entry) {
|
||||||
var result = await Alerts.FireAsync(new SweetAlertOptions {
|
var result = await Alerts.FireAsync(new SweetAlertOptions {
|
||||||
Title = "Do you really want to delete this entry?",
|
Title = "Are you sure?",
|
||||||
Text = "You won't be able to revert this!",
|
Text = "You won't be able to revert this!",
|
||||||
Icon = SweetAlertIcon.Warning,
|
Icon = SweetAlertIcon.Warning,
|
||||||
ConfirmButtonText = "Yes",
|
ConfirmButtonText = "Yes",
|
||||||
@@ -238,7 +242,7 @@
|
|||||||
|
|
||||||
if (result.IsConfirmed) {
|
if (result.IsConfirmed) {
|
||||||
await _modelRepository.DeleteO(entry);
|
await _modelRepository.DeleteO(entry);
|
||||||
Reload();
|
await Reload();
|
||||||
|
|
||||||
await Alerts.FireAsync(new SweetAlertOptions {
|
await Alerts.FireAsync(new SweetAlertOptions {
|
||||||
Title = "Deleted!",
|
Title = "Deleted!",
|
||||||
|
|||||||
Reference in New Issue
Block a user