From fc854251898aaa10fbb254d2e8043bc0bb965611 Mon Sep 17 00:00:00 2001 From: Leon Hoppe Date: Thu, 16 Jan 2025 11:24:16 +0100 Subject: [PATCH] Added reload button and animation --- .idea/.idea.HopFrame/.idea/workspace.xml | 58 +++++++++++-------- src/HopFrame.Core/Config/DbContextConfig.cs | 5 +- src/HopFrame.Core/Config/HopFrameConfig.cs | 22 +++---- src/HopFrame.Core/Config/PropertyConfig.cs | 31 ++++++---- src/HopFrame.Core/Config/TableConfig.cs | 7 ++- src/HopFrame.Core/Services/ITableManager.cs | 4 +- .../Services/Implementations/TableManager.cs | 10 ++-- .../Components/Pages/HopFrameListView.razor | 51 ++++++++++------ testing/HopFrame.Testing/Program.cs | 1 - 9 files changed, 110 insertions(+), 79 deletions(-) diff --git a/.idea/.idea.HopFrame/.idea/workspace.xml b/.idea/.idea.HopFrame/.idea/workspace.xml index 6d154b7..60c60eb 100644 --- a/.idea/.idea.HopFrame/.idea/workspace.xml +++ b/.idea/.idea.HopFrame/.idea/workspace.xml @@ -11,15 +11,13 @@ + + + - - - - - - { + "keyToString": { + ".NET Launch Settings Profile.HopFrame.Testing.executor": "Run", + ".NET Launch Settings Profile.HopFrame.Testing: https.executor": "Run", + ".NET Project.HopFrame.Testing.executor": "Run", + "RunOnceActivity.ShowReadmeOnStart": "true", + "RunOnceActivity.git.unshallow": "true", + "git-widget-placeholder": "feature/setup", + "list.type.of.created.stylesheet": "CSS", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "nodejs_package_manager_path": "npm", + "settings.editor.selected.configurable": "preferences.environmentSetup", + "vue.rearranger.settings.migration": "true" } -}]]> +} @@ -199,6 +206,7 @@ - \ No newline at end of file diff --git a/src/HopFrame.Core/Config/DbContextConfig.cs b/src/HopFrame.Core/Config/DbContextConfig.cs index b21f8cb..974a40f 100644 --- a/src/HopFrame.Core/Config/DbContextConfig.cs +++ b/src/HopFrame.Core/Config/DbContextConfig.cs @@ -21,7 +21,8 @@ public class DbContextConfig { } } -public class DbContextConfig(Type context) : DbContextConfig(context) where TDbContext : DbContext { +public class DbContextConfig(DbContextConfig config) { + public DbContextConfig InnerConfig { get; } = config; public DbContextConfig Table(Action> configurator) where TModel : class { var table = Table(); @@ -30,7 +31,7 @@ public class DbContextConfig(Type context) : DbContextConfig(context } public TableConfig Table() where TModel : class { - var table = Tables.Single(table => table.TableType == typeof(TModel)); + var table = InnerConfig.Tables.Single(table => table.TableType == typeof(TModel)); return new TableConfig(table); } diff --git a/src/HopFrame.Core/Config/HopFrameConfig.cs b/src/HopFrame.Core/Config/HopFrameConfig.cs index 1c1e676..4ac3bb4 100644 --- a/src/HopFrame.Core/Config/HopFrameConfig.cs +++ b/src/HopFrame.Core/Config/HopFrameConfig.cs @@ -4,14 +4,15 @@ using Microsoft.EntityFrameworkCore; namespace HopFrame.Core.Config; public class HopFrameConfig { - public List Contexts { get; init; } = new(); + public List Contexts { get; } = new(); public bool DisplayUserInfo { get; set; } = true; - public Type? AuthHandler { get; set; } public string? BasePolicy { get; set; } public string? LoginPageRewrite { get; set; } } public class HopFrameConfigurator(HopFrameConfig config) { + public HopFrameConfig InnerConfig { get; } = config; + public HopFrameConfigurator AddDbContext(Action> configurator) where TDbContext : DbContext { var context = AddDbContext(); configurator.Invoke(context); @@ -19,28 +20,23 @@ public class HopFrameConfigurator(HopFrameConfig config) { } public DbContextConfig AddDbContext() where TDbContext : DbContext { - var context = new DbContextConfig(typeof(TDbContext)); - config.Contexts.Add(context); - return context; + var context = new DbContextConfig(typeof(TDbContext)); + InnerConfig.Contexts.Add(context); + return new DbContextConfig(context); } public HopFrameConfigurator DisplayUserInfo(bool display) { - config.DisplayUserInfo = display; - return this; - } - - public HopFrameConfigurator SetAuthHandler() where TAuthHandler : IHopFrameAuthHandler { - config.AuthHandler = typeof(TAuthHandler); + InnerConfig.DisplayUserInfo = display; return this; } public HopFrameConfigurator SetBasePolicy(string basePolicy) { - config.BasePolicy = basePolicy; + InnerConfig.BasePolicy = basePolicy; return this; } public HopFrameConfigurator SetLoginPage(string url) { - config.LoginPageRewrite = url; + InnerConfig.LoginPageRewrite = url; return this; } } diff --git a/src/HopFrame.Core/Config/PropertyConfig.cs b/src/HopFrame.Core/Config/PropertyConfig.cs index 14555e7..2bca3bf 100644 --- a/src/HopFrame.Core/Config/PropertyConfig.cs +++ b/src/HopFrame.Core/Config/PropertyConfig.cs @@ -16,63 +16,70 @@ public class PropertyConfig(PropertyInfo info) { public bool Editable { get; set; } = true; public bool Creatable { get; set; } = true; public bool DisplayValue { get; set; } = true; + public bool IsRelation { get; set; } } public class PropertyConfig(PropertyConfig config) { + public PropertyConfig InnerConfig { get; } = config; public PropertyConfig SetDisplayName(string displayName) { - config.Name = displayName; + InnerConfig.Name = displayName; return this; } public PropertyConfig List(bool list) { - config.List = list; - config.Searchable = false; + InnerConfig.List = list; + InnerConfig.Searchable = false; return this; } public PropertyConfig Sortable(bool sortable) { - config.Sortable = sortable; + InnerConfig.Sortable = sortable; return this; } public PropertyConfig Searchable(bool searchable) { - config.Searchable = searchable; + InnerConfig.Searchable = searchable; return this; } public PropertyConfig DisplayedProperty(Expression> propertyExpression) { - config.DisplayedProperty = TableConfig.GetPropertyInfo(propertyExpression); + InnerConfig.DisplayedProperty = TableConfig.GetPropertyInfo(propertyExpression); return this; } public PropertyConfig Format(Func formatter) { - config.Formatter = obj => formatter.Invoke((TProp)obj); + InnerConfig.Formatter = obj => formatter.Invoke((TProp)obj); return this; } public PropertyConfig ValueParser(Func parser) { - config.Parser = str => parser.Invoke(str)!; + InnerConfig.Parser = str => parser.Invoke(str)!; return this; } public PropertyConfig ValueTemplate(Func template) { - config.Template = () => template.Invoke()!; + InnerConfig.Template = () => template.Invoke()!; return this; } public PropertyConfig Editable(bool editable) { - config.Editable = editable; + InnerConfig.Editable = editable; return this; } public PropertyConfig Creatable(bool creatable) { - config.Creatable = creatable; + InnerConfig.Creatable = creatable; return this; } public PropertyConfig DisplayValue(bool display) { - config.DisplayValue = display; + InnerConfig.DisplayValue = display; + return this; + } + + public PropertyConfig IsRelation(bool isRelation) { + InnerConfig.IsRelation = isRelation; return this; } diff --git a/src/HopFrame.Core/Config/TableConfig.cs b/src/HopFrame.Core/Config/TableConfig.cs index 22c7c19..04270ae 100644 --- a/src/HopFrame.Core/Config/TableConfig.cs +++ b/src/HopFrame.Core/Config/TableConfig.cs @@ -35,16 +35,17 @@ public class TableConfig { } } -public class TableConfig(TableConfig innerConfig) { +public class TableConfig(TableConfig config) { + public TableConfig InnerConfig { get; } = config; public TableConfig Ignore() { - innerConfig.Ignored = true; + InnerConfig.Ignored = true; return this; } public PropertyConfig Property(Expression> propertyExpression) { var info = GetPropertyInfo(propertyExpression); - var prop = innerConfig.Properties + var prop = InnerConfig.Properties .Single(prop => prop.Info.Name == info.Name); return new PropertyConfig(prop); } diff --git a/src/HopFrame.Core/Services/ITableManager.cs b/src/HopFrame.Core/Services/ITableManager.cs index 00a1e07..be7cdb6 100644 --- a/src/HopFrame.Core/Services/ITableManager.cs +++ b/src/HopFrame.Core/Services/ITableManager.cs @@ -5,8 +5,8 @@ namespace HopFrame.Core.Services; public interface ITableManager { public IQueryable LoadPage(int page, int perPage = 20); - public (IEnumerable, int) Search(string searchTerm, int page = 0, int perPage = 20); - public int TotalPages(int perPage = 20); + public Task<(IEnumerable, int)> Search(string searchTerm, int page = 0, int perPage = 20); + public Task TotalPages(int perPage = 20); public Task DeleteItem(object item); public Task EditItem(object item); public Task AddItem(object item); diff --git a/src/HopFrame.Core/Services/Implementations/TableManager.cs b/src/HopFrame.Core/Services/Implementations/TableManager.cs index 179fe32..726464a 100644 --- a/src/HopFrame.Core/Services/Implementations/TableManager.cs +++ b/src/HopFrame.Core/Services/Implementations/TableManager.cs @@ -16,19 +16,21 @@ internal sealed class TableManager(DbContext context, TableConfig config .Take(perPage); } - public (IEnumerable, int) Search(string searchTerm, int page = 0, int perPage = 20) { + public Task<(IEnumerable, int)> Search(string searchTerm, int page = 0, int perPage = 20) { var table = context.Set(); var all = IncludeForgeinKeys(table) .AsEnumerable() .Where(item => ItemSearched(item, searchTerm)) .ToList(); - return (all.Skip(page * perPage).Take(perPage), (int)Math.Ceiling(all.Count / (double)perPage)); + return Task.FromResult(( + (IEnumerable)all.Skip(page * perPage).Take(perPage), + (int)Math.Ceiling(all.Count / (double)perPage))); } - public int TotalPages(int perPage = 20) { + public async Task TotalPages(int perPage = 20) { var table = context.Set(); - return (int)Math.Ceiling(table.Count() / (double)perPage); + return (int)Math.Ceiling(await table.CountAsync() / (double)perPage); } public async Task DeleteItem(object item) { diff --git a/src/HopFrame.Web/Components/Pages/HopFrameListView.razor b/src/HopFrame.Web/Components/Pages/HopFrameListView.razor index fe520f4..ca5a257 100644 --- a/src/HopFrame.Web/Components/Pages/HopFrameListView.razor +++ b/src/HopFrame.Web/Components/Pages/HopFrameListView.razor @@ -1,22 +1,32 @@ @page "/admin/{TableName}" @layout HopFrameLayout @rendermode InteractiveServer +@implements IDisposable @using HopFrame.Core.Config @using HopFrame.Core.Services @using HopFrame.Web.Models @using Microsoft.JSInterop -@using System.Text.Json +@using Microsoft.EntityFrameworkCore

@_config?.PropertyName

+ + Refresh + + Add Entry
+
@@ -48,7 +58,7 @@ @if (_totalPages > 1) {
- + @@ -58,12 +68,12 @@ Items="Enumerable.Range(0, _totalPages)" OptionValue="@(p => p.ToString())" OptionText="@(p => (p + 1).ToString())" - ValueChanged="s => ChangePage(Convert.ToInt32(s))" + ValueChanged="async s => await ChangePage(Convert.ToInt32(s))" Width="max-content" SelectedOption="@_currentPage"/> of @_totalPages - +
@@ -99,18 +109,20 @@ private int _currentPage; private int _totalPages; private string? _searchTerm; + private bool _loading; protected override void OnInitialized() { _config ??= Explorer.GetTable(TableName); if (_config is null) { Navigator.NavigateTo("/admin", true); - return; } + } - _manager ??= Explorer.GetTableManager(_config.PropertyName); - _currentlyDisplayedModels = _manager!.LoadPage(_currentPage).ToArray(); - _totalPages = _manager.TotalPages(); + protected override async Task OnInitializedAsync() { + _manager ??= Explorer.GetTableManager(_config!.PropertyName); + _currentlyDisplayedModels = await _manager!.LoadPage(_currentPage).ToArrayAsync(); + _totalPages = await _manager.TotalPages(); } protected override async Task OnAfterRenderAsync(bool firstRender) { @@ -122,6 +134,10 @@ } } + public void Dispose() { + _searchCancel.Dispose(); + } + private CancellationTokenSource _searchCancel = new(); private async Task OnSearch(ChangeEventArgs eventArgs) { await _searchCancel.CancelAsync(); @@ -130,24 +146,26 @@ _searchCancel = new(); await Task.Delay(500, _searchCancel.Token); - (var query, _totalPages) = _manager!.Search(_searchTerm); + (var query, _totalPages) = await _manager!.Search(_searchTerm); _currentlyDisplayedModels = query.ToArray(); } - private void Reload() { + private async Task Reload() { + _loading = true; if (!string.IsNullOrEmpty(_searchTerm)) { - (var query, _totalPages) = _manager!.Search(_searchTerm); + (var query, _totalPages) = await _manager!.Search(_searchTerm); _currentlyDisplayedModels = query.ToArray(); } else { - OnInitialized(); + await OnInitializedAsync(); } + _loading = false; } - private void ChangePage(int page) { + private async Task ChangePage(int page) { if (page < 0 || page > _totalPages - 1) return; _currentPage = page; - Reload(); + await Reload(); } private async Task DeleteEntry(object element) { @@ -156,8 +174,7 @@ if (result.Cancelled) return; await _manager!.DeleteItem(element); - - Reload(); + await Reload(); } private async Task CreateOrEdit(object? element) { @@ -176,6 +193,6 @@ else await _manager!.EditItem(data!.CurrentObject!); - Reload(); + await Reload(); } } \ No newline at end of file diff --git a/testing/HopFrame.Testing/Program.cs b/testing/HopFrame.Testing/Program.cs index 5946cef..a736cf7 100644 --- a/testing/HopFrame.Testing/Program.cs +++ b/testing/HopFrame.Testing/Program.cs @@ -20,7 +20,6 @@ builder.Services.AddDbContext(options => { }); builder.Services.AddHopFrame(options => { - options.SetAuthHandler(); options.AddDbContext(context => { context.Table(table => { table.Property(u => u.Password)