Refactored project to module structure
This commit is contained in:
@@ -1,11 +1,10 @@
|
||||
@using LucideBlazor
|
||||
@using Moonlight.Shared.Http.Requests.Seup
|
||||
@using ShadcnBlazor.Cards
|
||||
@using ShadcnBlazor.Spinners
|
||||
@using Moonlight.Shared.Admin.Setup
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.Cards
|
||||
@using ShadcnBlazor.Inputs
|
||||
@using ShadcnBlazor.Labels
|
||||
|
||||
@using ShadcnBlazor.Spinners
|
||||
@inject HttpClient HttpClient
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
@@ -18,13 +17,14 @@
|
||||
{
|
||||
<div
|
||||
class="flex h-56 items-center justify-center rounded-lg bg-linear-to-br from-gray-100 to-gray-300 dark:from-gray-800 dark:to-gray-900">
|
||||
<img alt="Moonlight Logo" class="size-34" src="/_content/Moonlight.Frontend/logo.svg" />
|
||||
<img alt="Moonlight Logo" class="size-34" src="/_content/Moonlight.Frontend/logo.svg"/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2 text-center">
|
||||
<h2 class="text-2xl font-bold">Welcome to Moonlight Panel</h2>
|
||||
<p class="text-muted-foreground">
|
||||
You successfully installed moonlight. Now you are ready to perform some initial steps to complete your installation
|
||||
You successfully installed moonlight. Now you are ready to perform some initial steps to
|
||||
complete your installation
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
@@ -32,17 +32,19 @@
|
||||
{
|
||||
<div
|
||||
class="flex h-56 items-center justify-center rounded-lg bg-linear-to-br from-gray-100 to-gray-300 dark:from-gray-800 dark:to-gray-900">
|
||||
<UserIcon ClassName="size-34 text-blue-500" />
|
||||
<UserIcon ClassName="size-34 text-blue-500"/>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="space-y-2 text-center">
|
||||
<h2 class="text-2xl font-bold">Admin Account Creation</h2>
|
||||
<p class="text-muted-foreground">
|
||||
To continue please fill in the account details of the user you want to use as the initial administrator account.
|
||||
If you use an external OIDC provider, these details need to match with your desired OIDC account
|
||||
To continue please fill in the account details of the user you want to use as the initial
|
||||
administrator account.
|
||||
If you use an external OIDC provider, these details need to match with your desired OIDC
|
||||
account
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="grid grid-cols-1 gap-5">
|
||||
<div class="grid gap-2">
|
||||
<Label for="username">Username</Label>
|
||||
@@ -73,7 +75,7 @@
|
||||
{
|
||||
<div
|
||||
class="flex h-56 items-center justify-center rounded-lg bg-linear-to-br from-gray-100 to-gray-300 dark:from-gray-800 dark:to-gray-900">
|
||||
<RocketIcon ClassName="size-34 text-blue-500" />
|
||||
<RocketIcon ClassName="size-34 text-blue-500"/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2 text-center">
|
||||
@@ -105,7 +107,7 @@
|
||||
@if (CurrentStep > 0)
|
||||
{
|
||||
<Button @onclick="() => Navigate(-1)" Variant="ButtonVariant.Outline">
|
||||
<ChevronLeftIcon />
|
||||
<ChevronLeftIcon/>
|
||||
Back
|
||||
</Button>
|
||||
}
|
||||
@@ -120,7 +122,7 @@
|
||||
{
|
||||
<Button @onclick="ApplyAsync">
|
||||
Finish
|
||||
<RocketIcon />
|
||||
<RocketIcon/>
|
||||
</Button>
|
||||
}
|
||||
</div>
|
||||
@@ -140,16 +142,19 @@
|
||||
{
|
||||
private bool IsLoaded;
|
||||
|
||||
private int CurrentStep = 0;
|
||||
private int StepCount = 3;
|
||||
private int CurrentStep;
|
||||
private readonly int StepCount = 3;
|
||||
|
||||
private ApplySetupDto SetupDto = new();
|
||||
private readonly ApplySetupDto SetupDto = new();
|
||||
|
||||
private void Navigate(int diff) => CurrentStep += diff;
|
||||
private void Navigate(int diff)
|
||||
{
|
||||
CurrentStep += diff;
|
||||
}
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if(!firstRender)
|
||||
if (!firstRender)
|
||||
return;
|
||||
|
||||
var response = await HttpClient.GetAsync("api/admin/setup");
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Moonlight.Shared.Http.Requests.Admin.ApiKeys;
|
||||
using Moonlight.Shared.Http.Responses.Admin.ApiKeys;
|
||||
using Moonlight.Shared.Admin.Sys.ApiKeys;
|
||||
using Riok.Mapperly.Abstractions;
|
||||
|
||||
namespace Moonlight.Frontend.Mappers;
|
||||
namespace Moonlight.Frontend.Admin.Sys.ApiKeys;
|
||||
|
||||
[Mapper]
|
||||
[SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")]
|
||||
@@ -1,8 +1,7 @@
|
||||
@using Moonlight.Frontend.Helpers
|
||||
@using Moonlight.Frontend.UI.Admin.Components
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Requests.Admin.ApiKeys
|
||||
@using Moonlight.Shared.Http.Responses
|
||||
@using Moonlight.Frontend.Admin.Users.Shared
|
||||
@using Moonlight.Frontend.Infrastructure.Helpers
|
||||
@using Moonlight.Shared
|
||||
@using Moonlight.Shared.Admin.Sys.ApiKeys
|
||||
@using ShadcnBlazor.Dialogs
|
||||
@using ShadcnBlazor.Extras.Forms
|
||||
@using ShadcnBlazor.Extras.Toasts
|
||||
@@ -26,7 +25,7 @@
|
||||
<FieldGroup>
|
||||
<DataAnnotationsValidator/>
|
||||
<FormValidationSummary/>
|
||||
|
||||
|
||||
<FieldSet>
|
||||
<Field>
|
||||
<FieldLabel for="keyName">Name</FieldLabel>
|
||||
@@ -34,11 +33,12 @@
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel for="keyDescription">Description</FieldLabel>
|
||||
<TextareaInputField @bind-Value="Request.Description" id="keyDescription" placeholder="What this key is for"/>
|
||||
<TextareaInputField @bind-Value="Request.Description" id="keyDescription"
|
||||
placeholder="What this key is for"/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel for="keyValidUntil">Valid until</FieldLabel>
|
||||
<DateTimeInputField @bind-Value="Request.ValidUntil" id="keyValidUntil" />
|
||||
<DateTimeInputField @bind-Value="Request.ValidUntil" id="keyValidUntil"/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel>Permissions</FieldLabel>
|
||||
@@ -59,11 +59,11 @@
|
||||
|
||||
private CreateApiKeyDto Request;
|
||||
|
||||
private List<string> Permissions = new();
|
||||
private readonly List<string> Permissions = new();
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Request = new()
|
||||
Request = new CreateApiKeyDto
|
||||
{
|
||||
Permissions = [],
|
||||
ValidUntil = DateTimeOffset.UtcNow
|
||||
@@ -74,13 +74,13 @@
|
||||
{
|
||||
Request.Permissions = Permissions.ToArray();
|
||||
Request.ValidUntil = Request.ValidUntil.ToUniversalTime();
|
||||
|
||||
|
||||
var response = await HttpClient.PostAsJsonAsync(
|
||||
"/api/admin/apiKeys",
|
||||
Request,
|
||||
SerializationContext.Default.Options
|
||||
);
|
||||
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore);
|
||||
@@ -1,19 +1,18 @@
|
||||
@using LucideBlazor
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Moonlight.Frontend.UI.Admin.Modals
|
||||
@using Moonlight.Frontend.Infrastructure.Helpers
|
||||
@using Moonlight.Shared
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Requests
|
||||
@using Moonlight.Shared.Http.Responses
|
||||
@using Moonlight.Shared.Http.Responses.Admin.ApiKeys
|
||||
@using Moonlight.Shared.Admin.Sys.ApiKeys
|
||||
@using Moonlight.Shared.Shared
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.DataGrids
|
||||
@using ShadcnBlazor.Dropdowns
|
||||
@using ShadcnBlazor.Extras.AlertDialogs
|
||||
@using ShadcnBlazor.Extras.Dialogs
|
||||
@using ShadcnBlazor.Tabels
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.Extras.Toasts
|
||||
@using ShadcnBlazor.Tabels
|
||||
@using SerializationContext = Moonlight.Shared.SerializationContext
|
||||
|
||||
@inject ToastService ToastService
|
||||
@inject DialogService DialogService
|
||||
@@ -49,15 +48,17 @@
|
||||
</CellTemplate>
|
||||
</TemplateColumn>
|
||||
<PropertyColumn IsFilterable="true"
|
||||
Identifier="@nameof(ApiKeyDto.Description)" Field="k => k.Description" HeadClassName="hidden lg:table-cell" CellClassName="hidden lg:table-cell" />
|
||||
<TemplateColumn Identifier="@nameof(ApiKeyDto.ValidUntil)" Title="Valid until" HeadClassName="hidden lg:table-cell">
|
||||
Identifier="@nameof(ApiKeyDto.Description)" Field="k => k.Description"
|
||||
HeadClassName="hidden lg:table-cell" CellClassName="hidden lg:table-cell"/>
|
||||
<TemplateColumn Identifier="@nameof(ApiKeyDto.ValidUntil)" Title="Valid until"
|
||||
HeadClassName="hidden lg:table-cell">
|
||||
<CellTemplate>
|
||||
<TableCell ClassName="hidden lg:table-cell">
|
||||
@{
|
||||
var diff = context.ValidUntil - DateTimeOffset.UtcNow;
|
||||
var text = string.Format(diff.TotalSeconds < 0 ? "Expired since {0}" : "Expires in {0}", Formatter.FormatDuration(diff));
|
||||
}
|
||||
|
||||
|
||||
<span>
|
||||
@text
|
||||
</span>
|
||||
@@ -78,7 +79,8 @@
|
||||
</Slot>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent SideOffset="2">
|
||||
<DropdownMenuItem OnClick="() => EditAsync(context)" Disabled="@(!EditAccess.Succeeded)">
|
||||
<DropdownMenuItem OnClick="() => EditAsync(context)"
|
||||
Disabled="@(!EditAccess.Succeeded)">
|
||||
Edit
|
||||
<DropdownMenuShortcut>
|
||||
<PenIcon/>
|
||||
@@ -104,9 +106,9 @@
|
||||
@code
|
||||
{
|
||||
[CascadingParameter] public Task<AuthenticationState> AuthState { get; set; }
|
||||
|
||||
|
||||
private DataGrid<ApiKeyDto> Grid;
|
||||
|
||||
|
||||
private AuthorizationResult EditAccess;
|
||||
private AuthorizationResult DeleteAccess;
|
||||
private AuthorizationResult CreateAccess;
|
||||
@@ -114,7 +116,7 @@
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthState;
|
||||
|
||||
|
||||
EditAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.ApiKeys.Edit);
|
||||
DeleteAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.ApiKeys.Delete);
|
||||
CreateAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.ApiKeys.Create);
|
||||
@@ -135,13 +137,7 @@
|
||||
|
||||
private async Task CreateAsync()
|
||||
{
|
||||
await DialogService.LaunchAsync<CreateApiKeyDialog>(parameters =>
|
||||
{
|
||||
parameters[nameof(CreateApiKeyDialog.OnSubmit)] = async () =>
|
||||
{
|
||||
await Grid.RefreshAsync();
|
||||
};
|
||||
});
|
||||
await DialogService.LaunchAsync<CreateApiKeyDialog>(parameters => { parameters[nameof(CreateApiKeyDialog.OnSubmit)] = async () => { await Grid.RefreshAsync(); }; });
|
||||
}
|
||||
|
||||
private async Task EditAsync(ApiKeyDto key)
|
||||
@@ -149,10 +145,7 @@
|
||||
await DialogService.LaunchAsync<UpdateApiKeyDialog>(parameters =>
|
||||
{
|
||||
parameters[nameof(UpdateApiKeyDialog.Key)] = key;
|
||||
parameters[nameof(UpdateApiKeyDialog.OnSubmit)] = async () =>
|
||||
{
|
||||
await Grid.RefreshAsync();
|
||||
};
|
||||
parameters[nameof(UpdateApiKeyDialog.OnSubmit)] = async () => { await Grid.RefreshAsync(); };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
@using Moonlight.Frontend.Helpers
|
||||
@using Moonlight.Frontend.Mappers
|
||||
@using Moonlight.Frontend.UI.Admin.Components
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Requests.Admin.ApiKeys
|
||||
@using Moonlight.Shared.Http.Responses.Admin.ApiKeys
|
||||
@using Moonlight.Frontend.Admin.Users.Shared
|
||||
@using Moonlight.Frontend.Infrastructure.Helpers
|
||||
@using Moonlight.Shared
|
||||
@using Moonlight.Shared.Admin.Sys.ApiKeys
|
||||
@using ShadcnBlazor.Dialogs
|
||||
@using ShadcnBlazor.Extras.Forms
|
||||
@using ShadcnBlazor.Extras.Toasts
|
||||
@@ -34,11 +32,12 @@
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel for="keyDescription">Description</FieldLabel>
|
||||
<TextareaInputField @bind-Value="Request.Description" id="keyDescription" placeholder="What this key is for"/>
|
||||
<TextareaInputField @bind-Value="Request.Description" id="keyDescription"
|
||||
placeholder="What this key is for"/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel for="keyValidUntil">Valid until</FieldLabel>
|
||||
<DateTimeInputField @bind-Value="Request.ValidUntil" id="keyValidUntil" />
|
||||
<DateTimeInputField @bind-Value="Request.ValidUntil" id="keyValidUntil"/>
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel>Permissions</FieldLabel>
|
||||
@@ -71,13 +70,13 @@
|
||||
{
|
||||
Request.Permissions = Permissions.ToArray();
|
||||
Request.ValidUntil = Request.ValidUntil.ToUniversalTime();
|
||||
|
||||
|
||||
var response = await HttpClient.PatchAsJsonAsync(
|
||||
$"/api/admin/apiKeys/{Key.Id}",
|
||||
Request,
|
||||
SerializationContext.Default.Options
|
||||
);
|
||||
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore);
|
||||
@@ -88,7 +87,7 @@
|
||||
"API Key update",
|
||||
$"Successfully updated API key {Request.Name}"
|
||||
);
|
||||
|
||||
|
||||
await OnSubmit.Invoke();
|
||||
await CloseAsync();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Moonlight.Shared
|
||||
@using Moonlight.Shared.Http.Responses.Admin
|
||||
@using Moonlight.Shared.Admin.Sys.Diagnose
|
||||
@using ShadcnBlazor.Accordions
|
||||
@using ShadcnBlazor.Alerts
|
||||
@using ShadcnBlazor.Buttons
|
||||
@@ -10,7 +10,6 @@
|
||||
@using ShadcnBlazor.Emptys
|
||||
@using ShadcnBlazor.Extras.Common
|
||||
@using ShadcnBlazor.Spinners
|
||||
|
||||
@inject HttpClient HttpClient
|
||||
@inject IAuthorizationService AuthorizationService
|
||||
|
||||
@@ -223,15 +222,15 @@
|
||||
[CascadingParameter] public Task<AuthenticationState> AuthState { get; set; }
|
||||
|
||||
private AuthorizationResult AccessResult;
|
||||
|
||||
private bool IsLoading = false;
|
||||
private bool HasDiagnosed = false;
|
||||
|
||||
private bool IsLoading;
|
||||
private bool HasDiagnosed;
|
||||
private DiagnoseResultDto[] Entries;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthState;
|
||||
|
||||
|
||||
AccessResult = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.System.Diagnose);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
@using LucideBlazor
|
||||
@using Moonlight.Frontend.UI.Admin.Modals
|
||||
@using Moonlight.Shared.Http.Responses.Admin
|
||||
@using Moonlight.Shared.Admin.Sys.ContainerHelper
|
||||
@using Moonlight.Shared.Admin.Sys.Versions
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.Cards
|
||||
@using ShadcnBlazor.Emptys
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.Extras.AlertDialogs
|
||||
@using ShadcnBlazor.Extras.Common
|
||||
@using ShadcnBlazor.Extras.Dialogs
|
||||
@using ShadcnBlazor.Fields
|
||||
@using ShadcnBlazor.Selects
|
||||
@using ShadcnBlazor.Switches
|
||||
|
||||
@inject HttpClient HttpClient
|
||||
@inject DialogService DialogService
|
||||
@inject AlertDialogService AlertDialogService
|
||||
@@ -43,10 +42,10 @@
|
||||
|
||||
if (version.IsDevelopment)
|
||||
displayName += " (dev)";
|
||||
|
||||
|
||||
if (version.IsPreRelease)
|
||||
displayName += " (beta)";
|
||||
|
||||
|
||||
<SelectItem Value="@version.Identifier">
|
||||
@displayName
|
||||
</SelectItem>
|
||||
@@ -137,7 +136,7 @@
|
||||
|
||||
if (currentVersion != null)
|
||||
SelectedVersion = currentVersion.Identifier;
|
||||
|
||||
|
||||
Versions = (await HttpClient.GetFromJsonAsync<VersionDto[]>("api/admin/versions"))!;
|
||||
}
|
||||
|
||||
@@ -149,7 +148,7 @@
|
||||
parameters[nameof(UpdateInstanceModal.Version)] = SelectedVersion;
|
||||
parameters[nameof(UpdateInstanceModal.NoBuildCache)] = NoBuildCache;
|
||||
},
|
||||
onConfigure: model =>
|
||||
model =>
|
||||
{
|
||||
model.ShowCloseButton = false;
|
||||
model.ClassName = "sm:max-w-4xl!";
|
||||
@@ -1,14 +1,12 @@
|
||||
@inherits ShadcnBlazor.Extras.Dialogs.DialogBase
|
||||
|
||||
@using System.Text.Json
|
||||
@using LucideBlazor
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Events
|
||||
@using Moonlight.Shared.Http.Requests.Admin.ContainerHelper
|
||||
@using Moonlight.Shared.Admin.Sys.ContainerHelper
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.Dialogs
|
||||
@using ShadcnBlazor.Progresses
|
||||
@using ShadcnBlazor.Spinners
|
||||
@using SerializationContext = Moonlight.Shared.SerializationContext
|
||||
|
||||
@inject HttpClient HttpClient
|
||||
|
||||
@@ -121,7 +119,7 @@ else
|
||||
Progress = 20;
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
await HttpClient.PostAsJsonAsync("api/admin/ch/version", new SetVersionDto()
|
||||
await HttpClient.PostAsJsonAsync("api/admin/ch/version", new SetVersionDto
|
||||
{
|
||||
Version = Version
|
||||
}, SerializationContext.Default.Options);
|
||||
@@ -1,8 +1,9 @@
|
||||
@page "/admin/system"
|
||||
|
||||
@using LucideBlazor
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Moonlight.Frontend.Admin.Sys.HelperContainer
|
||||
@using Moonlight.Frontend.Admin.Sys.Settings
|
||||
@using Moonlight.Shared
|
||||
@using ShadcnBlazor.Tab
|
||||
|
||||
@@ -12,7 +13,7 @@
|
||||
<Tabs DefaultValue="@(Tab ?? "settings")" OnValueChanged="OnTabChanged">
|
||||
<TabsList ClassName="inline-flex w-full lg:w-fit justify-start overflow-x-auto overflow-y-hidden">
|
||||
<TabsTrigger Value="settings" Disabled="@(!SettingsResult.Succeeded)">
|
||||
<CogIcon />
|
||||
<CogIcon/>
|
||||
Settings
|
||||
</TabsTrigger>
|
||||
<TabsTrigger Value="themes" Disabled="@(!ThemesAccess.Succeeded)">
|
||||
@@ -35,31 +36,31 @@
|
||||
@if (SettingsResult.Succeeded)
|
||||
{
|
||||
<TabsContent Value="settings">
|
||||
<Settings />
|
||||
<Settings/>
|
||||
</TabsContent>
|
||||
}
|
||||
@if (DiagnoseResult.Succeeded)
|
||||
{
|
||||
<TabsContent Value="diagnose">
|
||||
<Diagnose />
|
||||
<Diagnose/>
|
||||
</TabsContent>
|
||||
}
|
||||
@if (ApiKeyAccess.Succeeded)
|
||||
{
|
||||
<TabsContent Value="apiKeys">
|
||||
<ApiKeys />
|
||||
<Moonlight.Frontend.Admin.Sys.ApiKeys.Index/>
|
||||
</TabsContent>
|
||||
}
|
||||
@if (ThemesAccess.Succeeded)
|
||||
{
|
||||
<TabsContent Value="themes">
|
||||
<Moonlight.Frontend.UI.Admin.Views.Sys.Themes.Index />
|
||||
<Moonlight.Frontend.Admin.Sys.Themes.Index/>
|
||||
</TabsContent>
|
||||
}
|
||||
@if (InstanceResult.Succeeded && VersionsResult.Succeeded)
|
||||
{
|
||||
<TabsContent Value="instance">
|
||||
<Instance />
|
||||
<Instance/>
|
||||
</TabsContent>
|
||||
}
|
||||
</Tabs>
|
||||
@@ -69,7 +70,7 @@
|
||||
[SupplyParameterFromQuery(Name = "tab")]
|
||||
[Parameter]
|
||||
public string? Tab { get; set; }
|
||||
|
||||
|
||||
[CascadingParameter] public Task<AuthenticationState> AuthState { get; set; }
|
||||
|
||||
private AuthorizationResult ApiKeyAccess;
|
||||
@@ -78,7 +79,7 @@
|
||||
private AuthorizationResult VersionsResult;
|
||||
private AuthorizationResult SettingsResult;
|
||||
private AuthorizationResult DiagnoseResult;
|
||||
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthState;
|
||||
@@ -1,12 +1,12 @@
|
||||
@page "/admin"
|
||||
@using LucideBlazor
|
||||
@using Moonlight.Frontend.UI.Admin.Modals
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Responses.Admin
|
||||
@using Moonlight.Frontend.Infrastructure.Helpers
|
||||
@using Moonlight.Shared.Admin.Sys
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.Cards
|
||||
@using ShadcnBlazor.Extras.Dialogs
|
||||
@using ShadcnBlazor.Spinners
|
||||
@using SerializationContext = Moonlight.Shared.SerializationContext
|
||||
|
||||
@inject HttpClient HttpClient
|
||||
@inject DialogService DialogService
|
||||
@@ -30,12 +30,12 @@
|
||||
<CardDescription>CPU Usage</CardDescription>
|
||||
<CardTitle ClassName="text-lg">@Math.Round(InfoResponse.CpuUsage, 2)%</CardTitle>
|
||||
<CardAction>
|
||||
<CpuIcon ClassName="size-6 text-muted-foreground" />
|
||||
<CpuIcon ClassName="size-6 text-muted-foreground"/>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
}
|
||||
</Card>
|
||||
|
||||
|
||||
<Card ClassName="col-span-1">
|
||||
@if (IsInfoLoading || InfoResponse == null)
|
||||
{
|
||||
@@ -49,12 +49,12 @@
|
||||
<CardDescription>Memory Usage</CardDescription>
|
||||
<CardTitle ClassName="text-lg">@Formatter.FormatSize(InfoResponse.MemoryUsage)</CardTitle>
|
||||
<CardAction>
|
||||
<MemoryStickIcon ClassName="size-6 text-muted-foreground" />
|
||||
<MemoryStickIcon ClassName="size-6 text-muted-foreground"/>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
}
|
||||
</Card>
|
||||
|
||||
|
||||
<Card ClassName="col-span-1">
|
||||
@if (IsInfoLoading || InfoResponse == null)
|
||||
{
|
||||
@@ -68,12 +68,12 @@
|
||||
<CardDescription>Operating System</CardDescription>
|
||||
<CardTitle ClassName="text-lg">@InfoResponse.OperatingSystem</CardTitle>
|
||||
<CardAction>
|
||||
<ComputerIcon ClassName="size-6 text-muted-foreground" />
|
||||
<ComputerIcon ClassName="size-6 text-muted-foreground"/>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
}
|
||||
</Card>
|
||||
|
||||
|
||||
<Card ClassName="col-span-1">
|
||||
@if (IsInfoLoading || InfoResponse == null)
|
||||
{
|
||||
@@ -87,12 +87,12 @@
|
||||
<CardDescription>Uptime</CardDescription>
|
||||
<CardTitle ClassName="text-lg">@Formatter.FormatDuration(InfoResponse.Uptime)</CardTitle>
|
||||
<CardAction>
|
||||
<ClockIcon ClassName="size-6 text-muted-foreground" />
|
||||
<ClockIcon ClassName="size-6 text-muted-foreground"/>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
}
|
||||
</Card>
|
||||
|
||||
|
||||
<Card ClassName="col-span-1">
|
||||
@if (IsInfoLoading || InfoResponse == null)
|
||||
{
|
||||
@@ -106,12 +106,12 @@
|
||||
<CardDescription>Version</CardDescription>
|
||||
<CardTitle ClassName="text-lg">@InfoResponse.VersionName</CardTitle>
|
||||
<CardAction>
|
||||
<RocketIcon ClassName="size-6 text-muted-foreground" />
|
||||
<RocketIcon ClassName="size-6 text-muted-foreground"/>
|
||||
</CardAction>
|
||||
</CardHeader>
|
||||
}
|
||||
</Card>
|
||||
|
||||
|
||||
<Card ClassName="col-span-1">
|
||||
@if (IsInfoLoading || InfoResponse == null)
|
||||
{
|
||||
@@ -127,7 +127,7 @@
|
||||
{
|
||||
<CardTitle ClassName="text-lg text-green-500">Up-to-date</CardTitle>
|
||||
<CardAction>
|
||||
<RefreshCwIcon ClassName="size-6 text-muted-foreground" />
|
||||
<RefreshCwIcon ClassName="size-6 text-muted-foreground"/>
|
||||
</CardAction>
|
||||
}
|
||||
else
|
||||
@@ -153,7 +153,7 @@
|
||||
|
||||
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||
{
|
||||
if(!firstRender)
|
||||
if (!firstRender)
|
||||
return;
|
||||
|
||||
InfoResponse = await HttpClient.GetFromJsonAsync<SystemInfoDto>("api/admin/system/info", SerializationContext.Default.Options);
|
||||
@@ -1,8 +1,6 @@
|
||||
@using Microsoft.Extensions.Options
|
||||
@using Moonlight.Frontend.Configuration
|
||||
@using ShadcnBlazor.Cards
|
||||
@using ShadcnBlazor.Sidebars
|
||||
|
||||
@inject IOptions<SystemSettingsOptions> Options
|
||||
|
||||
<div class="mt-5 flex flex-col md:flex-row gap-5">
|
||||
@@ -10,8 +8,9 @@
|
||||
<CardContent ClassName="px-2 flex flex-col gap-y-1 h-full max-h-[65vh] overflow-y-auto scrollbar-thin">
|
||||
@foreach (var menuPage in Pages)
|
||||
{
|
||||
<SidebarMenuButton @onclick="() => Navigate(menuPage)" IsActive="@(CurrentPage == menuPage)" ClassName="overflow-visible">
|
||||
<DynamicComponent Type="@menuPage.IconComponentType" />
|
||||
<SidebarMenuButton @onclick="() => Navigate(menuPage)" IsActive="@(CurrentPage == menuPage)"
|
||||
ClassName="overflow-visible">
|
||||
<DynamicComponent Type="@menuPage.IconComponentType"/>
|
||||
<span>@menuPage.Name</span>
|
||||
</SidebarMenuButton>
|
||||
}
|
||||
@@ -25,7 +24,7 @@
|
||||
<CardDescription>@CurrentPage.Description</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<DynamicComponent Type="@CurrentPage.ComponentType" />
|
||||
<DynamicComponent Type="@CurrentPage.ComponentType"/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
}
|
||||
@@ -48,5 +47,7 @@
|
||||
}
|
||||
|
||||
private void Navigate(SystemSettingsPage page)
|
||||
=> CurrentPage = page;
|
||||
{
|
||||
CurrentPage = page;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +1,39 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Moonlight.Frontend.Configuration;
|
||||
namespace Moonlight.Frontend.Admin.Sys.Settings;
|
||||
|
||||
public class SystemSettingsOptions
|
||||
{
|
||||
private readonly List<SystemSettingsPage> InnerComponents = new();
|
||||
public IReadOnlyList<SystemSettingsPage> Components => InnerComponents;
|
||||
|
||||
private readonly List<SystemSettingsPage> InnerComponents = new();
|
||||
|
||||
public void Add<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TIcon,
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TComponent>(string name, string description,
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
|
||||
TComponent>(string name, string description,
|
||||
int order)
|
||||
where TIcon : ComponentBase where TComponent : ComponentBase
|
||||
=> Add(name, description, order, typeof(TIcon), typeof(TComponent));
|
||||
{
|
||||
Add(name, description, order, typeof(TIcon), typeof(TComponent));
|
||||
}
|
||||
|
||||
public void Add(string name, string description, int order, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type iconComponent, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type component)
|
||||
=> InnerComponents.Add(new SystemSettingsPage(name, description, order, iconComponent, component));
|
||||
public void Add(string name, string description, int order,
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type iconComponent,
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type component)
|
||||
{
|
||||
InnerComponents.Add(new SystemSettingsPage(name, description, order, iconComponent, component));
|
||||
}
|
||||
|
||||
public void Remove<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TComponent>()
|
||||
where TComponent : ComponentBase
|
||||
=> Remove(typeof(TComponent));
|
||||
{
|
||||
Remove(typeof(TComponent));
|
||||
}
|
||||
|
||||
public void Remove([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type componentType)
|
||||
=> InnerComponents.RemoveAll(x => x.ComponentType == componentType);
|
||||
{
|
||||
InnerComponents.RemoveAll(x => x.ComponentType == componentType);
|
||||
}
|
||||
}
|
||||
|
||||
public record SystemSettingsPage(
|
||||
@@ -1,14 +1,13 @@
|
||||
@using LucideBlazor
|
||||
@using Moonlight.Frontend.Helpers
|
||||
@using Moonlight.Frontend.Services
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Requests.Admin.Settings
|
||||
@using Moonlight.Shared.Http.Responses.Admin.Settings
|
||||
@using Moonlight.Frontend.Infrastructure.Helpers
|
||||
@using Moonlight.Frontend.Shared.Frontend
|
||||
@using Moonlight.Shared.Admin.Sys.Settings
|
||||
@using ShadcnBlazor.Extras.Common
|
||||
@using ShadcnBlazor.Extras.Forms
|
||||
@using ShadcnBlazor.Extras.Toasts
|
||||
@using ShadcnBlazor.Fields
|
||||
@using ShadcnBlazor.Inputs
|
||||
@using SerializationContext = Moonlight.Shared.SerializationContext
|
||||
|
||||
@inject HttpClient HttpClient
|
||||
@inject ToastService ToastService
|
||||
@@ -16,11 +15,11 @@
|
||||
|
||||
<LazyLoader Load="LoadAsync">
|
||||
<EnhancedEditForm Model="Request" OnValidSubmit="OnValidSubmit">
|
||||
<DataAnnotationsValidator />
|
||||
|
||||
<DataAnnotationsValidator/>
|
||||
|
||||
<FieldSet>
|
||||
<FormValidationSummary />
|
||||
|
||||
<FormValidationSummary/>
|
||||
|
||||
<FieldGroup>
|
||||
<Field>
|
||||
<FieldLabel>Name</FieldLabel>
|
||||
@@ -46,8 +45,8 @@
|
||||
"api/admin/system/settings/whiteLabeling",
|
||||
SerializationContext.Default.Options
|
||||
);
|
||||
|
||||
Request = new SetWhiteLabelingDto()
|
||||
|
||||
Request = new SetWhiteLabelingDto
|
||||
{
|
||||
Name = dto!.Name
|
||||
};
|
||||
@@ -65,7 +64,7 @@
|
||||
{
|
||||
await FrontendService.ReloadAsync();
|
||||
await ToastService.SuccessAsync("Setting", "Successfully updated white labeling settings");
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
@page "/admin/system/themes/create"
|
||||
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Moonlight.Shared
|
||||
@using LucideBlazor
|
||||
@using Moonlight.Frontend.Helpers
|
||||
@using Moonlight.Frontend.Services
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Requests.Admin.Themes
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Moonlight.Frontend.Infrastructure.Helpers
|
||||
@using Moonlight.Frontend.Shared.Frontend
|
||||
@using Moonlight.Shared
|
||||
@using Moonlight.Shared.Admin.Sys.Themes
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.Cards
|
||||
@using ShadcnBlazor.Extras.Editors
|
||||
@@ -15,6 +13,7 @@
|
||||
@using ShadcnBlazor.Fields
|
||||
@using ShadcnBlazor.Inputs
|
||||
@using ShadcnBlazor.Switches
|
||||
@using SerializationContext = Moonlight.Shared.SerializationContext
|
||||
|
||||
@attribute [Authorize(Policy = Permissions.Themes.Create)]
|
||||
|
||||
@@ -109,7 +108,7 @@
|
||||
|
||||
@code
|
||||
{
|
||||
private CreateThemeDto Request = new()
|
||||
private readonly CreateThemeDto Request = new()
|
||||
{
|
||||
CssContent = "/* Define your css here */"
|
||||
};
|
||||
@@ -125,7 +124,7 @@
|
||||
Request,
|
||||
SerializationContext.Default.Options
|
||||
);
|
||||
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore);
|
||||
@@ -2,16 +2,15 @@
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Moonlight.Shared
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Requests
|
||||
@using Moonlight.Shared.Http.Responses
|
||||
@using Moonlight.Shared.Http.Responses.Admin.Themes
|
||||
@using Moonlight.Shared.Admin.Sys.Themes
|
||||
@using Moonlight.Shared.Shared
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.DataGrids
|
||||
@using ShadcnBlazor.Dropdowns
|
||||
@using ShadcnBlazor.Extras.AlertDialogs
|
||||
@using ShadcnBlazor.Tabels
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.Extras.Toasts
|
||||
@using ShadcnBlazor.Tabels
|
||||
@using SerializationContext = Moonlight.Shared.SerializationContext
|
||||
|
||||
@inject ToastService ToastService
|
||||
@inject NavigationManager Navigation
|
||||
@@ -143,11 +142,20 @@
|
||||
return new DataGridResponse<ThemeDto>(response!.Data, response.TotalLength);
|
||||
}
|
||||
|
||||
private void Create() => Navigation.NavigateTo("/admin/system/themes/create");
|
||||
private void Create()
|
||||
{
|
||||
Navigation.NavigateTo("/admin/system/themes/create");
|
||||
}
|
||||
|
||||
private void Edit(ThemeDto theme) => Navigation.NavigateTo($"/admin/system/themes/{theme.Id}");
|
||||
private void Edit(ThemeDto theme)
|
||||
{
|
||||
Navigation.NavigateTo($"/admin/system/themes/{theme.Id}");
|
||||
}
|
||||
|
||||
private void Download(ThemeDto theme) => Navigation.NavigateTo($"api/admin/themes/{theme.Id}/export", true);
|
||||
private void Download(ThemeDto theme)
|
||||
{
|
||||
Navigation.NavigateTo($"api/admin/themes/{theme.Id}/export", true);
|
||||
}
|
||||
|
||||
private async Task DeleteAsync(ThemeDto theme)
|
||||
{
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Moonlight.Shared.Http.Requests.Admin.Themes;
|
||||
using Moonlight.Shared.Http.Responses.Admin.Themes;
|
||||
using Moonlight.Shared.Admin.Sys.Themes;
|
||||
using Riok.Mapperly.Abstractions;
|
||||
|
||||
namespace Moonlight.Frontend.Mappers;
|
||||
namespace Moonlight.Frontend.Admin.Sys.Themes;
|
||||
|
||||
[Mapper]
|
||||
[SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")]
|
||||
@@ -1,14 +1,10 @@
|
||||
@page "/admin/system/themes/{Id:int}"
|
||||
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Moonlight.Shared
|
||||
@using LucideBlazor
|
||||
@using Moonlight.Frontend.Helpers
|
||||
@using Moonlight.Frontend.Mappers
|
||||
@using Moonlight.Frontend.Services
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Requests.Admin.Themes
|
||||
@using Moonlight.Shared.Http.Responses.Admin.Themes
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Moonlight.Frontend.Infrastructure.Helpers
|
||||
@using Moonlight.Frontend.Shared.Frontend
|
||||
@using Moonlight.Shared
|
||||
@using Moonlight.Shared.Admin.Sys.Themes
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.Cards
|
||||
@using ShadcnBlazor.Extras.Common
|
||||
@@ -18,6 +14,7 @@
|
||||
@using ShadcnBlazor.Fields
|
||||
@using ShadcnBlazor.Inputs
|
||||
@using ShadcnBlazor.Switches
|
||||
@using SerializationContext = Moonlight.Shared.SerializationContext
|
||||
|
||||
@attribute [Authorize(Policy = Permissions.Themes.Edit)]
|
||||
|
||||
@@ -139,7 +136,7 @@
|
||||
Request,
|
||||
SerializationContext.Default.Options
|
||||
);
|
||||
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore);
|
||||
@@ -1,6 +1,8 @@
|
||||
@page "/admin/users"
|
||||
@using LucideBlazor
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Moonlight.Frontend.Admin.Users.Roles
|
||||
@using Moonlight.Frontend.Admin.Users.Users
|
||||
@using Moonlight.Shared
|
||||
@using ShadcnBlazor.Tab
|
||||
|
||||
@@ -11,19 +13,19 @@
|
||||
<Tabs DefaultValue="@(Tab ?? "users")" OnValueChanged="OnTabChanged">
|
||||
<TabsList ClassName="inline-flex w-full lg:w-fit justify-start overflow-x-auto overflow-y-hidden">
|
||||
<TabsTrigger Value="users">
|
||||
<UserRoundIcon />
|
||||
<UserRoundIcon/>
|
||||
Users
|
||||
</TabsTrigger>
|
||||
<TabsTrigger Value="roles">
|
||||
<UsersRoundIcon />
|
||||
<UsersRoundIcon/>
|
||||
Roles
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent Value="users">
|
||||
<Users />
|
||||
<Users/>
|
||||
</TabsContent>
|
||||
<TabsContent Value="roles">
|
||||
<Roles />
|
||||
<Roles/>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
@using Moonlight.Frontend.Helpers
|
||||
@using Moonlight.Frontend.UI.Admin.Components
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Requests.Admin.Roles
|
||||
@using Moonlight.Frontend.Admin.Users.Shared
|
||||
@using Moonlight.Frontend.Infrastructure.Helpers
|
||||
@using Moonlight.Shared.Admin.Users.Roles
|
||||
@using ShadcnBlazor.Dialogs
|
||||
@using ShadcnBlazor.Extras.Forms
|
||||
@using ShadcnBlazor.Extras.Toasts
|
||||
@using ShadcnBlazor.Fields
|
||||
@using ShadcnBlazor.Inputs
|
||||
@using SerializationContext = Moonlight.Shared.SerializationContext
|
||||
|
||||
@inherits ShadcnBlazor.Extras.Dialogs.DialogBase
|
||||
|
||||
@@ -62,24 +62,24 @@
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Request = new()
|
||||
Request = new CreateRoleDto
|
||||
{
|
||||
Permissions = []
|
||||
};
|
||||
|
||||
Permissions = new();
|
||||
Permissions = new List<string>();
|
||||
}
|
||||
|
||||
private async Task<bool> OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore)
|
||||
{
|
||||
Request.Permissions = Permissions.ToArray();
|
||||
|
||||
|
||||
var response = await HttpClient.PostAsJsonAsync(
|
||||
"api/admin/roles",
|
||||
Request,
|
||||
SerializationContext.Default.Options
|
||||
);
|
||||
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore);
|
||||
@@ -1,7 +1,7 @@
|
||||
@using LucideBlazor
|
||||
@using Moonlight.Shared.Http.Responses
|
||||
@using Moonlight.Shared.Http.Responses.Admin
|
||||
@using Moonlight.Shared.Http.Responses.Admin.Users
|
||||
@using Moonlight.Shared.Admin.Users.Roles
|
||||
@using Moonlight.Shared.Admin.Users.Users
|
||||
@using Moonlight.Shared.Shared
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.DataGrids
|
||||
@using ShadcnBlazor.Dialogs
|
||||
@@ -9,7 +9,6 @@
|
||||
@using ShadcnBlazor.Extras.Common
|
||||
@using ShadcnBlazor.Labels
|
||||
@using ShadcnBlazor.Tabels
|
||||
|
||||
@inherits ShadcnBlazor.Extras.Dialogs.DialogBase
|
||||
|
||||
@inject HttpClient HttpClient
|
||||
@@ -50,7 +49,8 @@
|
||||
<CellTemplate>
|
||||
<TableCell>
|
||||
<div class="flex justify-end me-1.5">
|
||||
<WButton OnClick="_ => RemoveAsync(context)" Variant="ButtonVariant.Destructive" Size="ButtonSize.Icon">
|
||||
<WButton OnClick="_ => RemoveAsync(context)" Variant="ButtonVariant.Destructive"
|
||||
Size="ButtonSize.Icon">
|
||||
<TrashIcon/>
|
||||
</WButton>
|
||||
</div>
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Moonlight.Shared.Http.Requests.Admin.Roles;
|
||||
using Moonlight.Shared.Http.Responses.Admin;
|
||||
using Moonlight.Shared.Admin.Users.Roles;
|
||||
using Riok.Mapperly.Abstractions;
|
||||
|
||||
namespace Moonlight.Frontend.Mappers;
|
||||
namespace Moonlight.Frontend.Admin.Users.Roles;
|
||||
|
||||
[Mapper]
|
||||
[SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")]
|
||||
@@ -1,19 +1,17 @@
|
||||
@using LucideBlazor
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Moonlight.Frontend.UI.Admin.Modals
|
||||
@using Moonlight.Shared
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Requests
|
||||
@using Moonlight.Shared.Http.Responses
|
||||
@using Moonlight.Shared.Http.Responses.Admin
|
||||
@using ShadcnBlazor.DataGrids
|
||||
@using Moonlight.Shared.Admin.Users.Roles
|
||||
@using Moonlight.Shared.Shared
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.DataGrids
|
||||
@using ShadcnBlazor.Dropdowns
|
||||
@using ShadcnBlazor.Extras.AlertDialogs
|
||||
@using ShadcnBlazor.Extras.Dialogs
|
||||
@using ShadcnBlazor.Extras.Toasts
|
||||
@using ShadcnBlazor.Tabels
|
||||
@using SerializationContext = Moonlight.Shared.SerializationContext
|
||||
|
||||
@inject HttpClient HttpClient
|
||||
@inject DialogService DialogService
|
||||
@@ -67,13 +65,15 @@
|
||||
</Slot>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent SideOffset="2">
|
||||
<DropdownMenuItem OnClick="() => MembersAsync(context)" Disabled="@(!MembersAccess.Succeeded)">
|
||||
<DropdownMenuItem OnClick="() => MembersAsync(context)"
|
||||
Disabled="@(!MembersAccess.Succeeded)">
|
||||
Members
|
||||
<DropdownMenuShortcut>
|
||||
<UsersRoundIcon/>
|
||||
</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem OnClick="() => EditAsync(context)" Disabled="@(!EditAccess.Succeeded)">
|
||||
<DropdownMenuItem OnClick="() => EditAsync(context)"
|
||||
Disabled="@(!EditAccess.Succeeded)">
|
||||
Edit
|
||||
<DropdownMenuShortcut>
|
||||
<PenIcon/>
|
||||
@@ -99,7 +99,7 @@
|
||||
@code
|
||||
{
|
||||
[CascadingParameter] public Task<AuthenticationState> AuthState { get; set; }
|
||||
|
||||
|
||||
private DataGrid<RoleDto> Grid;
|
||||
|
||||
private AuthorizationResult MembersAccess;
|
||||
@@ -110,7 +110,7 @@
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthState;
|
||||
|
||||
|
||||
MembersAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.Roles.Members);
|
||||
EditAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.Roles.Edit);
|
||||
DeleteAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.Roles.Delete);
|
||||
@@ -132,13 +132,7 @@
|
||||
|
||||
private async Task CreateAsync()
|
||||
{
|
||||
await DialogService.LaunchAsync<CreateRoleDialog>(parameters =>
|
||||
{
|
||||
parameters[nameof(CreateRoleDialog.OnSubmit)] = async Task () =>
|
||||
{
|
||||
await Grid.RefreshAsync();
|
||||
};
|
||||
});
|
||||
await DialogService.LaunchAsync<CreateRoleDialog>(parameters => { parameters[nameof(CreateRoleDialog.OnSubmit)] = async Task () => { await Grid.RefreshAsync(); }; });
|
||||
}
|
||||
|
||||
private async Task EditAsync(RoleDto role)
|
||||
@@ -146,10 +140,7 @@
|
||||
await DialogService.LaunchAsync<UpdateRoleDialog>(parameters =>
|
||||
{
|
||||
parameters[nameof(UpdateRoleDialog.Role)] = role;
|
||||
parameters[nameof(UpdateRoleDialog.OnSubmit)] = async Task () =>
|
||||
{
|
||||
await Grid.RefreshAsync();
|
||||
};
|
||||
parameters[nameof(UpdateRoleDialog.OnSubmit)] = async Task () => { await Grid.RefreshAsync(); };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -160,7 +151,7 @@
|
||||
await ToastService.ErrorAsync("Permission denied", "You dont have the required permission to manage members");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await DialogService.LaunchAsync<ManageRoleMembersDialog>(parameters => { parameters[nameof(ManageRoleMembersDialog.Role)] = role; }, model => { model.ClassName = "sm:max-w-xl"; });
|
||||
}
|
||||
|
||||
@@ -173,7 +164,7 @@
|
||||
{
|
||||
var response = await HttpClient.DeleteAsync($"api/admin/roles/{role.Id}");
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
|
||||
await ToastService.SuccessAsync("User deletion", $"Successfully deleted role {role.Name}");
|
||||
|
||||
await Grid.RefreshAsync();
|
||||
@@ -1,14 +1,12 @@
|
||||
@using Moonlight.Frontend.Helpers
|
||||
@using Moonlight.Frontend.Mappers
|
||||
@using Moonlight.Frontend.UI.Admin.Components
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Requests.Admin.Roles
|
||||
@using Moonlight.Shared.Http.Responses.Admin
|
||||
@using Moonlight.Frontend.Admin.Users.Shared
|
||||
@using Moonlight.Frontend.Infrastructure.Helpers
|
||||
@using Moonlight.Shared.Admin.Users.Roles
|
||||
@using ShadcnBlazor.Dialogs
|
||||
@using ShadcnBlazor.Extras.Forms
|
||||
@using ShadcnBlazor.Extras.Toasts
|
||||
@using ShadcnBlazor.Fields
|
||||
@using ShadcnBlazor.Inputs
|
||||
@using SerializationContext = Moonlight.Shared.SerializationContext
|
||||
|
||||
@inherits ShadcnBlazor.Extras.Dialogs.DialogBase
|
||||
|
||||
@@ -72,13 +70,13 @@
|
||||
private async Task<bool> OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore)
|
||||
{
|
||||
Request.Permissions = Permissions.ToArray();
|
||||
|
||||
|
||||
var response = await HttpClient.PatchAsJsonAsync(
|
||||
$"api/admin/roles/{Role.Id}",
|
||||
Request,
|
||||
SerializationContext.Default.Options
|
||||
);
|
||||
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore);
|
||||
@@ -86,7 +84,7 @@
|
||||
}
|
||||
|
||||
await ToastService.SuccessAsync("Role update", $"Role {Request.Name} has been successfully updated");
|
||||
|
||||
|
||||
await OnSubmit.Invoke();
|
||||
await CloseAsync();
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Moonlight.Frontend.Models;
|
||||
namespace Moonlight.Frontend.Admin.Users.Shared;
|
||||
|
||||
public class Permission
|
||||
{
|
||||
public string Identifier { get; init; }
|
||||
public string Name { get; init; }
|
||||
public string Description { get; init; }
|
||||
|
||||
public Permission(string identifier, string name, string description)
|
||||
{
|
||||
Identifier = identifier;
|
||||
Name = name;
|
||||
Description = description;
|
||||
}
|
||||
|
||||
public string Identifier { get; init; }
|
||||
public string Name { get; init; }
|
||||
public string Description { get; init; }
|
||||
}
|
||||
@@ -1,21 +1,22 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Moonlight.Frontend.Models;
|
||||
namespace Moonlight.Frontend.Admin.Users.Shared;
|
||||
|
||||
public record PermissionCategory
|
||||
{
|
||||
public string Name { get; init; }
|
||||
|
||||
// Used to prevent the IL-Trimming from removing this type as its dynamically assigned a type, and we
|
||||
// need it to work properly
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
|
||||
public Type Icon { get; init; }
|
||||
public Permission[] Permissions { get; init; }
|
||||
|
||||
public PermissionCategory(string name, Type icon, Permission[] permissions)
|
||||
{
|
||||
Name = name;
|
||||
Icon = icon;
|
||||
Permissions = permissions;
|
||||
}
|
||||
|
||||
public string Name { get; init; }
|
||||
|
||||
// Used to prevent the IL-Trimming from removing this type as its dynamically assigned a type, and we
|
||||
// need it to work properly
|
||||
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
|
||||
public Type Icon { get; init; }
|
||||
|
||||
public Permission[] Permissions { get; init; }
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
@using Moonlight.Frontend.Interfaces
|
||||
@using Moonlight.Frontend.Models
|
||||
@using ShadcnBlazor.Extras.Common
|
||||
@using Moonlight.Frontend.Infrastructure.Hooks
|
||||
@using ShadcnBlazor.Accordions
|
||||
@using ShadcnBlazor.Checkboxes
|
||||
@using ShadcnBlazor.Extras.Common
|
||||
@using ShadcnBlazor.Labels
|
||||
|
||||
@inject IEnumerable<IPermissionProvider> Providers
|
||||
|
||||
<LazyLoader Load="LoadAsync">
|
||||
@@ -1,12 +1,11 @@
|
||||
@using Moonlight.Frontend.Helpers
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Requests.Admin.Users
|
||||
@using Moonlight.Shared.Http.Responses
|
||||
@using Moonlight.Frontend.Infrastructure.Helpers
|
||||
@using Moonlight.Shared.Admin.Users.Users
|
||||
@using ShadcnBlazor.Dialogs
|
||||
@using ShadcnBlazor.Extras.Forms
|
||||
@using ShadcnBlazor.Extras.Toasts
|
||||
@using ShadcnBlazor.Fields
|
||||
@using ShadcnBlazor.Inputs
|
||||
@using SerializationContext = Moonlight.Shared.SerializationContext
|
||||
|
||||
@inherits ShadcnBlazor.Extras.Dialogs.DialogBase
|
||||
|
||||
@@ -26,7 +25,7 @@
|
||||
|
||||
<FieldGroup>
|
||||
<FormValidationSummary/>
|
||||
<DataAnnotationsValidator />
|
||||
<DataAnnotationsValidator/>
|
||||
|
||||
<FieldSet>
|
||||
<Field>
|
||||
@@ -58,7 +57,7 @@
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
Request = new();
|
||||
Request = new CreateUserDto();
|
||||
}
|
||||
|
||||
private async Task<bool> OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore)
|
||||
@@ -1,14 +1,10 @@
|
||||
@using Moonlight.Frontend.Helpers
|
||||
@using Moonlight.Frontend.Mappers
|
||||
@using Moonlight.Shared.Http.Requests.Admin.Users
|
||||
@using Moonlight.Shared.Http.Responses
|
||||
@using Moonlight.Shared.Http.Responses.Admin.Users
|
||||
@using Moonlight.Frontend.Infrastructure.Helpers
|
||||
@using Moonlight.Shared.Admin.Users.Users
|
||||
@using ShadcnBlazor.Dialogs
|
||||
@using ShadcnBlazor.Extras.Forms
|
||||
@using ShadcnBlazor.Extras.Toasts
|
||||
@using ShadcnBlazor.Fields
|
||||
@using ShadcnBlazor.Inputs
|
||||
|
||||
@inherits ShadcnBlazor.Extras.Dialogs.DialogBase
|
||||
|
||||
@inject HttpClient HttpClient
|
||||
@@ -68,7 +64,7 @@
|
||||
$"/api/admin/users/{User.Id}",
|
||||
Request
|
||||
);
|
||||
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore);
|
||||
@@ -79,7 +75,7 @@
|
||||
"User update",
|
||||
$"Successfully updated user {Request.Username}"
|
||||
);
|
||||
|
||||
|
||||
await OnCompleted.Invoke();
|
||||
await CloseAsync();
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Moonlight.Shared.Http.Requests.Admin.Users;
|
||||
using Moonlight.Shared.Http.Responses.Admin.Users;
|
||||
using Moonlight.Shared.Admin.Users.Users;
|
||||
using Riok.Mapperly.Abstractions;
|
||||
|
||||
namespace Moonlight.Frontend.Mappers;
|
||||
namespace Moonlight.Frontend.Admin.Users.Users;
|
||||
|
||||
[Mapper]
|
||||
[SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")]
|
||||
@@ -1,19 +1,17 @@
|
||||
@using LucideBlazor
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Moonlight.Frontend.UI.Admin.Modals
|
||||
@using Moonlight.Shared
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Admin.Users.Users
|
||||
@using Moonlight.Shared.Shared
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.DataGrids
|
||||
@using ShadcnBlazor.Dropdowns
|
||||
@using ShadcnBlazor.Extras.AlertDialogs
|
||||
@using ShadcnBlazor.Extras.Dialogs
|
||||
@using ShadcnBlazor.Extras.Toasts
|
||||
@using ShadcnBlazor.Tabels
|
||||
@using Moonlight.Shared.Http.Requests
|
||||
@using Moonlight.Shared.Http.Responses
|
||||
@using Moonlight.Shared.Http.Responses.Admin.Users
|
||||
@using ShadcnBlazor.Extras.Dialogs
|
||||
@using SerializationContext = Moonlight.Shared.SerializationContext
|
||||
|
||||
@inject HttpClient HttpClient
|
||||
@inject AlertDialogService AlertDialogService
|
||||
@@ -65,13 +63,15 @@
|
||||
</Slot>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent SideOffset="2">
|
||||
<DropdownMenuItem OnClick="() => LogoutAsync(context)" Disabled="@(!LogoutAccess.Succeeded)">
|
||||
<DropdownMenuItem OnClick="() => LogoutAsync(context)"
|
||||
Disabled="@(!LogoutAccess.Succeeded)">
|
||||
Logout
|
||||
<DropdownMenuShortcut>
|
||||
<LogOutIcon/>
|
||||
</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem OnClick="() => EditAsync(context)" Disabled="@(!EditAccess.Succeeded)">
|
||||
<DropdownMenuItem OnClick="() => EditAsync(context)"
|
||||
Disabled="@(!EditAccess.Succeeded)">
|
||||
Edit
|
||||
<DropdownMenuShortcut>
|
||||
<PenIcon/>
|
||||
@@ -97,9 +97,9 @@
|
||||
@code
|
||||
{
|
||||
[CascadingParameter] public Task<AuthenticationState> AuthState { get; set; }
|
||||
|
||||
|
||||
private DataGrid<UserDto> Grid;
|
||||
|
||||
|
||||
private AuthorizationResult LogoutAccess;
|
||||
private AuthorizationResult EditAccess;
|
||||
private AuthorizationResult DeleteAccess;
|
||||
@@ -108,7 +108,7 @@
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthState;
|
||||
|
||||
|
||||
LogoutAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.Users.Logout);
|
||||
EditAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.Users.Edit);
|
||||
DeleteAccess = await AuthorizationService.AuthorizeAsync(authState.User, Permissions.Users.Delete);
|
||||
@@ -130,13 +130,7 @@
|
||||
|
||||
private async Task CreateAsync()
|
||||
{
|
||||
await DialogService.LaunchAsync<CreateUserDialog>(parameters =>
|
||||
{
|
||||
parameters[nameof(CreateUserDialog.OnCompleted)] = async () =>
|
||||
{
|
||||
await Grid.RefreshAsync();
|
||||
};
|
||||
});
|
||||
await DialogService.LaunchAsync<CreateUserDialog>(parameters => { parameters[nameof(CreateUserDialog.OnCompleted)] = async () => { await Grid.RefreshAsync(); }; });
|
||||
}
|
||||
|
||||
private async Task EditAsync(UserDto user)
|
||||
@@ -144,10 +138,7 @@
|
||||
await DialogService.LaunchAsync<UpdateUserDialog>(parameters =>
|
||||
{
|
||||
parameters[nameof(UpdateUserDialog.User)] = user;
|
||||
parameters[nameof(UpdateUserDialog.OnCompleted)] = async () =>
|
||||
{
|
||||
await Grid.RefreshAsync();
|
||||
};
|
||||
parameters[nameof(UpdateUserDialog.OnCompleted)] = async () => { await Grid.RefreshAsync(); };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
using LucideBlazor;
|
||||
using Moonlight.Frontend.Interfaces;
|
||||
using Moonlight.Frontend.Models;
|
||||
using Moonlight.Shared;
|
||||
|
||||
namespace Moonlight.Frontend.Implementations;
|
||||
|
||||
public sealed class PermissionProvider : IPermissionProvider
|
||||
{
|
||||
public Task<PermissionCategory[]> GetPermissionsAsync()
|
||||
{
|
||||
return Task.FromResult<PermissionCategory[]>([
|
||||
new PermissionCategory("Users", typeof(UserRoundIcon), [
|
||||
new Permission(Permissions.Users.Create, "Create", "Create new users"),
|
||||
new Permission(Permissions.Users.View, "View", "View all users"),
|
||||
new Permission(Permissions.Users.Edit, "Edit", "Edit user details"),
|
||||
new Permission(Permissions.Users.Delete, "Delete", "Delete user accounts"),
|
||||
new Permission(Permissions.Users.Logout, "Logout", "Logout user accounts"),
|
||||
]),
|
||||
new PermissionCategory("Roles", typeof(UsersRoundIcon), [
|
||||
new Permission(Permissions.Roles.Create, "Create", "Create new roles"),
|
||||
new Permission(Permissions.Roles.View, "View", "View all roles"),
|
||||
new Permission(Permissions.Roles.Edit, "Edit", "Edit role details"),
|
||||
new Permission(Permissions.Roles.Delete, "Delete", "Delete role accounts"),
|
||||
new Permission(Permissions.Roles.Members, "Members", "Manage role members"),
|
||||
]),
|
||||
new PermissionCategory("System", typeof(CogIcon), [
|
||||
new Permission(Permissions.System.Info, "Info", "View system info"),
|
||||
new Permission(Permissions.System.Diagnose, "Diagnose", "Run diagnostics"),
|
||||
new Permission(Permissions.System.Versions, "Versions", "Look at the available versions"),
|
||||
new Permission(Permissions.System.Instance, "Instance", "Update the moonlight instance and add plugins"),
|
||||
new Permission(Permissions.System.Settings, "Settings", "Change settings of the instance"),
|
||||
]),
|
||||
new PermissionCategory("API Keys", typeof(KeyIcon), [
|
||||
new Permission(Permissions.ApiKeys.Create, "Create", "Create new API keys"),
|
||||
new Permission(Permissions.ApiKeys.View, "View", "View all API keys"),
|
||||
new Permission(Permissions.ApiKeys.Edit, "Edit", "Edit API key details"),
|
||||
new Permission(Permissions.ApiKeys.Delete, "Delete", "Delete API keys"),
|
||||
]),
|
||||
new PermissionCategory("Themes", typeof(PaintRollerIcon), [
|
||||
new Permission(Permissions.Themes.Create, "Create", "Create new theme"),
|
||||
new Permission(Permissions.Themes.View, "View", "View all themes"),
|
||||
new Permission(Permissions.Themes.Edit, "Edit", "Edit themes"),
|
||||
new Permission(Permissions.Themes.Delete, "Delete", "Delete themes"),
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,26 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Moonlight.Frontend.Interfaces;
|
||||
using Moonlight.Frontend.Infrastructure.Hooks;
|
||||
|
||||
namespace Moonlight.Frontend.Configuration;
|
||||
namespace Moonlight.Frontend.Infrastructure.Configuration;
|
||||
|
||||
public class LayoutMiddlewareOptions
|
||||
{
|
||||
public IReadOnlyList<Type> Components => InnerComponents;
|
||||
|
||||
private readonly List<Type> InnerComponents = new();
|
||||
public IReadOnlyList<Type> Components => InnerComponents;
|
||||
|
||||
public void Add<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() where T : LayoutMiddlewareBase
|
||||
{
|
||||
InnerComponents.Add(typeof(T));
|
||||
}
|
||||
|
||||
public void Insert<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(int index) where T : LayoutMiddlewareBase
|
||||
|
||||
public void Insert<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(int index)
|
||||
where T : LayoutMiddlewareBase
|
||||
{
|
||||
InnerComponents.Insert(index, typeof(T));
|
||||
}
|
||||
|
||||
public void Remove<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>() where T : LayoutMiddlewareBase
|
||||
public void Remove<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
|
||||
where T : LayoutMiddlewareBase
|
||||
{
|
||||
InnerComponents.Remove(typeof(T));
|
||||
}
|
||||
@@ -1,27 +1,34 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Moonlight.Frontend.Configuration;
|
||||
namespace Moonlight.Frontend.Infrastructure.Configuration;
|
||||
|
||||
public class LayoutPageOptions
|
||||
{
|
||||
public IReadOnlyList<LayoutPageComponent> Components => InnerComponents;
|
||||
|
||||
private readonly List<LayoutPageComponent> InnerComponents = new();
|
||||
public IReadOnlyList<LayoutPageComponent> Components => InnerComponents;
|
||||
|
||||
public void Add<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>(LayoutPageSlot slot, int order)
|
||||
where T : ComponentBase
|
||||
=> Add(typeof(T), slot, order);
|
||||
|
||||
{
|
||||
Add(typeof(T), slot, order);
|
||||
}
|
||||
|
||||
public void Add(Type componentType, LayoutPageSlot slot, int order)
|
||||
=> InnerComponents.Add(new LayoutPageComponent(componentType, order, slot));
|
||||
{
|
||||
InnerComponents.Add(new LayoutPageComponent(componentType, order, slot));
|
||||
}
|
||||
|
||||
public void Remove<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>()
|
||||
where T : ComponentBase
|
||||
=> Remove(typeof(T));
|
||||
{
|
||||
Remove(typeof(T));
|
||||
}
|
||||
|
||||
public void Remove(Type componentType)
|
||||
=> InnerComponents.RemoveAll(x => x.ComponentType == componentType);
|
||||
{
|
||||
InnerComponents.RemoveAll(x => x.ComponentType == componentType);
|
||||
}
|
||||
}
|
||||
|
||||
public record LayoutPageComponent(Type ComponentType, int Order, LayoutPageSlot Slot);
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Reflection;
|
||||
|
||||
namespace Moonlight.Frontend.Configuration;
|
||||
namespace Moonlight.Frontend.Infrastructure.Configuration;
|
||||
|
||||
public class NavigationAssemblyOptions
|
||||
{
|
||||
@@ -1,44 +1,44 @@
|
||||
namespace Moonlight.Frontend;
|
||||
namespace Moonlight.Frontend.Infrastructure.Helpers;
|
||||
|
||||
public static class Formatter
|
||||
{
|
||||
public static string FormatSize(long bytes, double conversionStep = 1024)
|
||||
{
|
||||
if (bytes == 0) return "0 B";
|
||||
|
||||
|
||||
string[] units = ["B", "KB", "MB", "GB", "TB", "PB", "EB"];
|
||||
var unitIndex = 0;
|
||||
double size = bytes;
|
||||
|
||||
|
||||
while (size >= conversionStep && unitIndex < units.Length - 1)
|
||||
{
|
||||
size /= conversionStep;
|
||||
unitIndex++;
|
||||
}
|
||||
|
||||
|
||||
var decimals = unitIndex == 0 ? 0 : 2;
|
||||
return $"{Math.Round(size, decimals)} {units[unitIndex]}";
|
||||
}
|
||||
|
||||
|
||||
public static string FormatDuration(TimeSpan timeSpan)
|
||||
{
|
||||
var abs = timeSpan.Duration(); // Handle negative timespans
|
||||
|
||||
|
||||
if (abs.TotalSeconds < 1)
|
||||
return $"{abs.TotalMilliseconds:F0}ms";
|
||||
|
||||
|
||||
if (abs.TotalMinutes < 1)
|
||||
return $"{abs.TotalSeconds:F1}s";
|
||||
|
||||
|
||||
if (abs.TotalHours < 1)
|
||||
return $"{abs.Minutes}m {abs.Seconds}s";
|
||||
|
||||
|
||||
if (abs.TotalDays < 1)
|
||||
return $"{abs.Hours}h {abs.Minutes}m";
|
||||
|
||||
|
||||
if (abs.TotalDays < 365)
|
||||
return $"{abs.Days}d {abs.Hours}h";
|
||||
|
||||
|
||||
var years = (int)(abs.TotalDays / 365);
|
||||
var days = abs.Days % 365;
|
||||
return days > 0 ? $"{years}y {days}d" : $"{years}y";
|
||||
@@ -1,30 +1,29 @@
|
||||
using System.Net.Http.Json;
|
||||
using Microsoft.AspNetCore.Components.Forms;
|
||||
using Moonlight.Shared.Http.Responses;
|
||||
using Moonlight.Shared.Shared;
|
||||
|
||||
namespace Moonlight.Frontend.Helpers;
|
||||
namespace Moonlight.Frontend.Infrastructure.Helpers;
|
||||
|
||||
public static class ProblemDetailsHelper
|
||||
{
|
||||
public static async Task HandleProblemDetailsAsync(HttpResponseMessage response, object model, ValidationMessageStore validationMessageStore)
|
||||
public static async Task HandleProblemDetailsAsync(HttpResponseMessage response, object model,
|
||||
ValidationMessageStore validationMessageStore)
|
||||
{
|
||||
var problemDetails = await response.Content.ReadFromJsonAsync<ProblemDetails>();
|
||||
|
||||
if (problemDetails == null)
|
||||
{
|
||||
response.EnsureSuccessStatusCode(); // Trigger exception when unable to parse
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!string.IsNullOrEmpty(problemDetails.Detail))
|
||||
if (!string.IsNullOrEmpty(problemDetails.Detail))
|
||||
validationMessageStore.Add(new FieldIdentifier(model, string.Empty), problemDetails.Detail);
|
||||
|
||||
if (problemDetails.Errors != null)
|
||||
{
|
||||
foreach (var error in problemDetails.Errors)
|
||||
{
|
||||
foreach (var message in error.Value)
|
||||
validationMessageStore.Add(new FieldIdentifier(model, error.Key), message);
|
||||
}
|
||||
}
|
||||
foreach (var message in error.Value)
|
||||
validationMessageStore.Add(new FieldIdentifier(model, error.Key), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using Moonlight.Frontend.Models;
|
||||
using Moonlight.Frontend.Admin.Users.Shared;
|
||||
|
||||
namespace Moonlight.Frontend.Interfaces;
|
||||
namespace Moonlight.Frontend.Infrastructure.Hooks;
|
||||
|
||||
public interface IPermissionProvider
|
||||
{
|
||||
@@ -0,0 +1,8 @@
|
||||
using Moonlight.Frontend.Infrastructure.Models;
|
||||
|
||||
namespace Moonlight.Frontend.Infrastructure.Hooks;
|
||||
|
||||
public interface ISidebarProvider
|
||||
{
|
||||
public Task<SidebarItem[]> GetItemsAsync();
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Moonlight.Frontend.Interfaces;
|
||||
namespace Moonlight.Frontend.Infrastructure.Hooks;
|
||||
|
||||
public abstract class LayoutMiddlewareBase : ComponentBase
|
||||
{
|
||||
@@ -1,7 +1,7 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Moonlight.Shared;
|
||||
|
||||
namespace Moonlight.Frontend.Implementations;
|
||||
namespace Moonlight.Frontend.Infrastructure.Implementations;
|
||||
|
||||
public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
|
||||
{
|
||||
@@ -2,22 +2,22 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moonlight.Shared;
|
||||
|
||||
namespace Moonlight.Frontend.Implementations;
|
||||
namespace Moonlight.Frontend.Infrastructure.Implementations;
|
||||
|
||||
public class PermissionPolicyProvider : IAuthorizationPolicyProvider
|
||||
{
|
||||
private readonly DefaultAuthorizationPolicyProvider FallbackProvider;
|
||||
|
||||
|
||||
public PermissionPolicyProvider(IOptions<AuthorizationOptions> options)
|
||||
{
|
||||
FallbackProvider = new DefaultAuthorizationPolicyProvider(options);
|
||||
}
|
||||
|
||||
|
||||
public async Task<AuthorizationPolicy?> GetPolicyAsync(string policyName)
|
||||
{
|
||||
if (!policyName.StartsWith(Permissions.Prefix, StringComparison.OrdinalIgnoreCase))
|
||||
return await FallbackProvider.GetPolicyAsync(policyName);
|
||||
|
||||
|
||||
var policy = new AuthorizationPolicyBuilder();
|
||||
policy.AddRequirements(new PermissionRequirement(policyName));
|
||||
|
||||
@@ -25,18 +25,22 @@ public class PermissionPolicyProvider : IAuthorizationPolicyProvider
|
||||
}
|
||||
|
||||
public Task<AuthorizationPolicy> GetDefaultPolicyAsync()
|
||||
=> FallbackProvider.GetDefaultPolicyAsync();
|
||||
{
|
||||
return FallbackProvider.GetDefaultPolicyAsync();
|
||||
}
|
||||
|
||||
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync()
|
||||
=> FallbackProvider.GetFallbackPolicyAsync();
|
||||
{
|
||||
return FallbackProvider.GetFallbackPolicyAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public class PermissionRequirement : IAuthorizationRequirement
|
||||
{
|
||||
public string Identifier { get; }
|
||||
|
||||
public PermissionRequirement(string identifier)
|
||||
{
|
||||
Identifier = identifier;
|
||||
}
|
||||
|
||||
public string Identifier { get; }
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using LucideBlazor;
|
||||
using Moonlight.Frontend.Admin.Users.Shared;
|
||||
using Moonlight.Frontend.Infrastructure.Hooks;
|
||||
using Moonlight.Shared;
|
||||
|
||||
namespace Moonlight.Frontend.Infrastructure.Implementations;
|
||||
|
||||
public sealed class PermissionProvider : IPermissionProvider
|
||||
{
|
||||
public Task<PermissionCategory[]> GetPermissionsAsync()
|
||||
{
|
||||
return Task.FromResult<PermissionCategory[]>([
|
||||
new PermissionCategory("Users", typeof(UserRoundIcon), [
|
||||
new Permission(Permissions.Users.Create, "Create", "Create new users"),
|
||||
new Permission(Permissions.Users.View, "View", "View all users"),
|
||||
new Permission(Permissions.Users.Edit, "Edit", "Edit user details"),
|
||||
new Permission(Permissions.Users.Delete, "Delete", "Delete user accounts"),
|
||||
new Permission(Permissions.Users.Logout, "Logout", "Logout user accounts")
|
||||
]),
|
||||
new PermissionCategory("Roles", typeof(UsersRoundIcon), [
|
||||
new Permission(Permissions.Roles.Create, "Create", "Create new roles"),
|
||||
new Permission(Permissions.Roles.View, "View", "View all roles"),
|
||||
new Permission(Permissions.Roles.Edit, "Edit", "Edit role details"),
|
||||
new Permission(Permissions.Roles.Delete, "Delete", "Delete role accounts"),
|
||||
new Permission(Permissions.Roles.Members, "Members", "Manage role members")
|
||||
]),
|
||||
new PermissionCategory("System", typeof(CogIcon), [
|
||||
new Permission(Permissions.System.Info, "Info", "View system info"),
|
||||
new Permission(Permissions.System.Diagnose, "Diagnose", "Run diagnostics"),
|
||||
new Permission(Permissions.System.Versions, "Versions", "Look at the available versions"),
|
||||
new Permission(Permissions.System.Instance, "Instance",
|
||||
"Update the moonlight instance and add plugins"),
|
||||
new Permission(Permissions.System.Settings, "Settings", "Change settings of the instance")
|
||||
]),
|
||||
new PermissionCategory("API Keys", typeof(KeyIcon), [
|
||||
new Permission(Permissions.ApiKeys.Create, "Create", "Create new API keys"),
|
||||
new Permission(Permissions.ApiKeys.View, "View", "View all API keys"),
|
||||
new Permission(Permissions.ApiKeys.Edit, "Edit", "Edit API key details"),
|
||||
new Permission(Permissions.ApiKeys.Delete, "Delete", "Delete API keys")
|
||||
]),
|
||||
new PermissionCategory("Themes", typeof(PaintRollerIcon), [
|
||||
new Permission(Permissions.Themes.Create, "Create", "Create new theme"),
|
||||
new Permission(Permissions.Themes.View, "View", "View all themes"),
|
||||
new Permission(Permissions.Themes.Edit, "Edit", "Edit themes"),
|
||||
new Permission(Permissions.Themes.Delete, "Delete", "Delete themes")
|
||||
])
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
using LucideBlazor;
|
||||
using Moonlight.Frontend.Interfaces;
|
||||
using Moonlight.Frontend.Models;
|
||||
using Moonlight.Frontend.Infrastructure.Hooks;
|
||||
using Moonlight.Frontend.Infrastructure.Models;
|
||||
using Moonlight.Shared;
|
||||
|
||||
namespace Moonlight.Frontend.Implementations;
|
||||
namespace Moonlight.Frontend.Infrastructure.Implementations;
|
||||
|
||||
public sealed class SidebarProvider : ISidebarProvider
|
||||
{
|
||||
public Task<SidebarItem[]> GetItemsAsync()
|
||||
{
|
||||
return Task.FromResult<SidebarItem[]>([
|
||||
new()
|
||||
new SidebarItem
|
||||
{
|
||||
Name = "Overview",
|
||||
IconType = typeof(LayoutDashboardIcon),
|
||||
@@ -18,7 +18,7 @@ public sealed class SidebarProvider : ISidebarProvider
|
||||
IsExactPath = true,
|
||||
Order = 0
|
||||
},
|
||||
new()
|
||||
new SidebarItem
|
||||
{
|
||||
Name = "Overview",
|
||||
IconType = typeof(LayoutDashboardIcon),
|
||||
@@ -28,7 +28,7 @@ public sealed class SidebarProvider : ISidebarProvider
|
||||
Order = 0,
|
||||
Policy = Permissions.System.Info
|
||||
},
|
||||
new()
|
||||
new SidebarItem
|
||||
{
|
||||
Name = "Users",
|
||||
IconType = typeof(UsersRoundIcon),
|
||||
@@ -38,7 +38,7 @@ public sealed class SidebarProvider : ISidebarProvider
|
||||
Order = 10,
|
||||
Policy = Permissions.Users.View
|
||||
},
|
||||
new()
|
||||
new SidebarItem
|
||||
{
|
||||
Name = "System",
|
||||
IconType = typeof(SettingsIcon),
|
||||
@@ -1,6 +1,6 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Moonlight.Frontend.Models;
|
||||
namespace Moonlight.Frontend.Infrastructure.Models;
|
||||
|
||||
public record SidebarItem
|
||||
{
|
||||
@@ -3,17 +3,13 @@
|
||||
@using LucideBlazor
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Microsoft.Extensions.Options
|
||||
@using Moonlight.Frontend.Configuration
|
||||
@using Moonlight.Frontend.UI.Shared
|
||||
@using Moonlight.Frontend.UI.Shared.Components
|
||||
@using Moonlight.Frontend.Infrastructure.Configuration
|
||||
@using Moonlight.Frontend.Shared.Auth
|
||||
@using ShadcnBlazor.Emptys
|
||||
@using Moonlight.Frontend.UI.Shared.Components.Auth
|
||||
@using Moonlight.Frontend.UI.Shared.Partials
|
||||
@using ShadcnBlazor.Extras.AlertDialogs
|
||||
@using ShadcnBlazor.Extras.Dialogs
|
||||
@using ShadcnBlazor.Extras.Toasts
|
||||
@using ShadcnBlazor.Portals
|
||||
|
||||
@inject NavigationManager Navigation
|
||||
@inject IOptions<NavigationAssemblyOptions> NavigationOptions
|
||||
|
||||
@@ -22,7 +18,8 @@
|
||||
<AuthorizeView>
|
||||
<ChildContent>
|
||||
<LayoutMiddleware>
|
||||
<Router AppAssembly="@typeof(App).Assembly" AdditionalAssemblies="Assemblies" NotFoundPage="typeof(NotFound)">
|
||||
<Router AppAssembly="@typeof(App).Assembly" AdditionalAssemblies="Assemblies"
|
||||
NotFoundPage="typeof(NotFound)">
|
||||
<Found Context="routeData">
|
||||
<AuthorizeRouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)">
|
||||
<NotAuthorized Context="authRouteViewContext">
|
||||
@@ -32,12 +29,12 @@
|
||||
</Found>
|
||||
</Router>
|
||||
</LayoutMiddleware>
|
||||
|
||||
|
||||
<ToastLauncher/>
|
||||
<DialogLauncher/>
|
||||
<AlertDialogLauncher/>
|
||||
|
||||
<PortalOutlet />
|
||||
|
||||
<PortalOutlet/>
|
||||
</ChildContent>
|
||||
<Authorizing>
|
||||
<Authenticating/>
|
||||
@@ -53,7 +50,7 @@
|
||||
|
||||
if (uri.LocalPath.StartsWith("/setup"))
|
||||
{
|
||||
<Setup />
|
||||
<Setup/>
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1,5 +1,4 @@
|
||||
@using ShadcnBlazor.Sidebars
|
||||
|
||||
<header
|
||||
class="flex h-(--header-height) shrink-0 items-center gap-2 border-b transition-[width,height] ease-linear group-has-data-[collapsible=icon]/sidebar-wrapper:h-(--header-height)"
|
||||
style="--header-height: calc(var(--spacing) * 12)">
|
||||
@@ -1,16 +1,15 @@
|
||||
@using System.Text.Json
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Moonlight.Frontend.Interfaces
|
||||
@using Moonlight.Frontend.Models
|
||||
@using Moonlight.Frontend.Services
|
||||
@using ShadcnBlazor.Sidebars
|
||||
|
||||
@inject NavigationManager Navigation
|
||||
@inject NavigationManager Navigation
|
||||
@inject IAuthorizationService AuthorizationService
|
||||
@inject FrontendService FrontendService
|
||||
@inject IEnumerable<ISidebarProvider> Providers
|
||||
|
||||
@using System.Text.Json
|
||||
@using Microsoft.AspNetCore.Authorization
|
||||
@using Microsoft.AspNetCore.Components.Authorization
|
||||
@using Moonlight.Frontend.Infrastructure.Hooks
|
||||
@using Moonlight.Frontend.Infrastructure.Models
|
||||
@using Moonlight.Frontend.Shared.Frontend
|
||||
@using ShadcnBlazor.Sidebars
|
||||
@implements IDisposable
|
||||
|
||||
@{
|
||||
@@ -75,32 +74,32 @@
|
||||
@code
|
||||
{
|
||||
[CascadingParameter] public Task<AuthenticationState> AuthState { get; set; }
|
||||
|
||||
|
||||
private readonly List<SidebarItem> Items = new();
|
||||
private FrontendConfiguration? FrontendConfiguration;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
var authState = await AuthState;
|
||||
|
||||
|
||||
foreach (var provider in Providers)
|
||||
{
|
||||
var items = await provider.GetItemsAsync();
|
||||
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item.Policy))
|
||||
{
|
||||
var result = await AuthorizationService.AuthorizeAsync(authState.User, item.Policy);
|
||||
|
||||
if(!result.Succeeded)
|
||||
|
||||
if (!result.Succeeded)
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
Items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Navigation.LocationChanged += OnLocationChanged;
|
||||
|
||||
FrontendConfiguration = await FrontendService.GetConfigurationAsync();
|
||||
@@ -1,7 +1,6 @@
|
||||
@using Microsoft.Extensions.Options
|
||||
@using Moonlight.Frontend.Configuration
|
||||
@using Moonlight.Frontend.Interfaces
|
||||
|
||||
@using Moonlight.Frontend.Infrastructure.Configuration
|
||||
@using Moonlight.Frontend.Infrastructure.Hooks
|
||||
@inject IOptions<LayoutMiddlewareOptions> Options
|
||||
|
||||
@Chain
|
||||
@@ -9,7 +8,7 @@
|
||||
@code
|
||||
{
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
|
||||
|
||||
private RenderFragment Chain;
|
||||
|
||||
protected override void OnInitialized()
|
||||
@@ -21,7 +20,7 @@
|
||||
// Capture current values
|
||||
var currentChain = Chain;
|
||||
var currentComponent = component;
|
||||
|
||||
|
||||
Chain = builder =>
|
||||
{
|
||||
builder.OpenComponent(0, currentComponent);
|
||||
@@ -1,8 +1,7 @@
|
||||
@using Microsoft.Extensions.Options
|
||||
@using Moonlight.Frontend.Configuration
|
||||
@using Moonlight.Frontend.Infrastructure.Configuration
|
||||
@using ShadcnBlazor.Extras.Alerts
|
||||
@using ShadcnBlazor.Sidebars
|
||||
|
||||
@inherits LayoutComponentBase
|
||||
|
||||
@inject IOptions<LayoutPageOptions> LayoutPageOptions
|
||||
@@ -15,18 +14,18 @@
|
||||
|
||||
@foreach (var headerComponent in HeaderComponents)
|
||||
{
|
||||
<DynamicComponent Type="headerComponent" />
|
||||
<DynamicComponent Type="headerComponent"/>
|
||||
}
|
||||
|
||||
|
||||
<div class="mx-8 my-8 max-w-full">
|
||||
<AlertLauncher/>
|
||||
|
||||
@Body
|
||||
</div>
|
||||
|
||||
|
||||
@foreach (var footerComponent in FooterComponents)
|
||||
{
|
||||
<DynamicComponent Type="footerComponent" />
|
||||
<DynamicComponent Type="footerComponent"/>
|
||||
}
|
||||
</SidebarInset>
|
||||
</SidebarProvider>
|
||||
@@ -35,7 +34,7 @@
|
||||
{
|
||||
private Type[] HeaderComponents;
|
||||
private Type[] FooterComponents;
|
||||
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
HeaderComponents = LayoutPageOptions.Value.Components
|
||||
@@ -43,7 +42,7 @@
|
||||
.OrderBy(x => x.Order)
|
||||
.Select(x => x.ComponentType)
|
||||
.ToArray();
|
||||
|
||||
|
||||
FooterComponents = LayoutPageOptions.Value.Components
|
||||
.Where(x => x.Slot == LayoutPageSlot.Footer)
|
||||
.OrderBy(x => x.Order)
|
||||
@@ -5,7 +5,6 @@
|
||||
@using ShadcnBlazor.Dropdowns
|
||||
@using ShadcnBlazor.Interop
|
||||
@using ShadcnBlazor.Sidebars
|
||||
|
||||
@inject NavigationManager Navigation
|
||||
|
||||
<SidebarMenu>
|
||||
@@ -72,5 +71,8 @@
|
||||
Email = authState.User.FindFirst(ClaimTypes.Email)?.Value ?? "N/A";
|
||||
}
|
||||
|
||||
private void Logout() => Navigation.NavigateTo("/api/auth/logout", true);
|
||||
private void Logout()
|
||||
{
|
||||
Navigation.NavigateTo("/api/auth/logout", true);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
@page "/notfound"
|
||||
|
||||
@using LucideBlazor
|
||||
@using ShadcnBlazor.Emptys
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.Emptys
|
||||
|
||||
<Empty>
|
||||
<EmptyHeader>
|
||||
@@ -3,16 +3,15 @@ using System.Net.Http.Json;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.VisualBasic;
|
||||
using Moonlight.Shared.Http;
|
||||
using Moonlight.Shared.Http.Responses.Admin.Auth;
|
||||
using Moonlight.Shared.Shared.Auth;
|
||||
using SerializationContext = Moonlight.Shared.SerializationContext;
|
||||
|
||||
namespace Moonlight.Frontend.Services;
|
||||
namespace Moonlight.Frontend.Infrastructure.Services;
|
||||
|
||||
public class RemoteAuthProvider : AuthenticationStateProvider
|
||||
{
|
||||
private readonly ILogger<RemoteAuthProvider> Logger;
|
||||
private readonly HttpClient HttpClient;
|
||||
private readonly ILogger<RemoteAuthProvider> Logger;
|
||||
|
||||
public RemoteAuthProvider(ILogger<RemoteAuthProvider> logger, HttpClient httpClient)
|
||||
{
|
||||
@@ -1,8 +0,0 @@
|
||||
using Moonlight.Frontend.Models;
|
||||
|
||||
namespace Moonlight.Frontend.Interfaces;
|
||||
|
||||
public interface ISidebarProvider
|
||||
{
|
||||
public Task<SidebarItem[]> GetItemsAsync();
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Moonlight.Frontend.Models;
|
||||
|
||||
public class FrontendConfiguration
|
||||
{
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
@@ -24,18 +24,47 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="10.0.3"/>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.3"/>
|
||||
<PackageReference Include="Riok.Mapperly" Version="4.3.1"/>
|
||||
<PackageReference Include="ShadcnBlazor" Version="1.0.14" />
|
||||
<PackageReference Include="ShadcnBlazor.Extras" Version="1.0.14" />
|
||||
<PackageReference Include="SimplePlugin.Abstractions" Version="1.0.2" />
|
||||
<PackageReference Include="ShadcnBlazor" Version="1.0.14"/>
|
||||
<PackageReference Include="ShadcnBlazor.Extras" Version="1.0.14"/>
|
||||
<PackageReference Include="SimplePlugin.Abstractions" Version="1.0.2"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Moonlight.Shared\Moonlight.Shared.csproj"/>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Styles/*" Pack="true" PackagePath="Styles/" />
|
||||
<None Include="Moonlight.Frontend.targets" Pack="true" PackagePath="build\Moonlight.Frontend.targets" />
|
||||
<None Include="Moonlight.Frontend.targets" Pack="true" PackagePath="buildTransitive\Moonlight.Frontend.targets" />
|
||||
<None Include="Styles/*" Pack="true" PackagePath="Styles/"/>
|
||||
<None Include="Moonlight.Frontend.targets" Pack="true" PackagePath="build\Moonlight.Frontend.targets"/>
|
||||
<None Include="Moonlight.Frontend.targets" Pack="true" PackagePath="buildTransitive\Moonlight.Frontend.targets"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<UpToDateCheckInput Remove="UI\Shared\Components\Auth\AccessDenied.razor"/>
|
||||
<UpToDateCheckInput Remove="UI\Shared\Components\Auth\Authenticating.razor"/>
|
||||
<UpToDateCheckInput Remove="UI\Shared\Components\Auth\Authentication.razor"/>
|
||||
<UpToDateCheckInput Remove="Admin\Diagnose\Index.razor"/>
|
||||
<UpToDateCheckInput Remove="Admin\Themes\Create.razor"/>
|
||||
<UpToDateCheckInput Remove="Admin\Themes\Index.razor"/>
|
||||
<UpToDateCheckInput Remove="Admin\Themes\Update.razor"/>
|
||||
<UpToDateCheckInput Remove="UI\Shared\Partials\AppHeader.razor"/>
|
||||
<UpToDateCheckInput Remove="UI\Shared\Partials\AppSidebar.razor"/>
|
||||
<UpToDateCheckInput Remove="UI\Shared\Partials\MainLayout.razor"/>
|
||||
<UpToDateCheckInput Remove="UI\Shared\Partials\NavUser.razor"/>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="Admin\Sys\HelperContainer\Instance.razor"/>
|
||||
<AdditionalFiles Include="Admin\Sys\Settings\Settings.razor"/>
|
||||
<AdditionalFiles Include="Admin\Sys\Themes\Create.razor"/>
|
||||
<AdditionalFiles Include="Admin\Sys\Themes\Index.razor"/>
|
||||
<AdditionalFiles Include="Admin\Sys\Themes\Update.razor"/>
|
||||
<AdditionalFiles Include="Infrastructure\Partials\AppHeader.razor"/>
|
||||
<AdditionalFiles Include="Infrastructure\Partials\AppSidebar.razor"/>
|
||||
<AdditionalFiles Include="Infrastructure\Partials\MainLayout.razor"/>
|
||||
<AdditionalFiles Include="Infrastructure\Partials\NavUser.razor"/>
|
||||
<AdditionalFiles Include="Shared\Auth\AccessDenied.razor"/>
|
||||
<AdditionalFiles Include="Shared\Auth\Authenticating.razor"/>
|
||||
<AdditionalFiles Include="Shared\Auth\Authentication.razor"/>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
<Target Name="Moonlight_CopyContents" BeforeTargets="Build">
|
||||
<ItemGroup>
|
||||
<Files Include="$(MSBuildThisFileDirectory)..\Styles\**\*" />
|
||||
<Files Include="$(MSBuildThisFileDirectory)..\Styles\**\*"/>
|
||||
</ItemGroup>
|
||||
|
||||
<Copy SourceFiles="@(Files)" DestinationFolder="$(MoonlightCssClassDir)" SkipUnchangedFiles="true" />
|
||||
<Copy SourceFiles="@(Files)" DestinationFolder="$(MoonlightCssClassDir)" SkipUnchangedFiles="true"/>
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -11,7 +11,12 @@ public abstract class MoonlightPlugin : IPluginModule
|
||||
{
|
||||
Plugins = plugins;
|
||||
}
|
||||
|
||||
public virtual void PreBuild(WebAssemblyHostBuilder builder){}
|
||||
public virtual void PostBuild(WebAssemblyHost application){}
|
||||
|
||||
public virtual void PreBuild(WebAssemblyHostBuilder builder)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void PostBuild(WebAssemblyHost application)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
@using LucideBlazor
|
||||
@using ShadcnBlazor.Emptys
|
||||
|
||||
<div class="m-10 flex items-center justify-center">
|
||||
<Empty>
|
||||
<EmptyHeader>
|
||||
@@ -1,6 +1,5 @@
|
||||
@using LucideBlazor
|
||||
@using ShadcnBlazor.Emptys
|
||||
|
||||
<div class="h-screen w-full flex items-center justify-center">
|
||||
<Empty>
|
||||
<EmptyHeader>
|
||||
@@ -1,8 +1,8 @@
|
||||
@using Moonlight.Shared.Http
|
||||
@using Moonlight.Shared.Http.Responses.Admin.Auth
|
||||
@using Moonlight.Shared.Shared.Auth
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using ShadcnBlazor.Cards
|
||||
@using ShadcnBlazor.Spinners
|
||||
@using ShadcnBlazor.Buttons
|
||||
@using SerializationContext = Moonlight.Shared.SerializationContext
|
||||
|
||||
@inject HttpClient HttpClient
|
||||
@inject NavigationManager Navigation
|
||||
@@ -0,0 +1,8 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Moonlight.Frontend.Shared.Frontend;
|
||||
|
||||
public class FrontendConfiguration
|
||||
{
|
||||
[JsonPropertyName("name")] public string Name { get; set; }
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using Microsoft.JSInterop;
|
||||
using Moonlight.Frontend.Models;
|
||||
|
||||
namespace Moonlight.Frontend.Services;
|
||||
namespace Moonlight.Frontend.Shared.Frontend;
|
||||
|
||||
public class FrontendService
|
||||
{
|
||||
@@ -11,7 +10,7 @@ public class FrontendService
|
||||
{
|
||||
JsRuntime = jsRuntime;
|
||||
}
|
||||
|
||||
|
||||
public async Task<FrontendConfiguration> GetConfigurationAsync()
|
||||
{
|
||||
return await JsRuntime.InvokeAsync<FrontendConfiguration>("frontendConfig.getConfiguration");
|
||||
@@ -2,9 +2,9 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moonlight.Frontend.Implementations;
|
||||
using Moonlight.Frontend.Interfaces;
|
||||
using Moonlight.Frontend.Services;
|
||||
using Moonlight.Frontend.Infrastructure.Hooks;
|
||||
using Moonlight.Frontend.Infrastructure.Implementations;
|
||||
using Moonlight.Frontend.Infrastructure.Services;
|
||||
|
||||
namespace Moonlight.Frontend.Startup;
|
||||
|
||||
@@ -17,7 +17,7 @@ public partial class Startup
|
||||
builder.Services.AddCascadingAuthenticationState();
|
||||
|
||||
builder.Services.AddSingleton<IPermissionProvider, PermissionProvider>();
|
||||
|
||||
|
||||
builder.Services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>();
|
||||
builder.Services.AddSingleton<IAuthorizationPolicyProvider, PermissionPolicyProvider>();
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ using LucideBlazor;
|
||||
using Microsoft.AspNetCore.Components.Web;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moonlight.Frontend.Configuration;
|
||||
using Moonlight.Frontend.Implementations;
|
||||
using Moonlight.Frontend.Interfaces;
|
||||
using Moonlight.Frontend.Services;
|
||||
using Moonlight.Frontend.UI;
|
||||
using Moonlight.Frontend.UI.Admin.Settings;
|
||||
using Moonlight.Frontend.Admin.Sys.Settings;
|
||||
using Moonlight.Frontend.Infrastructure.Configuration;
|
||||
using Moonlight.Frontend.Infrastructure.Hooks;
|
||||
using Moonlight.Frontend.Infrastructure.Implementations;
|
||||
using Moonlight.Frontend.Infrastructure.Partials;
|
||||
using Moonlight.Frontend.Shared.Frontend;
|
||||
using ShadcnBlazor;
|
||||
using ShadcnBlazor.Extras;
|
||||
|
||||
|
||||
@@ -14,6 +14,5 @@ public partial class Startup : MoonlightPlugin
|
||||
|
||||
public override void PostBuild(WebAssemblyHost application)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ public static class StartupHandler
|
||||
public static async Task RunAsync(string[] args, MoonlightPlugin[] plugins)
|
||||
{
|
||||
Console.WriteLine($"Starting with: {string.Join(", ", plugins.Select(x => x.GetType().FullName))}");
|
||||
|
||||
|
||||
var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
|
||||
// Setting up context
|
||||
@@ -21,7 +21,7 @@ public static class StartupHandler
|
||||
var app = builder.Build();
|
||||
|
||||
// Stage 2: Post Build
|
||||
foreach(var plugin in plugins)
|
||||
foreach (var plugin in plugins)
|
||||
plugin.PostBuild(app);
|
||||
|
||||
await app.RunAsync();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="256px" height="301px" viewBox="0 0 256 301" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid">
|
||||
<svg width="256px" height="301px" viewBox="0 0 256 301" version="1.1" xmlns="http://www.w3.org/2000/svg"
|
||||
preserveAspectRatio="xMidYMid">
|
||||
<defs>
|
||||
<linearGradient x1="2.17771739%" y1="34.7938955%" x2="92.7221942%" y2="91.3419405%" id="linearGradient-1">
|
||||
<stop stop-color="#41A7EF" offset="0%"></stop>
|
||||
@@ -9,6 +10,7 @@
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g>
|
||||
<path d="M124.183681,101.699 C124.183681,66.515 136.256681,34.152 156.486681,8.525 C159.197681,5.092 156.787681,0.069 152.412681,0.012 C151.775681,0.004 151.136681,0 150.497681,0 C67.6206813,0 0.390681343,66.99 0.00168134279,149.775 C-0.386318657,232.369 66.4286813,300.195 149.019681,300.988 C189.884681,301.381 227.036681,285.484 254.376681,259.395 C257.519681,256.396 255.841681,251.082 251.548681,250.42 C179.413681,239.291 124.183681,176.949 124.183681,101.699" fill="url(#linearGradient-1)"></path>
|
||||
<path d="M124.183681,101.699 C124.183681,66.515 136.256681,34.152 156.486681,8.525 C159.197681,5.092 156.787681,0.069 152.412681,0.012 C151.775681,0.004 151.136681,0 150.497681,0 C67.6206813,0 0.390681343,66.99 0.00168134279,149.775 C-0.386318657,232.369 66.4286813,300.195 149.019681,300.988 C189.884681,301.381 227.036681,285.484 254.376681,259.395 C257.519681,256.396 255.841681,251.082 251.548681,250.42 C179.413681,239.291 124.183681,176.949 124.183681,101.699"
|
||||
fill="url(#linearGradient-1)"></path>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Reference in New Issue
Block a user