Added theme saving. Added interfaces for overview pages. Renamed sidebar interface function
This commit is contained in:
@@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Mvc;
|
||||
using MoonCore.Extended.PermFilter;
|
||||
using MoonCore.Helpers;
|
||||
using Moonlight.Shared.Http.Requests.Admin.Sys.Files;
|
||||
using Moonlight.Shared.Http.Responses.Admin.Sys.Files;
|
||||
using Moonlight.Shared.Http.Responses.Admin.Sys;
|
||||
|
||||
namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys;
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MoonCore.Extended.PermFilter;
|
||||
using MoonCore.Helpers;
|
||||
using Moonlight.Shared.Http.Requests.Admin.Sys;
|
||||
|
||||
namespace Moonlight.ApiServer.Http.Controllers.Admin.Sys;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/admin/system/theme")]
|
||||
public class ThemeController : Controller
|
||||
{
|
||||
[HttpPatch]
|
||||
[RequirePermission("admin.system.theme.update")]
|
||||
public async Task Patch([FromBody] UpdateThemeRequest request)
|
||||
{
|
||||
var themePath = PathBuilder.File("storage", "theme.json");
|
||||
|
||||
await System.IO.File.WriteAllTextAsync(
|
||||
themePath,
|
||||
JsonSerializer.Serialize(request.Variables)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MoonCore.Exceptions;
|
||||
using MoonCore.Helpers;
|
||||
using Moonlight.ApiServer.Configuration;
|
||||
using Moonlight.ApiServer.Services;
|
||||
using Moonlight.Shared.Misc;
|
||||
@@ -25,7 +27,7 @@ public class FrontendController : Controller
|
||||
}
|
||||
|
||||
[HttpGet("frontend.json")]
|
||||
public Task<FrontendConfiguration> GetConfiguration()
|
||||
public async Task<FrontendConfiguration> GetConfiguration()
|
||||
{
|
||||
var configuration = new FrontendConfiguration()
|
||||
{
|
||||
@@ -34,12 +36,21 @@ public class FrontendController : Controller
|
||||
HostEnvironment = "ApiServer"
|
||||
};
|
||||
|
||||
// Load theme if it exists
|
||||
var themePath = PathBuilder.File("storage", "theme.json");
|
||||
|
||||
if (System.IO.File.Exists(themePath))
|
||||
{
|
||||
var variablesJson = await System.IO.File.ReadAllTextAsync(themePath);
|
||||
configuration.Theme.Variables = JsonSerializer.Deserialize<Dictionary<string, string>>(variablesJson) ?? new();
|
||||
}
|
||||
|
||||
configuration.Plugins.Entrypoints = PluginService.HostedPluginsManifest.Entrypoints;
|
||||
configuration.Plugins.Assemblies = PluginService.HostedPluginsManifest.Assemblies;
|
||||
|
||||
configuration.Scripts = AssetService.GetJavascriptAssets();
|
||||
|
||||
return Task.FromResult(configuration);
|
||||
return configuration;
|
||||
}
|
||||
|
||||
[HttpGet("plugins/{assemblyName}")] // TODO: Test this
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
using Moonlight.ApiServer.Database.Entities;
|
||||
|
||||
namespace Moonlight.ApiServer.Interfaces.Auth;
|
||||
|
||||
public interface IAuthInterceptor
|
||||
{
|
||||
public bool AllowAccess(User user, IServiceProvider serviceProvider);
|
||||
public bool AllowRefresh(User user, IServiceProvider serviceProvider);
|
||||
}
|
||||
@@ -17,7 +17,6 @@ using MoonCore.Services;
|
||||
using Moonlight.ApiServer.Configuration;
|
||||
using Moonlight.ApiServer.Database.Entities;
|
||||
using Moonlight.ApiServer.Helpers;
|
||||
using Moonlight.ApiServer.Interfaces.Auth;
|
||||
using Moonlight.ApiServer.Interfaces.OAuth2;
|
||||
using Moonlight.ApiServer.Interfaces.Startup;
|
||||
using Moonlight.ApiServer.Services;
|
||||
@@ -248,27 +247,6 @@ public class Startup
|
||||
|
||||
#endregion
|
||||
|
||||
#region Interfaces
|
||||
|
||||
private Task RegisterInterfaces()
|
||||
{
|
||||
WebApplicationBuilder.Services.AddInterfaces(configuration =>
|
||||
{
|
||||
// We use moonlight itself as a plugin assembly
|
||||
configuration.AddAssembly(typeof(Startup).Assembly);
|
||||
|
||||
configuration.AddAssemblies(AdditionalAssemblies);
|
||||
configuration.AddAssemblies(PluginLoaderService.PluginAssemblies);
|
||||
|
||||
configuration.AddInterface<IOAuth2Provider>();
|
||||
configuration.AddInterface<IAuthInterceptor>();
|
||||
});
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Plugin Loading
|
||||
|
||||
private async Task LoadPlugins()
|
||||
|
||||
@@ -8,6 +8,7 @@ public class CoreStartup : IPluginStartup
|
||||
public Task BuildApplication(WebAssemblyHostBuilder builder)
|
||||
{
|
||||
builder.Services.AddSingleton<ISidebarItemProvider, DefaultSidebarItemProvider>();
|
||||
builder.Services.AddSingleton<IOverviewElementProvider, DefaultOverviewElementProvider>();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
using Moonlight.Client.Interfaces;
|
||||
|
||||
namespace Moonlight.Client.Implementations;
|
||||
|
||||
public class DefaultAdminOverviewElementProvider : IAdminOverviewElementProvider
|
||||
{
|
||||
public void ModifyOverview(List<Type> overviewComponents)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Moonlight.Client.Interfaces;
|
||||
using Moonlight.Client.UI.Components;
|
||||
|
||||
namespace Moonlight.Client.Implementations;
|
||||
|
||||
public class DefaultOverviewElementProvider : IOverviewElementProvider
|
||||
{
|
||||
public void ModifyOverview(List<Type> overviewComponents)
|
||||
{
|
||||
overviewComponents.Add(typeof(WelcomeOverviewElement));
|
||||
}
|
||||
}
|
||||
@@ -5,61 +5,62 @@ namespace Moonlight.Client.Implementations;
|
||||
|
||||
public class DefaultSidebarItemProvider : ISidebarItemProvider
|
||||
{
|
||||
public SidebarItem[] Get()
|
||||
public void ModifySidebar(List<SidebarItem> items)
|
||||
{
|
||||
return
|
||||
[
|
||||
// User
|
||||
new SidebarItem()
|
||||
{
|
||||
Icon = "icon-chart-no-axes-gantt",
|
||||
Name = "Overview",
|
||||
Path = "/",
|
||||
Priority = 0,
|
||||
RequiresExactMatch = true
|
||||
},
|
||||
items.AddRange(
|
||||
[
|
||||
// User
|
||||
new SidebarItem()
|
||||
{
|
||||
Icon = "icon-chart-no-axes-gantt",
|
||||
Name = "Overview",
|
||||
Path = "/",
|
||||
Priority = 0,
|
||||
RequiresExactMatch = true
|
||||
},
|
||||
|
||||
// Admin
|
||||
new SidebarItem()
|
||||
{
|
||||
Icon = "icon-chart-no-axes-gantt",
|
||||
Name = "Overview",
|
||||
Group = "Admin",
|
||||
Path = "/admin",
|
||||
Priority = 0,
|
||||
RequiresExactMatch = true,
|
||||
Permission = "admin.overview"
|
||||
},
|
||||
new SidebarItem()
|
||||
{
|
||||
Icon = "icon-users",
|
||||
Name = "Users",
|
||||
Group = "Admin",
|
||||
Path = "/admin/users",
|
||||
Priority = 1,
|
||||
RequiresExactMatch = false,
|
||||
Permission = "admin.users.read"
|
||||
},
|
||||
new SidebarItem()
|
||||
{
|
||||
Icon = "icon-key-square",
|
||||
Name = "API",
|
||||
Group = "Admin",
|
||||
Path = "/admin/api",
|
||||
Priority = 2,
|
||||
RequiresExactMatch = false,
|
||||
Permission = "admin.api.read"
|
||||
},
|
||||
new SidebarItem()
|
||||
{
|
||||
Icon = "icon-settings",
|
||||
Name = "System",
|
||||
Group = "Admin",
|
||||
Path = "/admin/system",
|
||||
Priority = 3,
|
||||
RequiresExactMatch = false,
|
||||
Permission = "admin.system.overview"
|
||||
},
|
||||
];
|
||||
// Admin
|
||||
new SidebarItem()
|
||||
{
|
||||
Icon = "icon-chart-no-axes-gantt",
|
||||
Name = "Overview",
|
||||
Group = "Admin",
|
||||
Path = "/admin",
|
||||
Priority = 0,
|
||||
RequiresExactMatch = true,
|
||||
Permission = "admin.overview"
|
||||
},
|
||||
new SidebarItem()
|
||||
{
|
||||
Icon = "icon-users",
|
||||
Name = "Users",
|
||||
Group = "Admin",
|
||||
Path = "/admin/users",
|
||||
Priority = 1,
|
||||
RequiresExactMatch = false,
|
||||
Permission = "admin.users.read"
|
||||
},
|
||||
new SidebarItem()
|
||||
{
|
||||
Icon = "icon-key-square",
|
||||
Name = "API",
|
||||
Group = "Admin",
|
||||
Path = "/admin/api",
|
||||
Priority = 2,
|
||||
RequiresExactMatch = false,
|
||||
Permission = "admin.api.read"
|
||||
},
|
||||
new SidebarItem()
|
||||
{
|
||||
Icon = "icon-settings",
|
||||
Name = "System",
|
||||
Group = "Admin",
|
||||
Path = "/admin/system",
|
||||
Priority = 3,
|
||||
RequiresExactMatch = false,
|
||||
Permission = "admin.system.overview"
|
||||
},
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
using MoonCore.Blazor.Tailwind.Fm.Models;
|
||||
using MoonCore.Helpers;
|
||||
using Moonlight.Shared.Http.Requests.Admin.Sys.Files;
|
||||
using Moonlight.Shared.Http.Responses.Admin.Sys.Files;
|
||||
using Moonlight.Shared.Http.Responses.Admin.Sys;
|
||||
|
||||
namespace Moonlight.Client.Implementations;
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Moonlight.Client.Interfaces;
|
||||
|
||||
public interface IAdminOverviewElementProvider
|
||||
{
|
||||
public void ModifyOverview(List<Type> overviewComponents);
|
||||
}
|
||||
6
Moonlight.Client/Interfaces/IOverviewElementProvider.cs
Normal file
6
Moonlight.Client/Interfaces/IOverviewElementProvider.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Moonlight.Client.Interfaces;
|
||||
|
||||
public interface IOverviewElementProvider
|
||||
{
|
||||
public void ModifyOverview(List<Type> overviewComponents);
|
||||
}
|
||||
@@ -4,5 +4,5 @@ namespace Moonlight.Client.Interfaces;
|
||||
|
||||
public interface ISidebarItemProvider
|
||||
{
|
||||
public SidebarItem[] Get();
|
||||
public void ModifySidebar(List<SidebarItem> items);
|
||||
}
|
||||
24
Moonlight.Client/UI/Components/WelcomeOverviewElement.razor
Normal file
24
Moonlight.Client/UI/Components/WelcomeOverviewElement.razor
Normal file
@@ -0,0 +1,24 @@
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
|
||||
<div class="col-span-12 md:col-span-6 xl:col-span-3">
|
||||
<div class="font-medium leading-[1.1] tracking-tight">
|
||||
<div class="animate-shimmer bg-gradient-to-r from-violet-400 via-sky-400 to-purple-400 bg-clip-text font-semibold text-transparent text-3xl" style="animation-duration: 5s; background-size: 200% 100%">
|
||||
Welcome, @(Username)
|
||||
</div>
|
||||
<div class="text-gray-200 text-2xl">What do you want to do today?</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
[CascadingParameter] public Task<AuthenticationState> AuthState { get; set; }
|
||||
|
||||
private string Username;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var identity = await AuthState;
|
||||
var usernameClaim = identity.User.Claims.ToArray().First(x => x.Type == "username");
|
||||
Username = usernameClaim.Value;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
@using Moonlight.Client.Interfaces
|
||||
@using Moonlight.Client.Models
|
||||
@using Moonlight.Client.Services
|
||||
@using Moonlight.Client.UI.Layouts
|
||||
|
||||
@inject NavigationManager Navigation
|
||||
@@ -129,8 +128,12 @@
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Items = SidebarItemProviders
|
||||
.SelectMany(x => x.Get())
|
||||
var sidebarItems = new List<SidebarItem>();
|
||||
|
||||
foreach (var provider in SidebarItemProviders)
|
||||
provider.ModifySidebar(sidebarItems);
|
||||
|
||||
Items = sidebarItems
|
||||
//.Where(x => x.Permission == null || (x.Permission != null && IdentityService.HasPermission(x.Permission)))
|
||||
.GroupBy(x => x.Group ?? "")
|
||||
.OrderByDescending(x => string.IsNullOrEmpty(x.Key))
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
@using MoonCore.Helpers
|
||||
@using Moonlight.Client.Services
|
||||
@using Moonlight.Client.UI.Components
|
||||
@using Moonlight.Shared.Http.Requests.Admin.Sys
|
||||
@using Moonlight.Shared.Misc
|
||||
|
||||
@inject HttpApiClient ApiClient
|
||||
@@ -199,9 +200,13 @@
|
||||
return;
|
||||
}
|
||||
|
||||
await ToastService.Success("Successfully saved theme settings");
|
||||
// Send new variables
|
||||
await ApiClient.Patch("api/admin/system/theme", new UpdateThemeRequest()
|
||||
{
|
||||
Variables = ThemeService.Variables
|
||||
});
|
||||
|
||||
//TODO: Implement saving on the api server
|
||||
await ToastService.Success("Successfully saved theme settings");
|
||||
}
|
||||
|
||||
private async Task Export()
|
||||
|
||||
@@ -1,15 +1,34 @@
|
||||
@page "/admin"
|
||||
@using Moonlight.Client.Services
|
||||
|
||||
@inject DownloadService DownloadService
|
||||
@using MoonCore.Helpers
|
||||
@using Moonlight.Client.Interfaces
|
||||
|
||||
<WButton OnClick="OnClick">Test DownloadService</WButton>
|
||||
@inject IEnumerable<IAdminOverviewElementProvider> ElementProviders
|
||||
|
||||
<div class="grid grid-cols-12">
|
||||
@foreach (var render in Renders)
|
||||
{
|
||||
@render
|
||||
}
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
private async Task OnClick(WButton _)
|
||||
private RenderFragment[] Renders;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
await DownloadService.DownloadString("test.txt", "Download seems to be working");
|
||||
var renders = new List<RenderFragment>();
|
||||
|
||||
var elementTypes = new List<Type>();
|
||||
|
||||
foreach (var elementProvider in ElementProviders)
|
||||
elementProvider.ModifyOverview(elementTypes);
|
||||
|
||||
foreach (var elementType in elementTypes)
|
||||
renders.Add(ComponentHelper.FromType(elementType));
|
||||
|
||||
Renders = renders.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,26 +1,32 @@
|
||||
@page "/"
|
||||
@using MoonCore.Helpers
|
||||
@using Moonlight.Client.Interfaces
|
||||
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@inject IEnumerable<IOverviewElementProvider> ElementProviders
|
||||
|
||||
<div class="font-medium leading-[1.1] tracking-tight">
|
||||
<div class="animate-shimmer bg-gradient-to-r from-violet-400 via-sky-400 to-purple-400 bg-clip-text font-semibold text-transparent text-3xl" style="animation-duration: 5s; background-size: 200% 100%">
|
||||
Welcome, @(Username)
|
||||
</div>
|
||||
<div class="text-gray-200 text-2xl">What do you want to do today?</div>
|
||||
<div class="grid grid-cols-12">
|
||||
@foreach (var render in Renders)
|
||||
{
|
||||
@render
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="text-primary-500/10"></div>
|
||||
|
||||
@code
|
||||
{
|
||||
[CascadingParameter] public Task<AuthenticationState> AuthState { get; set; }
|
||||
private RenderFragment[] Renders;
|
||||
|
||||
private string Username;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
var identity = await AuthState;
|
||||
var usernameClaim = identity.User.Claims.ToArray().First(x => x.Type == "username");
|
||||
Username = usernameClaim.Value;
|
||||
var renders = new List<RenderFragment>();
|
||||
|
||||
var elementTypes = new List<Type>();
|
||||
|
||||
foreach (var elementProvider in ElementProviders)
|
||||
elementProvider.ModifyOverview(elementTypes);
|
||||
|
||||
foreach (var elementType in elementTypes)
|
||||
renders.Add(ComponentHelper.FromType(elementType));
|
||||
|
||||
Renders = renders.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Moonlight.Shared.Http.Requests.Admin.Sys;
|
||||
|
||||
public class UpdateThemeRequest
|
||||
{
|
||||
[Required(ErrorMessage = "You need to provide Variables")]
|
||||
public Dictionary<string, string> Variables { get; set; }
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
namespace Moonlight.Shared.Http.Responses.Admin.Sys.Files;
|
||||
namespace Moonlight.Shared.Http.Responses.Admin.Sys;
|
||||
|
||||
public class FileSystemEntryResponse
|
||||
{
|
||||
Reference in New Issue
Block a user