@rendermode InteractiveServer @using System.Collections @using BlazorStrap @using BlazorStrap.Shared.Components.Modal @using static Microsoft.AspNetCore.Components.Web.RenderMode @using BlazorStrap.V5 @using CurrieTechnologies.Razor.SweetAlert2 @using HopFrame.Database.Repositories @using HopFrame.Security.Claims @using HopFrame.Web.Admin @using HopFrame.Web.Admin.Models @using HopFrame.Web.Admin.Providers @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Web @if (!_isEdit) { Create entry } else { Edit entry } @foreach (var prop in GetEditableProperties()) { @if (!_isEdit && prop.Generated) continue;
@if (IsListType(prop)) { @prop.DisplayName @foreach (var element in GetListPropertyValues(prop).Select((e, i) => new { e, i })) { @element.e }
@if (!prop.Selector) {
Add
} else {
Add
}
} else if (IsSwitch(prop)) {
@prop.DisplayName
} else if (prop.Prefix is not null && !_isEdit) { @prop.Prefix } else if (prop.Selector) { @prop.DisplayName } else { @prop.DisplayName @if (_validation[_validationIdentifiers[prop]].Any()) {
@_validation[_validationIdentifiers[prop]].First()
} }
}
Cancel Save
@inject IServiceProvider Provider @inject IAdminPagesProvider PageProvider @inject SweetAlertService Alerts @inject IPermissionRepository Permissions @inject ITokenContext Auth @code { #pragma warning disable CS4014 [Parameter] public Func ReloadDelegate { get; set; } private BSModalBase _modal; private EditContext _context; private ValidationMessageStore _validation; private Dictionary _validationIdentifiers; private IDictionary _values; private Dictionary _selectorValues; private IModelProvider _provider; private AdminPage _currentPage; private object _entry; private bool _isEdit; private IDictionary _inputValues; public async Task Show(AdminPage page, object entryToEdit = null) { _entry = null; _inputValues = new Dictionary(); _selectorValues = new Dictionary(); _currentPage = page; _entry = entryToEdit; _isEdit = entryToEdit is not null; _provider = _currentPage.LoadModelProvider(Provider); _entry ??= Activator.CreateInstance(_currentPage.ModelType); _context = new EditContext(_entry); _validation = new ValidationMessageStore(_context); _validationIdentifiers = new Dictionary(); _context.OnValidationRequested += Validate; _values = new Dictionary(); foreach (var property in _currentPage.Properties) { _values.Add(property, property.GetValue(_entry)); _validationIdentifiers.Add(property, new FieldIdentifier(_entry, property.Name)); } await _modal.ShowAsync(); } private IList GetEditableProperties() { return _currentPage.Properties .Where(p => !p.Ignore) .OrderBy(p => p.Editable) .ToList(); } private bool IsDisabled(AdminPageProperty prop) => (_isEdit && !prop.Editable) || prop.Generated; private bool IsRequired(AdminPageProperty prop) => !_isEdit ? prop.Required : prop.Required && prop.EditDisplayValue; private bool IsSwitch(AdminPageProperty prop) => prop.Type == typeof(bool); private bool IsListType(AdminPageProperty prop) => IsListType(prop.Type); private bool IsListType(Type type) { if (!type.IsGenericType) return false; var generic = type.GenericTypeArguments[0]; var gListType = typeof(IList<>).MakeGenericType(generic); var iListType = typeof(List<>).MakeGenericType(generic); return type.IsAssignableFrom(gListType) || type.IsAssignableFrom(iListType); } private IList GetListPropertyValues(AdminPageProperty prop) { if (!IsListType(prop)) return new List(); var list = new List(); var values = prop.GetValue(_entry); if (values is null) { prop.SetValue(_entry, Activator.CreateInstance(prop.Type)); return list; } foreach (var value in (IEnumerable)values) { list.Add(MapPropertyValue(value, prop)); } return list; } private string GetPropertyValue(AdminPageProperty property) { if (!_isEdit) return ""; if (!property.EditDisplayValue) return ""; return MapPropertyValue(property.GetValue(_entry), property); } public string MapPropertyValue(object value, AdminPageProperty property, bool isSubProperty = false) { if (value is null) return string.Empty; var type = value.GetType(); var page = PageProvider.HasPageFor(type); if (page is not null && !string.IsNullOrWhiteSpace(page.ListingProperty)) { var prop = page.Properties .SingleOrDefault(p => p.Name == page.ListingProperty); if (prop is not null) { return MapPropertyValue(prop.GetValue(value), prop); } } if (!string.IsNullOrEmpty(property.DisplayPropertyName) && !isSubProperty) { var prop = type.GetProperties() .SingleOrDefault(p => p.Name == property.DisplayPropertyName); return MapPropertyValue(prop?.GetValue(value), property, true); } var stringValue = value.ToString(); if (!string.IsNullOrWhiteSpace(property.Prefix)) { return stringValue?.Replace(property.Prefix, ""); } return stringValue; } private string GetInputType(AdminPageProperty property) { if (!property.EditDisplayValue) return "password"; return "text"; } private void Validate(object sender, ValidationRequestedEventArgs e) { _validation.Clear(); foreach (var value in _values) { if (value.Key.Unique) { if (value.Value == value.Key.GetValue(_entry)) continue; var data = _provider!.ReadAllO().GetAwaiter().GetResult(); foreach (var entry in data) { var other = value.Key.GetValue(entry); if (!other.Equals(value.Value)) continue; _validation.Add(_validationIdentifiers[value.Key], $"This {value.Key.DisplayName ?? value.Key.Name} already exists!"); break; } } if (value.Key.Validator is null) continue; var error = value.Key.Validator?.Invoke(value.Value); if (string.IsNullOrEmpty(error)) continue; _validation.Add(_validationIdentifiers[value.Key], error); } } private void DeleteListItem(AdminPageProperty prop, int index) { var list = prop.GetValue(_entry); list.RemoveAt(index); } private void AddListItem(AdminPageProperty prop) { if (!_inputValues.TryGetValue(prop, out var input) || input is null) { Alerts.FireAsync(new SweetAlertOptions { Title = "Error!", Text = "Please enter a value!", Icon = SweetAlertIcon.Error }); return; } var list = prop.GetValue(_entry); var value = prop.Parser?.Invoke(_entry, input) ?? input; list?.Add(value); } private async Task<(string, int)[]> SetupSelectorProperty(AdminPageProperty property) { var type = property.SelectorType ?? property.Type; if (IsListType(type)) { type = type.GenericTypeArguments[0]; } var page = PageProvider.HasPageFor(type); if (page is null) { throw new ArgumentException($"'{property.Name}' cannot be a selector because a admin page for '{type.Name}' does not exist!"); } var repo = page.LoadModelProvider(Provider); var objects = (await repo!.ReadAllO()).ToArray(); _selectorValues[property] = objects; var data = new List<(string, int)>(); for (var i = 0; i < objects.Length; i++) { data.Add((MapPropertyValue(objects[i], property), i)); } return data.ToArray(); } private bool IsIndexSelected(AdminPageProperty property, int index) { var value = property.GetValue(_entry); if (value is null) return false; return _selectorValues[property][index] == value; } private object ReadSelectorValue(AdminPageProperty property, object value) { if (!int.TryParse(value.ToString(), out int result)) { return null; } return _selectorValues[property][result]; } private async void Save() { if (_isEdit && _currentPage.Permissions.Update is not null) { if (!await Permissions.HasPermission(Auth.AccessToken, _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.AccessToken, _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) { if (IsListType(value.Key)) continue; value.Key.SetValue(_entry, value.Key.Parser?.Invoke(_entry, value.Value) ?? Convert.ChangeType(value.Value, value.Key.Type)); } if (!_isEdit) { await _provider.CreateO(_entry); Alerts.FireAsync(new SweetAlertOptions { Title = "New entry added!", Icon = SweetAlertIcon.Success, ShowConfirmButton = false, Timer = 1500 }); } else { await _provider.UpdateO(_entry); Alerts.FireAsync(new SweetAlertOptions { Title = "Entry updated!", Icon = SweetAlertIcon.Success, ShowConfirmButton = false, Timer = 1500 }); } await ReloadDelegate.Invoke(); } }