improved admin page

Added the logic for a more modular admin page, where every feature can add cards and components with just a call of a function
This commit is contained in:
Moritz 2024-05-14 14:43:54 +02:00
parent 45e81c98bf
commit 3270039a6a
7 changed files with 155 additions and 55 deletions

View file

@ -15,6 +15,7 @@ using Moonlight.Core.Models.Abstractions.Feature;
using Moonlight.Core.Models.Enums; using Moonlight.Core.Models.Enums;
using Moonlight.Core.Repositories; using Moonlight.Core.Repositories;
using Moonlight.Core.Services; using Moonlight.Core.Services;
using Moonlight.Core.UI.Components.Cards;
namespace Moonlight.Core; namespace Moonlight.Core;
@ -207,6 +208,8 @@ public class CoreFeature : MoonlightFeature
context.AddSidebarItem("Users", "bxs-group", "/admin/users", needsExactMatch: false, isAdmin: true); context.AddSidebarItem("Users", "bxs-group", "/admin/users", needsExactMatch: false, isAdmin: true);
context.AddSidebarItem("System", "bxs-component", "/admin/sys", needsExactMatch: false, isAdmin: true); context.AddSidebarItem("System", "bxs-component", "/admin/sys", needsExactMatch: false, isAdmin: true);
context.AddAdminCard<AdminUserCard>(index: int.MinValue);
return Task.CompletedTask; return Task.CompletedTask;
} }

View file

@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Components;
namespace Moonlight.Core.Models.Abstractions.Feature;
public class AdminComponent
{
public RenderFragment Component { get; set; }
public int Index { get; set; }
public int RequiredPermissionLevel { get; set; }
}

View file

@ -1,4 +1,9 @@
using System.Reflection; using System.ComponentModel;
using System.Reflection;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Options;
using Moonlight.Core.UI.Components.Partials;
using IComponent = Microsoft.AspNetCore.Components.IComponent;
namespace Moonlight.Core.Models.Abstractions.Feature; namespace Moonlight.Core.Models.Abstractions.Feature;
@ -6,6 +11,8 @@ public class UiInitContext
{ {
public List<SidebarItem> SidebarItems { get; set; } = new(); public List<SidebarItem> SidebarItems { get; set; } = new();
public List<Assembly> RouteAssemblies { get; set; } = new(); public List<Assembly> RouteAssemblies { get; set; } = new();
public List<AdminComponent> AdminPageComponents { get; set; } = new();
public List<AdminComponent> AdminPageCards { get; set; } = new();
public void EnablePages<T>() public void EnablePages<T>()
{ {
@ -15,6 +22,38 @@ public class UiInitContext
RouteAssemblies.Add(assembly); RouteAssemblies.Add(assembly);
} }
public void AddAdminComponent<T>(int index = 0, int requiredPermissionLevel = 0) where T : IComponent
{
AdminPageComponents.Add(
new AdminComponent()
{
Component = builder =>
{
builder.OpenComponent<T>(0);
builder.CloseComponent();
},
Index = index,
RequiredPermissionLevel = requiredPermissionLevel
}
);
}
public void AddAdminCard<T>(int index = 0, int requiredPermissionLevel = 0) where T : IComponent
{
AdminPageCards.Add(
new AdminComponent()
{
Component = builder =>
{
builder.OpenComponent<T>(0);
builder.CloseComponent();
},
Index = index,
RequiredPermissionLevel = requiredPermissionLevel
}
);
}
public void AddSidebarItem(string name, string icon, string target, bool isAdmin = false, bool needsExactMatch = false, int index = 0) public void AddSidebarItem(string name, string icon, string target, bool isAdmin = false, bool needsExactMatch = false, int index = 0)
{ {
SidebarItems.Add(new SidebarItem() SidebarItems.Add(new SidebarItem()

View file

@ -0,0 +1,35 @@
@using MoonCore.Abstractions
@using Moonlight.Core.Database.Entities
@inject Repository<User> UserRepository
<a class="mt-4 card" href="/admin/servers">
<div class="card-body">
<div class="row align-items-center gx-0">
<div class="col">
<h6 class="text-uppercase text-muted mb-2">
Users
</h6>
<span class="h2 mb-0">
@UserCount
</span>
</div>
<div class="col-auto">
<span class="h2 text-muted mb-0">
<i class="text-primary bx bxs-group bx-lg"></i>
</span>
</div>
</div>
</div>
</a>
@code {
private int UserCount;
protected override async Task OnInitializedAsync()
{
UserCount = UserRepository.Get().Count();
}
}

View file

@ -1,73 +1,46 @@
@page "/admin" @page "/admin"
@using MoonCore.Abstractions @using MoonCore.Abstractions
@using Moonlight.Core.Database.Entities @using Moonlight.Core.Database.Entities
@using Moonlight.Core.Services
@using Moonlight.Features.Servers.Entities @using Moonlight.Features.Servers.Entities
@inject Repository<Server> ServerRepository @inject Repository<Server> ServerRepository
@inject Repository<User> UserRepository
@inject FeatureService FeatureService
@inject IdentityService IdentityService
@attribute [RequirePermission(999)] @attribute [RequirePermission(999)]
<LazyLoader Load="Load"> <LazyLoader Load="Load">
<div class="row"> <div class="row mb-4">
<div class="col-12 col-lg-6 col-xl"> @foreach (var adminCard in FeatureService.UiContext.AdminPageCards.OrderBy(x => x.Index).ToArray())
<a class="mt-4 card" href="/admin/servers"> {
<div class="card-body"> if (IdentityService.CurrentUser.Permissions >= adminCard.RequiredPermissionLevel)
<div class="row align-items-center gx-0"> {
<div class="col"> <div class="col-12 col-lg-6 col-xl">
<h6 class="text-uppercase text-muted mb-2"> @adminCard.Component
Users
</h6>
<span class="h2 mb-0">
@UserCount
</span>
</div>
<div class="col-auto">
<span class="h2 text-muted mb-0">
<i class="text-primary bx bxs-group bx-lg"></i>
</span>
</div>
</div>
</div> </div>
</a> }
</div> }
<div class="col-12 col-lg-6 col-xl">
<a class="mt-4 card" href="/admin/users">
<div class="card-body">
<div class="row align-items-center gx-0">
<div class="col">
<h6 class="text-uppercase text-muted mb-2">
Servers
</h6>
<span class="h2 mb-0">
@ServerCount
</span>
</div>
<div class="col-auto">
<span class="h2 text-muted mb-0">
<i class="text-primary bx bx-server bx-lg"></i>
</span>
</div>
</div>
</div>
</a>
</div>
</div> </div>
@foreach (var adminComponent in FeatureService.UiContext.AdminPageComponents.OrderBy(x => x.Index).ToArray())
{
if (IdentityService.CurrentUser.Permissions >= adminComponent.RequiredPermissionLevel)
{
<div class="mb-4">
@adminComponent
</div>
}
}
</LazyLoader> </LazyLoader>
@* This is just the start of this admin page, there will still be added more during the developement process *@
@code { @code {
private int ServerCount;
private int UserCount;
private async Task Load(LazyLoader arg) private async Task Load(LazyLoader arg)
{ {
await Task.Run(() => await arg.SetText("Loading Information...");
{
arg.SetText("Loading Information...");
ServerCount = ServerRepository.Get().Count();
UserCount = UserRepository.Get().Count();
});
} }
} }

View file

@ -10,6 +10,7 @@ using Moonlight.Features.Servers.Http.Middleware;
using Moonlight.Features.Servers.Implementations.Diagnose; using Moonlight.Features.Servers.Implementations.Diagnose;
using Moonlight.Features.Servers.Models.Enums; using Moonlight.Features.Servers.Models.Enums;
using Moonlight.Features.Servers.Services; using Moonlight.Features.Servers.Services;
using Moonlight.Features.Servers.UI.Components.Cards;
namespace Moonlight.Features.Servers; namespace Moonlight.Features.Servers;
@ -104,6 +105,8 @@ public class ServersFeature : MoonlightFeature
context.AddSidebarItem("Servers", "bx-server", "/servers", isAdmin: false, needsExactMatch: false); context.AddSidebarItem("Servers", "bx-server", "/servers", isAdmin: false, needsExactMatch: false);
context.AddSidebarItem("Servers", "bx-server", "/admin/servers", isAdmin: true, needsExactMatch: false); context.AddSidebarItem("Servers", "bx-server", "/admin/servers", isAdmin: true, needsExactMatch: false);
context.AddAdminCard<AdminServersCard>();
return Task.CompletedTask; return Task.CompletedTask;
} }
} }

View file

@ -0,0 +1,35 @@
@using MoonCore.Abstractions
@using Moonlight.Features.Servers.Entities
@inject Repository<Server> ServerRepository
<a class="mt-4 card" href="/admin/users">
<div class="card-body">
<div class="row align-items-center gx-0">
<div class="col">
<h6 class="text-uppercase text-muted mb-2">
Servers
</h6>
<span class="h2 mb-0">
@ServerCount
</span>
</div>
<div class="col-auto">
<span class="h2 text-muted mb-0">
<i class="text-primary bx bx-server bx-lg"></i>
</span>
</div>
</div>
</div>
</a>
@code {
private int ServerCount;
protected override async Task OnInitializedAsync()
{
ServerCount = ServerRepository.Get().Count();
}
}