Started working on admin page modal
This commit is contained in:
@@ -13,5 +13,6 @@ public interface IAdminPropertyGenerator {
|
||||
IAdminPropertyGenerator DisplayName(string displayName);
|
||||
IAdminPropertyGenerator Description(string description);
|
||||
IAdminPropertyGenerator Prefix(string prefix);
|
||||
IAdminPropertyGenerator Validator(Func<object, bool> validator);
|
||||
|
||||
}
|
||||
@@ -14,7 +14,8 @@ internal sealed class AdminPageGenerator<TModel> : IAdminPageGenerator<TModel>,
|
||||
|
||||
public AdminPageGenerator() {
|
||||
Page = new AdminPage<TModel> {
|
||||
Permissions = new AdminPagePermissions()
|
||||
Permissions = new AdminPagePermissions(),
|
||||
ModelType = typeof(TModel)
|
||||
};
|
||||
_propertyGenerators = new Dictionary<string, AdminPropertyGenerator>();
|
||||
|
||||
|
||||
@@ -65,6 +65,11 @@ internal sealed class AdminPropertyGenerator(string name, Type type) : IAdminPro
|
||||
return this;
|
||||
}
|
||||
|
||||
public IAdminPropertyGenerator Validator(Func<object, bool> validator) {
|
||||
_property.Validator = validator;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AdminPageProperty Compile() {
|
||||
_property.DisplayName ??= _property.Name;
|
||||
return _property;
|
||||
@@ -111,6 +116,10 @@ internal sealed class AdminPropertyGenerator(string name, Type type) : IAdminPro
|
||||
Bold(attribute?.Bold == true);
|
||||
}
|
||||
|
||||
if (attributes.Any(a => a is RequiredAttribute)) {
|
||||
_property.Required = true;
|
||||
}
|
||||
|
||||
if (attributes.Any(a => a is AdminPrefixAttribute)) {
|
||||
var attribute = attributes.Single(a => a is AdminPrefixAttribute) as AdminPrefixAttribute;
|
||||
Prefix(attribute?.Prefix);
|
||||
|
||||
@@ -15,6 +15,8 @@ public class AdminPage {
|
||||
[JsonIgnore]
|
||||
public Type RepositoryProvider { get; set; }
|
||||
|
||||
public Type ModelType { get; set; }
|
||||
|
||||
public string DefaultSortPropertyName { get; set; }
|
||||
public ListSortDirection DefaultSortDirection { get; set; }
|
||||
|
||||
|
||||
@@ -13,8 +13,23 @@ public sealed class AdminPageProperty {
|
||||
public bool Editable { get; set; } = true;
|
||||
public bool EditDisplayValue { get; set; } = true;
|
||||
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; }
|
||||
[JsonIgnore]
|
||||
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>
|
||||
<AuthorizedView Permission="@_pageData.Permissions.View" RedirectIfUnauthorized="administration/login" />
|
||||
|
||||
<AdminPageModal ReloadDelegate="Reload" @ref="_modal"/>
|
||||
|
||||
<div class="title">
|
||||
<h3>
|
||||
@_pageData.Title administration
|
||||
@@ -63,9 +65,16 @@
|
||||
@foreach (var entry in _displayedModels) {
|
||||
<BSTR>
|
||||
@foreach (var prop in GetListingProperties()) {
|
||||
<BSTD Class="@GetClass(prop)">
|
||||
@GetValue(entry, prop)
|
||||
</BSTD>
|
||||
@if (prop.Bold) {
|
||||
<BSTD Class="bold">
|
||||
@GetPrintableValue(entry, prop)
|
||||
</BSTD>
|
||||
}
|
||||
else {
|
||||
<BSTD>
|
||||
@GetPrintableValue(entry, prop)
|
||||
</BSTD>
|
||||
}
|
||||
}
|
||||
|
||||
@if (_hasEditPermission || _hasDeletePermission) {
|
||||
@@ -105,6 +114,7 @@
|
||||
private AdminPage _pageData;
|
||||
private IModelRepository _modelRepository;
|
||||
private IEnumerable<object> _modelBuffer;
|
||||
private AdminPageModal _modal;
|
||||
|
||||
private bool _hasEditPermission;
|
||||
private bool _hasDeletePermission;
|
||||
@@ -114,14 +124,12 @@
|
||||
private DateTime _lastSearch;
|
||||
private IList<object> _displayedModels;
|
||||
|
||||
protected override void OnInitialized() {
|
||||
protected override async Task OnInitializedAsync() {
|
||||
_pageData = Pages.LoadAdminPage(Url);
|
||||
|
||||
_currentSortProperty = _pageData.DefaultSortPropertyName;
|
||||
_currentSortDirection = _pageData.DefaultSortDirection;
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
_modelRepository = Provider.GetService(_pageData.RepositoryProvider) as IModelRepository;
|
||||
if (_modelRepository is null)
|
||||
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);
|
||||
_hasDeletePermission = await Permissions.HasPermission(Auth.User, _pageData.Permissions.Delete);
|
||||
|
||||
Reload();
|
||||
await Reload();
|
||||
}
|
||||
|
||||
private IList<AdminPageProperty> GetListingProperties() {
|
||||
@@ -139,7 +147,7 @@
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private async void Reload() {
|
||||
private async Task Reload() {
|
||||
_modelBuffer = await _modelRepository.ReadAllO();
|
||||
_displayedModels = _modelBuffer.ToList();
|
||||
|
||||
@@ -157,15 +165,15 @@
|
||||
var prop = GetListingProperties()
|
||||
.SingleOrDefault(p => p.Name == property);
|
||||
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 dateY = (DateTime) y.GetType().GetProperty(prop.Name)?.GetValue(y)!;
|
||||
|
||||
return DateTime.Compare(dateX, dateY);
|
||||
}
|
||||
|
||||
var propX = GetValue(x, prop);
|
||||
var propY = GetValue(y, prop);
|
||||
var propX = GetPrintableValue(x, prop);
|
||||
var propY = GetPrintableValue(y, prop);
|
||||
|
||||
return String.CompareOrdinal(propX, propY);
|
||||
});
|
||||
@@ -198,7 +206,7 @@
|
||||
var props = GetListingProperties();
|
||||
|
||||
_displayedModels = _modelBuffer
|
||||
.Where(model => props.Any(prop => GetValue(model, prop).Contains(search)))
|
||||
.Where(model => props.Any(prop => GetPrintableValue(model, prop).Contains(search)))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
@@ -206,29 +214,25 @@
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private string GetValue(object entry, AdminPageProperty property) {
|
||||
object propValue = entry.GetType().GetProperty(property.Name)?.GetValue(entry);
|
||||
private static string GetPrintableValue(object element, AdminPageProperty prop) {
|
||||
var entry = prop.GetValue(element);
|
||||
|
||||
return propValue?.ToString();
|
||||
}
|
||||
//TODO: convert relational types
|
||||
|
||||
private string GetClass(AdminPageProperty property) {
|
||||
if (property.Bold)
|
||||
return "bold";
|
||||
return "";
|
||||
return entry?.ToString();
|
||||
}
|
||||
|
||||
private async void Create() {
|
||||
//TODO: Open create modal
|
||||
await _modal.Show(_pageData);
|
||||
}
|
||||
|
||||
private async void Edit(object entry) {
|
||||
//TODO: Open edit modal
|
||||
await _modal.Show(_pageData, entry);
|
||||
}
|
||||
|
||||
private async void Delete(object entry) {
|
||||
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!",
|
||||
Icon = SweetAlertIcon.Warning,
|
||||
ConfirmButtonText = "Yes",
|
||||
@@ -238,7 +242,7 @@
|
||||
|
||||
if (result.IsConfirmed) {
|
||||
await _modelRepository.DeleteO(entry);
|
||||
Reload();
|
||||
await Reload();
|
||||
|
||||
await Alerts.FireAsync(new SweetAlertOptions {
|
||||
Title = "Deleted!",
|
||||
|
||||
Reference in New Issue
Block a user