diff --git a/.idea/.idea.HopFrame/.idea/workspace.xml b/.idea/.idea.HopFrame/.idea/workspace.xml
index c5caf91..bbde447 100644
--- a/.idea/.idea.HopFrame/.idea/workspace.xml
+++ b/.idea/.idea.HopFrame/.idea/workspace.xml
@@ -9,18 +9,19 @@
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
@@ -62,6 +63,9 @@
"second": "2d65fdcb-5f13-45ad-a7ba-91dd4a88d6e4"
}
}
+
+
+
{
"associatedIndex": 3
@@ -140,7 +144,7 @@
-
+
@@ -150,7 +154,15 @@
1736850899254
-
+
+
+ 1736855209077
+
+
+
+ 1736855209077
+
+
@@ -161,6 +173,7 @@
-
+
+
\ No newline at end of file
diff --git a/src/HopFrame.Core/Services/IContextExplorer.cs b/src/HopFrame.Core/Services/IContextExplorer.cs
index b74f56e..cc0e4a6 100644
--- a/src/HopFrame.Core/Services/IContextExplorer.cs
+++ b/src/HopFrame.Core/Services/IContextExplorer.cs
@@ -4,5 +4,6 @@ namespace HopFrame.Core.Services;
public interface IContextExplorer {
public IEnumerable GetTableNames();
- public TableConfig? GetTable(string name);
+ public TableConfig? GetTable(string tableName);
+ public ITableManager? GetTableManager(string tableName);
}
\ No newline at end of file
diff --git a/src/HopFrame.Core/Services/ITableManager.cs b/src/HopFrame.Core/Services/ITableManager.cs
new file mode 100644
index 0000000..ac8421f
--- /dev/null
+++ b/src/HopFrame.Core/Services/ITableManager.cs
@@ -0,0 +1,5 @@
+namespace HopFrame.Core.Services;
+
+public interface ITableManager {
+ public Task> LoadPage(int page, int perPage = 25);
+}
\ No newline at end of file
diff --git a/src/HopFrame.Core/Services/Implementations/ContextExplorer.cs b/src/HopFrame.Core/Services/Implementations/ContextExplorer.cs
index 332f9fd..0f4e086 100644
--- a/src/HopFrame.Core/Services/Implementations/ContextExplorer.cs
+++ b/src/HopFrame.Core/Services/Implementations/ContextExplorer.cs
@@ -1,8 +1,9 @@
using HopFrame.Core.Config;
+using Microsoft.EntityFrameworkCore;
namespace HopFrame.Core.Services.Implementations;
-internal sealed class ContextExplorer(HopFrameConfig config) : IContextExplorer {
+internal sealed class ContextExplorer(HopFrameConfig config, IServiceProvider provider) : IContextExplorer {
public IEnumerable GetTableNames() {
foreach (var context in config.Contexts) {
foreach (var table in context.Tables) {
@@ -12,13 +13,28 @@ internal sealed class ContextExplorer(HopFrameConfig config) : IContextExplorer
}
}
- public TableConfig? GetTable(string name) {
+ public TableConfig? GetTable(string tableName) {
foreach (var context in config.Contexts) {
- var table = context.Tables.FirstOrDefault(table => table.PropertyName == name);
+ var table = context.Tables.FirstOrDefault(table => table.PropertyName == tableName);
if (table is not null)
return table;
}
return null;
}
+
+ public ITableManager? GetTableManager(string tableName) {
+ foreach (var context in config.Contexts) {
+ var table = context.Tables.FirstOrDefault(table => table.PropertyName == tableName);
+ if (table is null) continue;
+
+ var dbContext = provider.GetService(context.ContextType) as DbContext;
+ if (dbContext is null) return null;
+
+ var type = typeof(TableManager<>).MakeGenericType(table.TableType);
+ return Activator.CreateInstance(type, dbContext) as ITableManager;
+ }
+
+ return null;
+ }
}
\ No newline at end of file
diff --git a/src/HopFrame.Core/Services/Implementations/TableManager.cs b/src/HopFrame.Core/Services/Implementations/TableManager.cs
new file mode 100644
index 0000000..535553d
--- /dev/null
+++ b/src/HopFrame.Core/Services/Implementations/TableManager.cs
@@ -0,0 +1,15 @@
+using Microsoft.EntityFrameworkCore;
+
+namespace HopFrame.Core.Services.Implementations;
+
+internal sealed class TableManager(DbContext context) : ITableManager where TModel : class {
+
+ public async Task> LoadPage(int page, int perPage = 25) {
+ var table = context.Set();
+ return await table
+ .Skip(page * perPage)
+ .Take(perPage)
+ .ToArrayAsync();
+ }
+
+}
\ No newline at end of file
diff --git a/src/HopFrame.Web/Components/Layout/HopFrameLayout.razor b/src/HopFrame.Web/Components/Layout/HopFrameLayout.razor
index 99fe64d..87b9751 100644
--- a/src/HopFrame.Web/Components/Layout/HopFrameLayout.razor
+++ b/src/HopFrame.Web/Components/Layout/HopFrameLayout.razor
@@ -1,5 +1,6 @@
@using HopFrame.Core.Config
@using HopFrame.Core.Services
+@using Microsoft.Extensions.DependencyInjection
@inherits LayoutComponentBase
@@ -29,19 +30,16 @@
-@inject IServiceProvider Provider
+@inject IHopFrameAuthHandler Handler
@inject HopFrameConfig Config
@inject NavigationManager Navigator
@code {
protected override async Task OnInitializedAsync() {
- if (!string.IsNullOrEmpty(Config.BasePolicy)) {
- var handler = Provider.GetService(Config.AuthHandler!) as IHopFrameAuthHandler;
- var authorized = await handler!.IsAuthenticatedAsync(Config.BasePolicy);
- if (!authorized) {
- Navigator.NavigateTo((Config.LoginPageRewrite ?? "/login") + "?redirect=" + Navigator.Uri);
- }
+ var authorized = await Handler.IsAuthenticatedAsync(Config.BasePolicy);
+ if (!authorized) {
+ Navigator.NavigateTo((Config.LoginPageRewrite ?? "/login") + "?redirect=/" + Navigator.ToBaseRelativePath(Navigator.Uri), true);
}
}
diff --git a/src/HopFrame.Web/Components/Layout/HopFrameNavigation.razor b/src/HopFrame.Web/Components/Layout/HopFrameNavigation.razor
index 0a703b9..ec93b38 100644
--- a/src/HopFrame.Web/Components/Layout/HopFrameNavigation.razor
+++ b/src/HopFrame.Web/Components/Layout/HopFrameNavigation.razor
@@ -1,28 +1,28 @@
@using System.Text
@using HopFrame.Core.Config
@using HopFrame.Core.Services
+
@inject HopFrameConfig Config
-@inject IServiceProvider Provider
+@inject IHopFrameAuthHandler Handler
@code {
private string? _displayName;
private string? _initials;
+ private string? _searchValue;
protected override async Task OnInitializedAsync() {
if (Config.DisplayUserInfo) {
- var handler = Provider.GetService(Config.AuthHandler!) as IHopFrameAuthHandler;
- _displayName = await handler!.GetCurrentUserDisplayNameAsync();
+ _displayName = await Handler.GetCurrentUserDisplayNameAsync();
_initials = GetInitials(_displayName);
}
}
diff --git a/testing/HopFrame.Testing/Components/Pages/Home.razor b/testing/HopFrame.Testing/Components/Pages/Home.razor
index fbceb64..0e4fb43 100644
--- a/testing/HopFrame.Testing/Components/Pages/Home.razor
+++ b/testing/HopFrame.Testing/Components/Pages/Home.razor
@@ -8,11 +8,22 @@
Welcome to your new Fluent Blazor app.
@inject IContextExplorer Explorer
+@inject DatabaseContext Context
@code {
- protected override void OnInitialized() {
- Console.WriteLine(string.Join(", ", Explorer.GetTableNames()));
+ protected override async Task OnInitializedAsync() {
+ for (int i = 0; i < 10; i++) {
+ Context.Users.Add(new() {
+ Email = "leon@ladenbau-hoppe.de",
+ Id = Guid.CreateVersion7()
+ });
+ }
+ await Context.SaveChangesAsync();
+
+ var manager = Explorer.GetTableManager("Users");
+ var page = await manager!.LoadPage(0);
+ Console.WriteLine(string.Join(", ", page));
}
}
diff --git a/testing/HopFrame.Testing/DatabaseContext.cs b/testing/HopFrame.Testing/DatabaseContext.cs
index d62cb6d..85d512d 100644
--- a/testing/HopFrame.Testing/DatabaseContext.cs
+++ b/testing/HopFrame.Testing/DatabaseContext.cs
@@ -6,5 +6,13 @@ namespace HopFrame.Testing;
public class DatabaseContext(DbContextOptions options) : DbContext(options) {
public DbSet Users { get; set; }
-
+ public DbSet Posts { get; set; }
+
+ protected override void OnModelCreating(ModelBuilder modelBuilder) {
+ base.OnModelCreating(modelBuilder);
+
+ modelBuilder.Entity()
+ .HasOne()
+ .WithMany();
+ }
}
\ No newline at end of file
diff --git a/testing/HopFrame.Testing/Models/Post.cs b/testing/HopFrame.Testing/Models/Post.cs
new file mode 100644
index 0000000..59290b7
--- /dev/null
+++ b/testing/HopFrame.Testing/Models/Post.cs
@@ -0,0 +1,17 @@
+using System.ComponentModel.DataAnnotations;
+using System.ComponentModel.DataAnnotations.Schema;
+
+namespace HopFrame.Testing.Models;
+
+public class Post {
+ [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
+ public int Id { get; set; }
+
+ [MaxLength(255)]
+ public required string Caption { get; set; }
+
+ public required string Content { get; set; }
+
+ [ForeignKey("author")]
+ public User? Author { get; set; }
+}
\ No newline at end of file
diff --git a/testing/HopFrame.Testing/Models/User.cs b/testing/HopFrame.Testing/Models/User.cs
index 5233569..f602fbf 100644
--- a/testing/HopFrame.Testing/Models/User.cs
+++ b/testing/HopFrame.Testing/Models/User.cs
@@ -7,4 +7,8 @@ public class User {
public string? Password { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
+
+ public override string ToString() {
+ return Id.ToString();
+ }
}
\ No newline at end of file
diff --git a/testing/HopFrame.Testing/Program.cs b/testing/HopFrame.Testing/Program.cs
index 1133beb..8e45fb2 100644
--- a/testing/HopFrame.Testing/Program.cs
+++ b/testing/HopFrame.Testing/Program.cs
@@ -1,6 +1,8 @@
+using HopFrame.Core.Services;
using HopFrame.Testing;
using Microsoft.FluentUI.AspNetCore.Components;
using HopFrame.Testing.Components;
+using HopFrame.Testing.Services;
using HopFrame.Web;
using HopFrame.Web.Components.Pages;
using Microsoft.EntityFrameworkCore;
@@ -17,10 +19,12 @@ builder.Services.AddDbContext(options => {
});
builder.Services.AddHopFrame(options => {
- options.DisplayUserInfo(false);
+ options.SetAuthHandler();
options.AddDbContext();
});
+builder.Services.AddTransient();
+
var app = builder.Build();
// Configure the HTTP request pipeline.
diff --git a/testing/HopFrame.Testing/Services/AuthService.cs b/testing/HopFrame.Testing/Services/AuthService.cs
new file mode 100644
index 0000000..bafd2b3
--- /dev/null
+++ b/testing/HopFrame.Testing/Services/AuthService.cs
@@ -0,0 +1,12 @@
+using HopFrame.Core.Services;
+
+namespace HopFrame.Testing.Services;
+
+public class AuthService : IHopFrameAuthHandler {
+ public Task IsAuthenticatedAsync(string? policy) {
+ return Task.FromResult(true);
+ }
+ public Task GetCurrentUserDisplayNameAsync() {
+ return Task.FromResult("Leon Hoppe");
+ }
+}
\ No newline at end of file