Added AdminPages to admin dashboard and navigation + created 2.0 todo list

This commit is contained in:
2024-10-06 11:09:00 +02:00
parent 9cf818c55d
commit 6a110d5b8b
12 changed files with 90 additions and 28 deletions

View File

@@ -7,6 +7,14 @@ A simple backend management api for ASP.NET Core Web APIs
- [x] Permission management - [x] Permission management
- [x] Frontend dashboards - [x] Frontend dashboards
## 2.0 Todo list
- [x] 1.0 bug fixes
- [x] Code cleanup
- [x] Relations in database
- [ ] Generated Admin pages
- [ ] Pretty Login page for administration
- [ ] Clean documentation
# Usage # Usage
There are two different versions of HopFrame, either the Web API version or the full Blazor web version. There are two different versions of HopFrame, either the Web API version or the full Blazor web version.

View File

@@ -0,0 +1,6 @@
namespace HopFrame.Web.Admin.Attributes.Classes;
[AttributeUsage(AttributeTargets.Class)]
public class AdminUrlAttribute(string url) : Attribute {
public string Url { get; set; } = url;
}

View File

@@ -7,6 +7,7 @@ public interface IAdminPageGenerator<TModel> {
IAdminPageGenerator<TModel> Title(string title); IAdminPageGenerator<TModel> Title(string title);
IAdminPageGenerator<TModel> Description(string description); IAdminPageGenerator<TModel> Description(string description);
IAdminPageGenerator<TModel> Url(string url);
IAdminPageGenerator<TModel> ViewPermission(string permission); IAdminPageGenerator<TModel> ViewPermission(string permission);
IAdminPageGenerator<TModel> CreatePermission(string permission); IAdminPageGenerator<TModel> CreatePermission(string permission);

View File

@@ -73,6 +73,11 @@ internal class AdminContextGenerator : IAdminContextGenerator {
generator.Description(attribute?.Description); generator.Description(attribute?.Description);
} }
if (attributes.Any(a => a is AdminUrlAttribute)) {
var attribute = attributes.Single(a => a is AdminUrlAttribute) as AdminUrlAttribute;
generator.Url(attribute?.Url);
}
if (attributes.Any(a => a is AdminPermissionsAttribute)) { if (attributes.Any(a => a is AdminPermissionsAttribute)) {
var attribute = attributes.Single(a => a is AdminPermissionsAttribute) as AdminPermissionsAttribute; var attribute = attributes.Single(a => a is AdminPermissionsAttribute) as AdminPermissionsAttribute;
generator.CreatePermission(attribute?.Permissions.Create); generator.CreatePermission(attribute?.Permissions.Create);

View File

@@ -39,6 +39,7 @@ internal sealed class AdminPageGenerator<TModel> : IAdminPageGenerator<TModel>,
public IAdminPageGenerator<TModel> Title(string title) { public IAdminPageGenerator<TModel> Title(string title) {
_page.Title = title; _page.Title = title;
_page.Url ??= title.ToLower();
return this; return this;
} }
@@ -47,6 +48,11 @@ internal sealed class AdminPageGenerator<TModel> : IAdminPageGenerator<TModel>,
return this; return this;
} }
public IAdminPageGenerator<TModel> Url(string url) {
_page.Url = url;
return this;
}
public IAdminPageGenerator<TModel> ViewPermission(string permission) { public IAdminPageGenerator<TModel> ViewPermission(string permission) {
_page.Permissions.View = permission; _page.Permissions.View = permission;
return this; return this;

View File

@@ -8,6 +8,7 @@ public sealed class AdminPage<TModel> : AdminPage;
public class AdminPage { public class AdminPage {
public string Title { get; set; } public string Title { get; set; }
public string Description { get; set; } public string Description { get; set; }
public string Url { get; set; }
public AdminPagePermissions Permissions { get; set; } public AdminPagePermissions Permissions { get; set; }
public IList<AdminPageProperty> Properties { get; set; } public IList<AdminPageProperty> Properties { get; set; }

View File

@@ -5,6 +5,7 @@
@using BlazorStrap @using BlazorStrap
@using HopFrame.Web.Pages.Administration.Layout @using HopFrame.Web.Pages.Administration.Layout
@using BlazorStrap.V5 @using BlazorStrap.V5
@using HopFrame.Web.Admin.Providers
@using HopFrame.Web.Components @using HopFrame.Web.Components
@using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Web
@layout AdminLayout @layout AdminLayout
@@ -13,15 +14,15 @@
<BSContainer> <BSContainer>
<BSRow Justify="Justify.Center"> <BSRow Justify="Justify.Center">
@foreach (var view in AdminMenu.Subpages) { @foreach (var adminPage in Pages.LoadRegisteredAdminPages()) {
<AuthorizedView Permission="@view.Permission"> <AuthorizedView Permission="@adminPage.Permissions.View">
<BSCol Column="4" style="margin-bottom: 10px"> <BSCol Column="4" style="margin-bottom: 10px">
<BSCard CardType="CardType.Card" Color="BSColor.Dark" style="min-height: 200px"> <BSCard CardType="CardType.Card" Color="BSColor.Dark" style="min-height: 200px">
<BSCard CardType="CardType.Body" style="display: flex; flex-direction: column"> <BSCard CardType="CardType.Body" style="display: flex; flex-direction: column">
<BSCard CardType="CardType.Title">@view.Name</BSCard> <BSCard CardType="CardType.Title">@adminPage.Title</BSCard>
<BSCard CardType="CardType.Subtitle"><span style="color: gray">@view.Permission</span></BSCard> <BSCard CardType="CardType.Subtitle"><span style="color: gray">@adminPage.Permissions.View</span></BSCard>
<BSCard CardType="CardType.Text">@view.Description</BSCard> <BSCard CardType="CardType.Text">@adminPage.Description</BSCard>
<BSButton IsOutlined="true" MarginTop="Margins.Auto" style="width: max-content; align-self: center" OnClick="() => Navigator.NavigateTo(view.Url, true)" Color="BSColor.Light">Open</BSButton> <BSButton IsOutlined="true" MarginTop="Margins.Auto" style="width: max-content; align-self: center" OnClick="() => NavigateTo(adminPage.Url)" Color="BSColor.Light">Open</BSButton>
</BSCard> </BSCard>
</BSCard> </BSCard>
</BSCol> </BSCol>
@@ -31,3 +32,12 @@
</BSContainer> </BSContainer>
@inject NavigationManager Navigator @inject NavigationManager Navigator
@inject IAdminPagesProvider Pages
@code {
public void NavigateTo(string url) {
Navigator.NavigateTo("administration/" + url, true);
}
}

View File

@@ -3,10 +3,10 @@
@using BlazorStrap @using BlazorStrap
@using BlazorStrap.V5 @using BlazorStrap.V5
@using HopFrame.Security.Claims @using HopFrame.Security.Claims
@using HopFrame.Web.Admin.Providers
@using HopFrame.Web.Services @using HopFrame.Web.Services
@using static Microsoft.AspNetCore.Components.Web.RenderMode @using static Microsoft.AspNetCore.Components.Web.RenderMode
@using HopFrame.Web.Components.Administration @using HopFrame.Web.Components.Administration
@using HopFrame.Web.Model
@using HopFrame.Web.Components @using HopFrame.Web.Components
@@ -23,9 +23,9 @@
<BSNav MarginEnd="Margins.Auto" Class="mb-lg-0"> <BSNav MarginEnd="Margins.Auto" Class="mb-lg-0">
<BSNavItem IsActive="IsDashboardActive()" OnClick="NavigateToDashboard">Dashboard</BSNavItem> <BSNavItem IsActive="IsDashboardActive()" OnClick="NavigateToDashboard">Dashboard</BSNavItem>
@foreach (var nav in Subpages) { @foreach (var adminPage in Pages.LoadRegisteredAdminPages()) {
<AuthorizedView Permission="@nav.Permission"> <AuthorizedView Permission="@adminPage.Permissions.View">
<BSNavItem IsActive="IsNavItemActive(nav.Url)" OnClick="() => Navigate(nav.Url)">@nav.Name</BSNavItem> <BSNavItem IsActive="IsNavItemActive(adminPage.Url)" OnClick="() => Navigate(adminPage.Url)">@adminPage.Title</BSNavItem>
</AuthorizedView> </AuthorizedView>
} }
</BSNav> </BSNav>
@@ -46,25 +46,11 @@
@inject NavigationManager Navigator @inject NavigationManager Navigator
@inject ITokenContext Context @inject ITokenContext Context
@inject IAuthService Auth @inject IAuthService Auth
@inject IAdminPagesProvider Pages
@code { @code {
public static IList<NavigationItem> Subpages = new List<NavigationItem> {
new () {
Name = "Users",
Url = "administration/users",
Description = "On this page you can manage all user accounts.",
Permission = Security.AdminPermissions.ViewUsers
},
new () {
Name = "Groups",
Url = "administration/groups",
Description = "On this page you can view, create, edit and delete permission groups.",
Permission = Security.AdminPermissions.ViewGroups
}
};
private bool IsNavItemActive(string element) { private bool IsNavItemActive(string element) {
return Navigator.Uri.Contains(element); return Navigator.Uri.TrimEnd('/').EndsWith(element);
} }
private bool IsDashboardActive() { private bool IsDashboardActive() {
@@ -72,11 +58,11 @@
} }
private void NavigateToDashboard() { private void NavigateToDashboard() {
Navigate("administration"); Navigator.NavigateTo("administration", true);
} }
private void Navigate(string url) { private void Navigate(string url) {
Navigator.NavigateTo(url, true); Navigator.NavigateTo("administration/" + url, true);
} }
private void Logout() { private void Logout() {

View File

@@ -0,0 +1,12 @@
using HopFrame.Web.Admin;
using HopFrame.Web.Admin.Models;
using RestApiTest.Models;
namespace FrontendTest;
public class AdminContext : AdminPagesContext {
public AdminPage<Address> Addresses { get; set; }
public AdminPage<Employee> Employees { get; set; }
}

View File

@@ -0,0 +1,18 @@
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Mvc.ModelBinding;
namespace RestApiTest.Models;
public class Address {
[ForeignKey("Employee")]
public int AddressId { get; set; }
public string AddressDetails { get; set; }
public string City { get; set; }
public int ZipCode { get; set; }
public string State { get; set; }
public string Country { get; set; }
[JsonIgnore]
public virtual Employee Employee { get; set; }
}

View File

@@ -0,0 +1,8 @@
namespace RestApiTest.Models;
public class Employee {
public int EmployeeId { get; set; }
public string Name { get; set; }
public virtual Address Address { get; set; }
}

View File

@@ -7,6 +7,7 @@ var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<DatabaseContext>(); builder.Services.AddDbContext<DatabaseContext>();
builder.Services.AddHopFrame<DatabaseContext>(); builder.Services.AddHopFrame<DatabaseContext>();
builder.Services.AddAdminContext<AdminContext>();
// Add services to the container. // Add services to the container.
builder.Services.AddRazorComponents() builder.Services.AddRazorComponents()