From e2f344ab4e2d3a1fa20592427e71dc0f7ad70426 Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Fri, 23 Jan 2026 16:38:42 +0100 Subject: [PATCH 01/10] Added container rebuild flow with real-time logs and updated UI, backend implementation, config options, and container helper API integration. --- .../Configuration/ContainerHelperOptions.cs | 7 + .../Http/Controllers/Admin/ChController.cs | 27 +++ .../Http/Controllers/PingController.cs | 13 ++ Moonlight.Api/Services/ApplicationService.cs | 2 +- .../Services/ContainerHelperService.cs | 67 ++++++++ Moonlight.Api/Startup/Startup.Base.cs | 9 + .../UI/Admin/Modals/UpdateInstanceModal.razor | 157 ++++++++++++++---- .../UI/Admin/Views/Overview.razor | 1 + Moonlight.Shared/Http/Events/RebuildEvent.cs | 20 +++ Moonlight.Shared/Http/SerializationContext.cs | 4 + compose.yaml | 30 +++- 11 files changed, 300 insertions(+), 37 deletions(-) create mode 100644 Moonlight.Api/Configuration/ContainerHelperOptions.cs create mode 100644 Moonlight.Api/Http/Controllers/Admin/ChController.cs create mode 100644 Moonlight.Api/Http/Controllers/PingController.cs create mode 100644 Moonlight.Api/Services/ContainerHelperService.cs create mode 100644 Moonlight.Shared/Http/Events/RebuildEvent.cs diff --git a/Moonlight.Api/Configuration/ContainerHelperOptions.cs b/Moonlight.Api/Configuration/ContainerHelperOptions.cs new file mode 100644 index 00000000..42f89bd7 --- /dev/null +++ b/Moonlight.Api/Configuration/ContainerHelperOptions.cs @@ -0,0 +1,7 @@ +namespace Moonlight.Api.Configuration; + +public class ContainerHelperOptions +{ + public bool IsEnabled { get; set; } + public string Url { get; set; } = "http://helper:8080"; +} \ No newline at end of file diff --git a/Moonlight.Api/Http/Controllers/Admin/ChController.cs b/Moonlight.Api/Http/Controllers/Admin/ChController.cs new file mode 100644 index 00000000..4fe148df --- /dev/null +++ b/Moonlight.Api/Http/Controllers/Admin/ChController.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Moonlight.Api.Services; + +namespace Moonlight.Api.Http.Controllers.Admin; + +[ApiController] +[Route("api/admin/ch")] +public class ChController : Controller +{ + private readonly ContainerHelperService ContainerHelperService; + + public ChController(ContainerHelperService containerHelperService) + { + ContainerHelperService = containerHelperService; + } + + [HttpPost("rebuild")] + public Task RebuildAsync() + { + var result = ContainerHelperService.RebuildAsync(); + + return Task.FromResult( + TypedResults.ServerSentEvents(result) + ); + } +} \ No newline at end of file diff --git a/Moonlight.Api/Http/Controllers/PingController.cs b/Moonlight.Api/Http/Controllers/PingController.cs new file mode 100644 index 00000000..8de46960 --- /dev/null +++ b/Moonlight.Api/Http/Controllers/PingController.cs @@ -0,0 +1,13 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; + +namespace Moonlight.Api.Http.Controllers; + +[ApiController] +[Route("api/ping")] +public class PingController : Controller +{ + [HttpGet] + [AllowAnonymous] + public IActionResult Get() => Ok("Pong"); +} \ No newline at end of file diff --git a/Moonlight.Api/Services/ApplicationService.cs b/Moonlight.Api/Services/ApplicationService.cs index 3a002ab1..d72952ff 100644 --- a/Moonlight.Api/Services/ApplicationService.cs +++ b/Moonlight.Api/Services/ApplicationService.cs @@ -47,7 +47,7 @@ public class ApplicationService : IHostedLifecycleService // TODO: Update / version check VersionName = "v2.1.0 (a2d4edc0e5)"; - IsUpToDate = true; + IsUpToDate = false; OperatingSystem = OsHelper.GetName(); } diff --git a/Moonlight.Api/Services/ContainerHelperService.cs b/Moonlight.Api/Services/ContainerHelperService.cs new file mode 100644 index 00000000..578fc4ba --- /dev/null +++ b/Moonlight.Api/Services/ContainerHelperService.cs @@ -0,0 +1,67 @@ +using System.Text.Json; +using Moonlight.Shared.Http; +using Moonlight.Shared.Http.Events; + +namespace Moonlight.Api.Services; + +public class ContainerHelperService +{ + private readonly IHttpClientFactory HttpClientFactory; + + public ContainerHelperService(IHttpClientFactory httpClientFactory) + { + HttpClientFactory = httpClientFactory; + } + + public async IAsyncEnumerable RebuildAsync() + { + var options = new JsonSerializerOptions() + { + PropertyNameCaseInsensitive = true + }; + + options.TypeInfoResolverChain.Add(SerializationContext.Default); + + var client = HttpClientFactory.CreateClient("ContainerHelper"); + + var response = await client.GetAsync("api/rebuild", HttpCompletionOption.ResponseHeadersRead); + + if (!response.IsSuccessStatusCode) + { + var responseText = await response.Content.ReadAsStringAsync(); + yield return new RebuildEvent() + { + Type = RebuildEventType.Failed, + Data = responseText + }; + + yield break; + } + + await using var responseStream = await response.Content.ReadAsStreamAsync(); + using var streamReader = new StreamReader(responseStream); + + do + { + var line = await streamReader.ReadLineAsync(); + + if(line == null) + break; + + if(string.IsNullOrWhiteSpace(line)) + continue; + + var data = line.Trim("data: "); + + var deserializedData = JsonSerializer.Deserialize(data, options); + + yield return deserializedData; + } while (true); + + yield return new RebuildEvent() + { + Type = RebuildEventType.Succeeded, + Data = string.Empty + }; + } +} \ No newline at end of file diff --git a/Moonlight.Api/Startup/Startup.Base.cs b/Moonlight.Api/Startup/Startup.Base.cs index 147f6a48..25c97ea6 100644 --- a/Moonlight.Api/Startup/Startup.Base.cs +++ b/Moonlight.Api/Startup/Startup.Base.cs @@ -38,6 +38,15 @@ public partial class Startup builder.Services.AddOptions().BindConfiguration("Moonlight:Frontend"); builder.Services.AddScoped(); + + builder.Services.AddOptions().BindConfiguration("Moonlight:ContainerHelper"); + builder.Services.AddSingleton(); + + builder.Services.AddHttpClient("ContainerHelper", (provider, client) => + { + var options = provider.GetRequiredService>(); + client.BaseAddress = new Uri(options.Value.IsEnabled ? options.Value.Url : "http://you-should-fail.invalid"); + }); } private static void UseBase(WebApplication application) diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor index ba8e6dab..68f9eb96 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor @@ -1,37 +1,31 @@ @inherits ShadcnBlazor.Extras.Dialogs.DialogBase +@using System.Text.Json @using LucideBlazor +@using Moonlight.Shared.Http +@using Moonlight.Shared.Http.Events @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Extras.AlertDialogs @using ShadcnBlazor.Progresses @using ShadcnBlazor.Spinners @inject AlertDialogService AlertService +@inject HttpClient HttpClient - Updating... + Updating instance... -
- @for (var i = 0; i < Steps.Length; i++) - { - if (CurrentStep == i) +
+
+ @for (var i = 0; i < Steps.Length; i++) { -
- - - @Steps[i] - -
- } - else - { - if (i < CurrentStep) + if (CurrentStep == i) {
- + @Steps[i] @@ -39,13 +33,33 @@ } else { -
- - @Steps[i] -
+ if (i < CurrentStep) + { +
+ + + @Steps[i] + +
+ } + else + { +
+ + @Steps[i] +
+ } } } - } +
+
+ @for (var i = LogLines.Count - 1; i >= 0; i--) + { +
+ @LogLines[i] +
+ } +
@@ -62,12 +76,15 @@ [ "Preparing", "Updating configuration files", + "Starting rebuild task", "Building docker image", "Redeploying container instance", "Waiting for container instance to start up", "Update complete" ]; + private List LogLines = new(); + protected override async Task OnAfterRenderAsync(bool firstRender) { if (!firstRender) @@ -83,30 +100,100 @@ Progress = 20; await InvokeAsync(StateHasChanged); - await Task.Delay(6000); - - CurrentStep = 2; - Progress = 40; - await InvokeAsync(StateHasChanged); - await Task.Delay(2000); - CurrentStep = 3; - Progress = 60; + CurrentStep = 2; + Progress = 30; await InvokeAsync(StateHasChanged); - await Task.Delay(4000); + var response = await HttpClient.SendAsync( + new HttpRequestMessage(HttpMethod.Post, "api/admin/ch/rebuild"), + HttpCompletionOption.ResponseHeadersRead + ); - CurrentStep = 4; - Progress = 80; - await InvokeAsync(StateHasChanged); + await using var responseStream = await response.Content.ReadAsStreamAsync(); + using var streamReader = new StreamReader(responseStream); - await Task.Delay(4000); + do + { + try + { + var line = await streamReader.ReadLineAsync(); + + if (line == null) + break; + + if (string.IsNullOrWhiteSpace(line)) + continue; + + var data = line.Trim("data: "); + var deserializedData = JsonSerializer.Deserialize(data, Constants.SerializerOptions); + + switch (deserializedData.Type) + { + case RebuildEventType.Log: + LogLines.Add(deserializedData.Data); + break; + + case RebuildEventType.Step: + + switch (deserializedData.Data) + { + case "BuildImage": + CurrentStep = 3; + Progress = 40; + await InvokeAsync(StateHasChanged); + break; + + case "ServiceDown": + CurrentStep = 4; + Progress = 60; + await InvokeAsync(StateHasChanged); + break; + + case "ServiceUp": + CurrentStep = 4; + Progress = 80; + await InvokeAsync(StateHasChanged); + break; + } + + break; + } + + await InvokeAsync(StateHasChanged); + } + catch (Exception e) + { + // TODO: Log + break; + } + } while (true); CurrentStep = 5; + Progress = 90; + await InvokeAsync(StateHasChanged); + + // Ping instance until its reachable again + while (true) + { + try + { + await HttpClient.GetStringAsync("api/ping"); + break; + } + catch (Exception) + { + // Ignored + } + + await Task.Delay(3000); + } + + CurrentStep = 6; Progress = 100; await InvokeAsync(StateHasChanged); - + await Task.Delay(1000); await AlertService.SuccessAsync( diff --git a/Moonlight.Frontend/UI/Admin/Views/Overview.razor b/Moonlight.Frontend/UI/Admin/Views/Overview.razor index ddea7a73..f86db322 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Overview.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Overview.razor @@ -160,5 +160,6 @@ private async Task LaunchUpdateModalAsync() => await DialogService.LaunchAsync(onConfigure: model => { model.ShowCloseButton = false; + model.ClassName = "sm:max-w-4xl!"; }); } diff --git a/Moonlight.Shared/Http/Events/RebuildEvent.cs b/Moonlight.Shared/Http/Events/RebuildEvent.cs new file mode 100644 index 00000000..c3edab82 --- /dev/null +++ b/Moonlight.Shared/Http/Events/RebuildEvent.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; + +namespace Moonlight.Shared.Http.Events; + +public struct RebuildEvent +{ + [JsonPropertyName("type")] + public RebuildEventType Type { get; set; } + + [JsonPropertyName("data")] + public string Data { get; set; } +} + +public enum RebuildEventType +{ + Log = 0, + Failed = 1, + Succeeded = 2, + Step = 3 +} \ No newline at end of file diff --git a/Moonlight.Shared/Http/SerializationContext.cs b/Moonlight.Shared/Http/SerializationContext.cs index e3739a64..dfe8de60 100644 --- a/Moonlight.Shared/Http/SerializationContext.cs +++ b/Moonlight.Shared/Http/SerializationContext.cs @@ -1,4 +1,5 @@ using System.Text.Json.Serialization; +using Moonlight.Shared.Http.Events; using Moonlight.Shared.Http.Requests.ApiKeys; using Moonlight.Shared.Http.Requests.Roles; using Moonlight.Shared.Http.Requests.Themes; @@ -43,6 +44,9 @@ namespace Moonlight.Shared.Http; [JsonSerializable(typeof(UpdateThemeDto))] [JsonSerializable(typeof(PagedData))] [JsonSerializable(typeof(ThemeDto))] + +// Events +[JsonSerializable(typeof(RebuildEvent))] public partial class SerializationContext : JsonSerializerContext { } \ No newline at end of file diff --git a/compose.yaml b/compose.yaml index 3f80e03b..f19057b5 100644 --- a/compose.yaml +++ b/compose.yaml @@ -36,4 +36,32 @@ # Logging - "Logging__LogLevel__Default=Information" - - "Logging__LogLevel__Microsoft.AspNetCore=Warning" \ No newline at end of file + - "Logging__LogLevel__Microsoft.AspNetCore=Warning" + - "Logging__LogLevel__System.Net.Http.HttpClient=Warning" + + - "Moonlight__ContainerHelper__IsEnabled=true" + - "Moonlight__ContainerHelper__Url=http://app:8080" + + app: + image: git.battlestati.one/moonlight-panel/container_helper + + group_add: + - "989" + + environment: + # Logging + - "Logging__LogLevel__Default=Information" + - "Logging__LogLevel__Microsoft.AspNetCore=Warning" + + # Compose + - "ContainerHelper__Compose__Directory=${PWD}" + - "ContainerHelper__Compose__Binary=docker-compose" + - "ContainerHelper__Service__Name=api" + + # HTTP Proxy + - "HTTP_PROXY=${HTTP_PROXY}" + - "HTTPS_PROXY=${HTTPS_PROXY}" + + volumes: + - "${PWD}:${PWD}" + - "/var/run/docker.sock:/var/run/docker.sock" \ No newline at end of file From 4e96905fb28e41d9fd6fb2cfa15c397a7d2b1a90 Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Sun, 25 Jan 2026 22:51:51 +0100 Subject: [PATCH 02/10] Implemented container helper status checked. Started implementing container helper ui. Improved update modal --- .../Http/Controllers/Admin/ChController.cs | 18 ++++- .../Services/ContainerHelperService.cs | 23 ++++++ .../UI/Admin/Modals/UpdateInstanceModal.razor | 79 ++++++++++--------- .../UI/Admin/Views/Sys/Index.razor | 7 ++ .../UI/Admin/Views/Sys/Instance.razor | 56 +++++++++++++ .../Admin/ContainerHelperStatusDto.cs | 3 + Moonlight.Shared/Http/SerializationContext.cs | 3 + 7 files changed, 152 insertions(+), 37 deletions(-) create mode 100644 Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor create mode 100644 Moonlight.Shared/Http/Responses/Admin/ContainerHelperStatusDto.cs diff --git a/Moonlight.Api/Http/Controllers/Admin/ChController.cs b/Moonlight.Api/Http/Controllers/Admin/ChController.cs index 4fe148df..cb501b41 100644 --- a/Moonlight.Api/Http/Controllers/Admin/ChController.cs +++ b/Moonlight.Api/Http/Controllers/Admin/ChController.cs @@ -1,6 +1,9 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Options; +using Moonlight.Api.Configuration; using Moonlight.Api.Services; +using Moonlight.Shared.Http.Responses.Admin; namespace Moonlight.Api.Http.Controllers.Admin; @@ -9,10 +12,23 @@ namespace Moonlight.Api.Http.Controllers.Admin; public class ChController : Controller { private readonly ContainerHelperService ContainerHelperService; + private readonly IOptions Options; - public ChController(ContainerHelperService containerHelperService) + public ChController(ContainerHelperService containerHelperService, IOptions options) { ContainerHelperService = containerHelperService; + Options = options; + } + + [HttpGet("status")] + public async Task> GetStatusAsync() + { + if (!Options.Value.IsEnabled) + return new ContainerHelperStatusDto(false, false); + + var status = await ContainerHelperService.CheckConnectionAsync(); + + return new ContainerHelperStatusDto(true, status); } [HttpPost("rebuild")] diff --git a/Moonlight.Api/Services/ContainerHelperService.cs b/Moonlight.Api/Services/ContainerHelperService.cs index 578fc4ba..feb6a142 100644 --- a/Moonlight.Api/Services/ContainerHelperService.cs +++ b/Moonlight.Api/Services/ContainerHelperService.cs @@ -13,6 +13,23 @@ public class ContainerHelperService HttpClientFactory = httpClientFactory; } + public async Task CheckConnectionAsync() + { + var client = HttpClientFactory.CreateClient("ContainerHelper"); + + try + { + var response = await client.GetAsync("api/ping"); + response.EnsureSuccessStatusCode(); + + return true; + } + catch (Exception) + { + return false; + } + } + public async IAsyncEnumerable RebuildAsync() { var options = new JsonSerializerOptions() @@ -29,6 +46,7 @@ public class ContainerHelperService if (!response.IsSuccessStatusCode) { var responseText = await response.Content.ReadAsStringAsync(); + yield return new RebuildEvent() { Type = RebuildEventType.Failed, @@ -56,6 +74,11 @@ public class ContainerHelperService var deserializedData = JsonSerializer.Deserialize(data, options); yield return deserializedData; + + // Exit if service will go down for a clean exit + if(deserializedData is {Type: RebuildEventType.Step, Data: "ServiceDown"}) + yield break; + } while (true); yield return new RebuildEvent() diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor index 68f9eb96..8a48574f 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor @@ -2,14 +2,12 @@ @using System.Text.Json @using LucideBlazor -@using Moonlight.Shared.Http @using Moonlight.Shared.Http.Events +@using ShadcnBlazor.Buttons @using ShadcnBlazor.Dialogs -@using ShadcnBlazor.Extras.AlertDialogs @using ShadcnBlazor.Progresses @using ShadcnBlazor.Spinners -@inject AlertDialogService AlertService @inject HttpClient HttpClient @@ -62,46 +60,57 @@
- - - +@if (CurrentStep == Steps.Length) +{ + + + +} +else +{ + + + +} @code { - private int Progress = 0; - + private int Progress; private int CurrentStep; - private string[] Steps = + private readonly string[] Steps = [ - "Preparing", - "Updating configuration files", - "Starting rebuild task", - "Building docker image", - "Redeploying container instance", - "Waiting for container instance to start up", - "Update complete" + "Checking", // 0 + "Updating configuration files", // 1 + "Starting rebuild task", // 2 + "Building docker image", // 3 + "Redeploying container instance", // 4 + "Waiting for container instance to start up", // 5 + "Update complete" // 6 ]; - private List LogLines = new(); + private readonly List LogLines = new(); protected override async Task OnAfterRenderAsync(bool firstRender) { if (!firstRender) return; + // Checking CurrentStep = 0; Progress = 0; await InvokeAsync(StateHasChanged); await Task.Delay(2000); + // Update configuration CurrentStep = 1; Progress = 20; await InvokeAsync(StateHasChanged); await Task.Delay(2000); + // Starting rebuild task CurrentStep = 2; Progress = 30; await InvokeAsync(StateHasChanged); @@ -140,20 +149,22 @@ switch (deserializedData.Data) { case "BuildImage": + + // Building docker image + CurrentStep = 3; Progress = 40; + await InvokeAsync(StateHasChanged); break; case "ServiceDown": + + // Redeploying container instance + CurrentStep = 4; Progress = 60; - await InvokeAsync(StateHasChanged); - break; - case "ServiceUp": - CurrentStep = 4; - Progress = 80; await InvokeAsync(StateHasChanged); break; } @@ -163,17 +174,21 @@ await InvokeAsync(StateHasChanged); } - catch (Exception e) + catch (Exception) { - // TODO: Log break; } } while (true); + + // Waiting for container instance to start up CurrentStep = 5; Progress = 90; await InvokeAsync(StateHasChanged); + // Wait some time for instance to shut down + await Task.Delay(TimeSpan.FromSeconds(5)); + // Ping instance until its reachable again while (true) { @@ -186,21 +201,13 @@ { // Ignored } - + await Task.Delay(3000); } - - CurrentStep = 6; + + // Update complete + CurrentStep = 7; Progress = 100; await InvokeAsync(StateHasChanged); - - await Task.Delay(1000); - - await AlertService.SuccessAsync( - "Update completed", - "Update successfully completed. Please refresh the page to load new frontend changes" - ); - - await CloseAsync(); } } diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor index 6bc70e12..87c5422f 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor @@ -31,6 +31,10 @@ Diagnose + + + Instance + @@ -65,6 +69,9 @@ } + + + @code diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor new file mode 100644 index 00000000..2e58a953 --- /dev/null +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor @@ -0,0 +1,56 @@ +@using LucideBlazor +@using Moonlight.Shared.Http.Responses.Admin +@using ShadcnBlazor.Emptys +@using ShadcnBlazor.Extras.Common + +@inject HttpClient HttpClient + +
+ + @if (StatusDto.IsEnabled) + { + if (StatusDto.IsReachable) + { + } + else + { + + + + + + Container Helper unreachable + + The container helper is unreachable. No management actions are available + + + + } + } + else + { + + + + + + Container Helper is disabled + + The container helper is disabled on this instance. + This might be due to running a multiple container moonlight setup + + + + } + +
+ +@code +{ + private ContainerHelperStatusDto StatusDto; + + private async Task LoadAsync(LazyLoader _) + { + StatusDto = (await HttpClient.GetFromJsonAsync("api/admin/ch/status"))!; + } +} diff --git a/Moonlight.Shared/Http/Responses/Admin/ContainerHelperStatusDto.cs b/Moonlight.Shared/Http/Responses/Admin/ContainerHelperStatusDto.cs new file mode 100644 index 00000000..16bc5866 --- /dev/null +++ b/Moonlight.Shared/Http/Responses/Admin/ContainerHelperStatusDto.cs @@ -0,0 +1,3 @@ +namespace Moonlight.Shared.Http.Responses.Admin; + +public record ContainerHelperStatusDto(bool IsEnabled, bool IsReachable); \ No newline at end of file diff --git a/Moonlight.Shared/Http/SerializationContext.cs b/Moonlight.Shared/Http/SerializationContext.cs index dfe8de60..3f22bc9e 100644 --- a/Moonlight.Shared/Http/SerializationContext.cs +++ b/Moonlight.Shared/Http/SerializationContext.cs @@ -47,6 +47,9 @@ namespace Moonlight.Shared.Http; // Events [JsonSerializable(typeof(RebuildEvent))] + +// Container Helper +[JsonSerializable(typeof(ContainerHelperStatusDto))] public partial class SerializationContext : JsonSerializerContext { } \ No newline at end of file From deb69e6014fcd8af141853b1b464f456c0663f80 Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Mon, 26 Jan 2026 16:49:25 +0100 Subject: [PATCH 03/10] Upgraded to ShadcnBlazor 1.0.10. Started implementing instance management ui page --- Moonlight.Frontend/Moonlight.Frontend.csproj | 4 +- .../UI/Admin/Modals/CreateApiKeyDialog.razor | 2 +- .../UI/Admin/Modals/CreateRoleDialog.razor | 2 +- .../UI/Admin/Modals/CreateUserDialog.razor | 4 +- .../UI/Admin/Modals/UpdateApiKeyDialog.razor | 2 +- .../UI/Admin/Modals/UpdateRoleDialog.razor | 2 +- .../UI/Admin/Modals/UpdateUserDialog.razor | 4 +- .../UI/Admin/Views/Sys/Index.razor | 2 +- .../UI/Admin/Views/Sys/Instance.razor | 55 +++++++++++++++++++ .../UI/Admin/Views/Sys/Themes/Create.razor | 6 +- .../UI/Admin/Views/Sys/Themes/Update.razor | 6 +- 11 files changed, 72 insertions(+), 17 deletions(-) diff --git a/Moonlight.Frontend/Moonlight.Frontend.csproj b/Moonlight.Frontend/Moonlight.Frontend.csproj index 73eb2f4e..404f41d0 100644 --- a/Moonlight.Frontend/Moonlight.Frontend.csproj +++ b/Moonlight.Frontend/Moonlight.Frontend.csproj @@ -24,8 +24,8 @@ - - + + diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor index 24a3b735..0969beb7 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor @@ -21,7 +21,7 @@
- +
diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor index 7d1d1248..2070f74b 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor @@ -25,7 +25,7 @@
- diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor index 55597eb5..523713a3 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor @@ -23,7 +23,7 @@
- @@ -31,7 +31,7 @@
- - +
diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor index 8878320f..f70fa989 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor @@ -27,7 +27,7 @@
- diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor index fd2e77a8..0418d1ea 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor @@ -25,7 +25,7 @@
- @@ -33,7 +33,7 @@
-
- +
diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor index 2e58a953..0b85ef54 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor @@ -1,7 +1,11 @@ @using LucideBlazor @using Moonlight.Shared.Http.Responses.Admin +@using ShadcnBlazor.Cards @using ShadcnBlazor.Emptys +@using ShadcnBlazor.Buttons @using ShadcnBlazor.Extras.Common +@using ShadcnBlazor.Fields +@using ShadcnBlazor.Selects @inject HttpClient HttpClient @@ -11,6 +15,57 @@ { if (StatusDto.IsReachable) { +
+ + + Version + + + +
+ Update instance + + Select the version you want to update to + + + + Version + + + +
+ + + +
+
+
+ + + Plugins + + + + + + + + No Plugins found + + No plugins found in instance configuration + + + + + +
} else { diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor index 9f12a2e5..d328fc8e 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor @@ -55,7 +55,7 @@
- @@ -63,7 +63,7 @@
- -
- @@ -67,7 +67,7 @@
- - Date: Wed, 28 Jan 2026 16:43:29 +0100 Subject: [PATCH 04/10] Added vesrion to update instance dialog. Added apply functionality to instance page. Replaced dialog launch in overview to link to instance tab --- .../UI/Admin/Modals/UpdateInstanceModal.razor | 4 ++- .../UI/Admin/Views/Overview.razor | 12 +++---- .../UI/Admin/Views/Sys/Instance.razor | 34 ++++++++++++++++--- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor index 8a48574f..a4f10c1c 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor @@ -12,7 +12,7 @@ - Updating instance... + Updating instance to @Version... @@ -75,6 +75,8 @@ else @code { + [Parameter] public string Version { get; set; } + private int Progress; private int CurrentStep; diff --git a/Moonlight.Frontend/UI/Admin/Views/Overview.razor b/Moonlight.Frontend/UI/Admin/Views/Overview.razor index f86db322..f8e03c48 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Overview.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Overview.razor @@ -133,7 +133,11 @@ { Update available - + } @@ -156,10 +160,4 @@ await InvokeAsync(StateHasChanged); } - - private async Task LaunchUpdateModalAsync() => await DialogService.LaunchAsync(onConfigure: model => - { - model.ShowCloseButton = false; - model.ClassName = "sm:max-w-4xl!"; - }); } diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor index 0b85ef54..058e35cf 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor @@ -1,13 +1,18 @@ @using LucideBlazor +@using Moonlight.Frontend.UI.Admin.Modals @using Moonlight.Shared.Http.Responses.Admin @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 @inject HttpClient HttpClient +@inject DialogService DialogService +@inject AlertDialogService AlertDialogService
@@ -31,18 +36,19 @@ Version - - Testy + v2.1 + v2.1.1 - + @@ -55,7 +61,7 @@ - + No Plugins found @@ -103,9 +109,29 @@ @code { private ContainerHelperStatusDto StatusDto; + private string SelectedVersion = "v2.1"; private async Task LoadAsync(LazyLoader _) { StatusDto = (await HttpClient.GetFromJsonAsync("api/admin/ch/status"))!; } + + private async Task ApplyAsync() + { + await AlertDialogService.ConfirmDangerAsync( + "Moonlight Rebuild", + "If you continue the moonlight instance will become unavailable during the rebuild process. This will impact users on this instance", + async () => + { + await DialogService.LaunchAsync( + parameters => { parameters[nameof(UpdateInstanceModal.Version)] = SelectedVersion; }, + onConfigure: model => + { + model.ShowCloseButton = false; + model.ClassName = "sm:max-w-4xl!"; + } + ); + } + ); + } } From 136620f1e642a011cf90a717328604e1b7ba30d1 Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Thu, 29 Jan 2026 08:58:12 +0100 Subject: [PATCH 05/10] Updated all forms to use the EnhancedEditForm and blazors native validation. Fixed smaller issues after upgrading to ShadcnBlazor 1.0.11 --- Moonlight.Frontend/Moonlight.Frontend.csproj | 4 +- .../UI/Admin/Modals/CreateApiKeyDialog.razor | 74 ++++----- .../UI/Admin/Modals/CreateRoleDialog.razor | 78 +++++----- .../UI/Admin/Modals/CreateUserDialog.razor | 59 ++++---- .../Modals/ManageRoleMembersDialog.razor | 8 +- .../UI/Admin/Modals/UpdateApiKeyDialog.razor | 65 ++++---- .../UI/Admin/Modals/UpdateRoleDialog.razor | 79 +++++----- .../UI/Admin/Modals/UpdateUserDialog.razor | 62 ++++---- .../UI/Admin/Views/Sys/Diagnose.razor | 4 +- .../UI/Admin/Views/Sys/Index.razor | 8 - .../UI/Admin/Views/Sys/Instance.razor | 24 ++- .../UI/Admin/Views/Sys/Themes/Create.razor | 140 ++++++++--------- .../UI/Admin/Views/Sys/Themes/Update.razor | 143 +++++++++--------- .../Http/Requests/ApiKeys/CreateApiKeyDto.cs | 5 +- .../Http/Requests/ApiKeys/UpdateApiKeyDto.cs | 4 +- 15 files changed, 362 insertions(+), 395 deletions(-) diff --git a/Moonlight.Frontend/Moonlight.Frontend.csproj b/Moonlight.Frontend/Moonlight.Frontend.csproj index 404f41d0..2cfb72cf 100644 --- a/Moonlight.Frontend/Moonlight.Frontend.csproj +++ b/Moonlight.Frontend/Moonlight.Frontend.csproj @@ -24,8 +24,8 @@ - - + + diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor index 0969beb7..5fe70954 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor @@ -1,10 +1,9 @@ @using Moonlight.Frontend.UI.Admin.Components @using Moonlight.Shared.Http.Requests.ApiKeys @using ShadcnBlazor.Dialogs -@using ShadcnBlazor.Extras.Common -@using ShadcnBlazor.Extras.FormHandlers +@using ShadcnBlazor.Extras.Forms +@using ShadcnBlazor.Fields @using ShadcnBlazor.Inputs -@using ShadcnBlazor.Labels @inherits ShadcnBlazor.Extras.Dialogs.DialogBase @@ -15,56 +14,57 @@ - -
- + -
- - -
- -
- - -
- -
- - -
-
-
- - - Save changes - + + + + +
+ + Name + + + + Description + + + + Permissions + + + + +
+ + Save changes + +
+ @code { [Parameter] public Func OnSubmit { get; set; } private CreateApiKeyDto Request; - private FormHandler FormHandler; - private List Permissions = new(); + private List Permissions = new(); protected override void OnInitialized() { - Request = new(); + Request = new() + { + Permissions = [] + }; } - private async Task SubmitAsync() + private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { Request.Permissions = Permissions.ToArray(); + await OnSubmit.Invoke(Request); + await CloseAsync(); + return true; } } \ No newline at end of file diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor index 2070f74b..ce98ea80 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor @@ -1,11 +1,9 @@ @using Moonlight.Frontend.UI.Admin.Components @using Moonlight.Shared.Http.Requests.Roles -@using ShadcnBlazor.Buttons @using ShadcnBlazor.Dialogs -@using ShadcnBlazor.Extras.Common -@using ShadcnBlazor.Extras.FormHandlers +@using ShadcnBlazor.Extras.Forms +@using ShadcnBlazor.Fields @using ShadcnBlazor.Inputs -@using ShadcnBlazor.Labels @inherits ShadcnBlazor.Extras.Dialogs.DialogBase @@ -18,41 +16,36 @@ - -
- + + + -
- - -
- -
- - -
- -
- - -
-
-
- - - Save changes - +
+ + Name + + + + Description + + + + Permissions + + + + +
+ + Save changes + + + @code { @@ -60,7 +53,6 @@ private CreateRoleDto Request; private List Permissions; - private FormHandler FormHandler; protected override void OnInitialized() { @@ -68,19 +60,17 @@ { Permissions = [] }; - + Permissions = new(); } - private async Task SubmitAsync() + private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { Request.Permissions = Permissions.ToArray(); - await FormHandler.SubmitAsync(); - } - private async Task OnSubmitAsync() - { await OnSubmit.Invoke(Request); await CloseAsync(); + + return true; } } diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor index 523713a3..ebf8e442 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor @@ -1,9 +1,8 @@ @using Moonlight.Shared.Http.Requests.Users @using ShadcnBlazor.Dialogs -@using ShadcnBlazor.Extras.Common -@using ShadcnBlazor.Extras.FormHandlers +@using ShadcnBlazor.Extras.Forms +@using ShadcnBlazor.Fields @using ShadcnBlazor.Inputs -@using ShadcnBlazor.Labels @inherits ShadcnBlazor.Extras.Dialogs.DialogBase @@ -16,50 +15,50 @@ - -
+ + + -
- - -
- -
- - -
-
-
- - - Save changes - +
+ + Username + + + + Email Address + + +
+ + Save changes + + + @code { [Parameter] public Func OnSubmit { get; set; } private CreateUserDto Request; - private FormHandler FormHandler; protected override void OnInitialized() { Request = new(); } - private async Task SubmitAsync() + private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { await OnSubmit.Invoke(Request); - await CloseAsync(); + + return true; } } diff --git a/Moonlight.Frontend/UI/Admin/Modals/ManageRoleMembersDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/ManageRoleMembersDialog.razor index 6abb099a..4dc004fa 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/ManageRoleMembersDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/ManageRoleMembersDialog.razor @@ -32,9 +32,9 @@ SearchPlaceholder="Search user" ValueSelector="dto => dto.Username" Source="LoadUsersAsync"/> - + - +
@@ -50,9 +50,9 @@
- + - +
diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor index 6f0db39f..3f2f62e9 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor @@ -3,10 +3,9 @@ @using Moonlight.Shared.Http.Requests.ApiKeys @using Moonlight.Shared.Http.Responses.ApiKeys @using ShadcnBlazor.Dialogs -@using ShadcnBlazor.Extras.Common -@using ShadcnBlazor.Extras.FormHandlers +@using ShadcnBlazor.Extras.Forms +@using ShadcnBlazor.Fields @using ShadcnBlazor.Inputs -@using ShadcnBlazor.Labels @inherits ShadcnBlazor.Extras.Dialogs.DialogBase @@ -17,37 +16,32 @@ - -
- + + + + -
- - -
- -
- - -
- -
- - -
-
-
- - - Save changes - +
+ + Name + + + + Description + + + + Permissions + + + + +
+ + Save changes + + + @code { @@ -55,7 +49,6 @@ [Parameter] public ApiKeyDto Key { get; set; } private UpdateApiKeyDto Request; - private FormHandler FormHandler; private List Permissions = new(); protected override void OnInitialized() @@ -64,10 +57,12 @@ Permissions = Key.Permissions.ToList(); } - private async Task SubmitAsync() + private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { Request.Permissions = Permissions.ToArray(); await OnSubmit.Invoke(Request); await CloseAsync(); + + return true; } } \ No newline at end of file diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor index f70fa989..1c5870cb 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor @@ -2,12 +2,10 @@ @using Moonlight.Frontend.UI.Admin.Components @using Moonlight.Shared.Http.Requests.Roles @using Moonlight.Shared.Http.Responses.Admin -@using ShadcnBlazor.Buttons @using ShadcnBlazor.Dialogs -@using ShadcnBlazor.Extras.Common -@using ShadcnBlazor.Extras.FormHandlers +@using ShadcnBlazor.Extras.Forms +@using ShadcnBlazor.Fields @using ShadcnBlazor.Inputs -@using ShadcnBlazor.Labels @inherits ShadcnBlazor.Extras.Dialogs.DialogBase @@ -20,50 +18,44 @@ - -
- + + + -
- - -
- -
- - -
- -
- - -
-
-
- - - Save changes - +
+ + Name + + + + Description + + + + Permissions + + + + +
+ + Save changes + + + @code { [Parameter] public Func OnSubmit { get; set; } [Parameter] public RoleDto Role { get; set; } - + private UpdateRoleDto Request; private List Permissions; - private FormHandler FormHandler; protected override void OnInitialized() { @@ -71,15 +63,12 @@ Permissions = Role.Permissions.ToList(); } - private async Task SubmitAsync() + private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { Request.Permissions = Permissions.ToArray(); - await FormHandler.SubmitAsync(); - } - - private async Task OnSubmitAsync() - { await OnSubmit.Invoke(Request); await CloseAsync(); + + return true; } } diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor index 0418d1ea..d564202a 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor @@ -2,10 +2,9 @@ @using Moonlight.Shared.Http.Requests.Users @using Moonlight.Shared.Http.Responses.Users @using ShadcnBlazor.Dialogs -@using ShadcnBlazor.Extras.Common -@using ShadcnBlazor.Extras.FormHandlers +@using ShadcnBlazor.Extras.Forms +@using ShadcnBlazor.Fields @using ShadcnBlazor.Inputs -@using ShadcnBlazor.Labels @inherits ShadcnBlazor.Extras.Dialogs.DialogBase @@ -18,51 +17,50 @@ - -
- + + + -
- - -
- -
- - -
-
-
- - - Save changes - +
+ + Username + + + + Email Address + + +
+ + Save changes + + + @code { [Parameter] public Func OnSubmit { get; set; } [Parameter] public UserDto User { get; set; } - + private UpdateUserDto Request; - private FormHandler FormHandler; protected override void OnInitialized() { Request = UserMapper.ToUpdate(User); } - private async Task SubmitAsync() + private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { await OnSubmit.Invoke(Request); - await CloseAsync(); + + return true; } } diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Diagnose.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Diagnose.razor index 0cac7f81..f6433df8 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Diagnose.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Diagnose.razor @@ -44,10 +44,10 @@ - + Start diagnostics - +
diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor index 3675d5cc..7d764378 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Index.razor @@ -38,14 +38,6 @@ - -
-
- - -
-
-
+ + + Continue +
-
- - -
-
-
- - - -
- - - -
-
- +
+ + + + + + +
+ + Name -
+ -
- + + Version -
- -
- + + + + Author -
- -
- - -
-
- - - -
- - -
-
- - - -
+ + + + Is Enabled + + + + + + + + + CSS Content + + + + + +
+
+
+ @code { @@ -109,17 +112,12 @@ CssContent = "/* Define your css here */" }; - private FormHandler Form; private Editor Editor; - private async Task SubmitAsync() + private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { Request.CssContent = await Editor.GetValueAsync(); - await Form.SubmitAsync(); - } - private async Task OnSubmitAsync() - { await HttpClient.PostAsJsonAsync( "/api/admin/themes", Request, @@ -134,5 +132,7 @@ await FrontendService.ReloadAsync(); Navigation.NavigateTo("/admin/system?tab=themes"); + + return true; } } \ No newline at end of file diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor index 800ee14c..eed40f9e 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor @@ -8,12 +8,12 @@ @using Moonlight.Shared.Http.Requests.Themes @using Moonlight.Shared.Http.Responses.Themes @using ShadcnBlazor.Buttons -@using ShadcnBlazor.Labels @using ShadcnBlazor.Cards @using ShadcnBlazor.Extras.Common @using ShadcnBlazor.Extras.Editors -@using ShadcnBlazor.Extras.FormHandlers +@using ShadcnBlazor.Extras.Forms @using ShadcnBlazor.Extras.Toasts +@using ShadcnBlazor.Fields @using ShadcnBlazor.Inputs @using ShadcnBlazor.Switches @@ -24,99 +24,102 @@ @inject ToastService ToastService @inject FrontendService FrontendService -
-
-

Update theme

-
- Update the theme + + +
+
+

Update theme

+
+ Update the theme +
+
+
+ + + + Continue + +
-
-
- - -
-
- -
- - - - -
+
+ + + + -
-
- +
+ + Name -
+ -
- + + Version -
+ -
- + + Author -
+ -
- - -
-
+ + Is Enabled + + + + + + + - - -
- - -
-
- - - - -
+ CSS Content + + + + + +
+
+
+ + @code { [Parameter] public int Id { get; set; } - + private UpdateThemeDto Request; private ThemeDto Theme; - - private FormHandler Form; + private Editor Editor; - + private async Task LoadAsync(LazyLoader _) { var theme = await HttpClient.GetFromJsonAsync($"api/admin/themes/{Id}"); @@ -125,14 +128,10 @@ Request = ThemeMapper.ToUpdate(Theme); } - private async Task SubmitAsync() + private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { Request.CssContent = await Editor.GetValueAsync(); - await Form.SubmitAsync(); - } - private async Task OnSubmitAsync() - { await HttpClient.PatchAsJsonAsync( $"/api/admin/themes/{Theme.Id}", Request, @@ -147,5 +146,7 @@ await FrontendService.ReloadAsync(); Navigation.NavigateTo("/admin/system?tab=themes"); + + return true; } } \ No newline at end of file diff --git a/Moonlight.Shared/Http/Requests/ApiKeys/CreateApiKeyDto.cs b/Moonlight.Shared/Http/Requests/ApiKeys/CreateApiKeyDto.cs index 12b28620..0f5e2e65 100644 --- a/Moonlight.Shared/Http/Requests/ApiKeys/CreateApiKeyDto.cs +++ b/Moonlight.Shared/Http/Requests/ApiKeys/CreateApiKeyDto.cs @@ -4,10 +4,13 @@ namespace Moonlight.Shared.Http.Requests.ApiKeys; public class CreateApiKeyDto { + [Required] [MaxLength(30)] public string Name { get; set; } - + [MaxLength(300)] public string Description { get; set; } = ""; + + [Required] public string[] Permissions { get; set; } } \ No newline at end of file diff --git a/Moonlight.Shared/Http/Requests/ApiKeys/UpdateApiKeyDto.cs b/Moonlight.Shared/Http/Requests/ApiKeys/UpdateApiKeyDto.cs index 20f64b56..d9fcbfc2 100644 --- a/Moonlight.Shared/Http/Requests/ApiKeys/UpdateApiKeyDto.cs +++ b/Moonlight.Shared/Http/Requests/ApiKeys/UpdateApiKeyDto.cs @@ -4,10 +4,12 @@ namespace Moonlight.Shared.Http.Requests.ApiKeys; public class UpdateApiKeyDto { + [Required] [MaxLength(30)] public string Name { get; set; } - + [MaxLength(300)] public string Description { get; set; } = ""; + [Required] public string[] Permissions { get; set; } } \ No newline at end of file From 97a676ccd7e9f9ad55766ec06018abe8bdbd07f8 Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Thu, 29 Jan 2026 09:28:50 +0100 Subject: [PATCH 06/10] Implemented handling of server side issues using the rfc for problem detasils in the frontend --- .../Helpers/ProblemDetailsHelper.cs | 30 ++++++++++++++++++ .../UI/Admin/Modals/CreateApiKeyDialog.razor | 29 +++++++++++++++-- .../UI/Admin/Modals/CreateRoleDialog.razor | 23 ++++++++++++-- .../UI/Admin/Modals/CreateUserDialog.razor | 31 ++++++++++++++++--- .../UI/Admin/Modals/UpdateApiKeyDialog.razor | 29 +++++++++++++++-- .../UI/Admin/Modals/UpdateRoleDialog.razor | 24 ++++++++++++-- .../UI/Admin/Modals/UpdateUserDialog.razor | 28 +++++++++++++++-- .../UI/Admin/Views/Sys/ApiKeys.razor | 26 ++-------------- .../UI/Admin/Views/Sys/Themes/Create.razor | 9 +++++- .../UI/Admin/Views/Sys/Themes/Update.razor | 9 +++++- .../UI/Admin/Views/Users/Roles.razor | 18 ++--------- .../UI/Admin/Views/Users/Users.razor | 25 ++------------- .../Http/Responses/ProblemDetails.cs | 10 ++++++ Moonlight.Shared/Http/SerializationContext.cs | 3 ++ 14 files changed, 212 insertions(+), 82 deletions(-) create mode 100644 Moonlight.Frontend/Helpers/ProblemDetailsHelper.cs create mode 100644 Moonlight.Shared/Http/Responses/ProblemDetails.cs diff --git a/Moonlight.Frontend/Helpers/ProblemDetailsHelper.cs b/Moonlight.Frontend/Helpers/ProblemDetailsHelper.cs new file mode 100644 index 00000000..0f04d8ba --- /dev/null +++ b/Moonlight.Frontend/Helpers/ProblemDetailsHelper.cs @@ -0,0 +1,30 @@ +using System.Net.Http.Json; +using Microsoft.AspNetCore.Components.Forms; +using Moonlight.Shared.Http.Responses; + +namespace Moonlight.Frontend.Helpers; + +public static class ProblemDetailsHelper +{ + public static async Task HandleProblemDetailsAsync(HttpResponseMessage response, object model, ValidationMessageStore validationMessageStore) + { + var problemDetails = await response.Content.ReadFromJsonAsync(); + + if (problemDetails == null) + response.EnsureSuccessStatusCode(); // Trigger exception when unable to parse + else + { + 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); + } + } + } + } +} \ No newline at end of file diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor index 5fe70954..a0e0e899 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor @@ -1,12 +1,18 @@ -@using Moonlight.Frontend.UI.Admin.Components +@using Moonlight.Frontend.Helpers +@using Moonlight.Frontend.UI.Admin.Components @using Moonlight.Shared.Http.Requests.ApiKeys +@using Moonlight.Shared.Http.Responses @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 +@inject ToastService ToastService + Create new API key @@ -44,7 +50,7 @@ @code { - [Parameter] public Func OnSubmit { get; set; } + [Parameter] public Func OnSubmit { get; set; } private CreateApiKeyDto Request; @@ -61,8 +67,25 @@ private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { Request.Permissions = Permissions.ToArray(); + + var response = await HttpClient.PostAsJsonAsync( + "/api/admin/apiKeys", + Request, + Constants.SerializerOptions + ); + + if (!response.IsSuccessStatusCode) + { + await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); + return false; + } - await OnSubmit.Invoke(Request); + await ToastService.SuccessAsync( + "API Key creation", + $"Successfully created API key {Request.Name}" + ); + + await OnSubmit.Invoke(); await CloseAsync(); return true; diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor index ce98ea80..671e8317 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor @@ -1,12 +1,17 @@ +@using Moonlight.Frontend.Helpers @using Moonlight.Frontend.UI.Admin.Components @using Moonlight.Shared.Http.Requests.Roles @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 +@inject ToastService ToastService + Create new role @@ -49,7 +54,7 @@ @code { - [Parameter] public Func OnSubmit { get; set; } + [Parameter] public Func OnSubmit { get; set; } private CreateRoleDto Request; private List Permissions; @@ -67,8 +72,22 @@ private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { Request.Permissions = Permissions.ToArray(); + + var response = await HttpClient.PostAsJsonAsync( + "api/admin/roles", + Request, + Constants.SerializerOptions + ); + + if (!response.IsSuccessStatusCode) + { + await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); + return false; + } - await OnSubmit.Invoke(Request); + await ToastService.SuccessAsync("Role creation", $"Role {Request.Name} has been successfully created"); + + await OnSubmit.Invoke(); await CloseAsync(); return true; diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor index ebf8e442..55c1f566 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor @@ -1,11 +1,17 @@ -@using Moonlight.Shared.Http.Requests.Users +@using Moonlight.Frontend.Helpers +@using Moonlight.Shared.Http.Requests.Users +@using Moonlight.Shared.Http.Responses @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 +@inject ToastService ToastService + Create new user @@ -19,7 +25,7 @@ - +
@@ -45,7 +51,7 @@ @code { - [Parameter] public Func OnSubmit { get; set; } + [Parameter] public Func OnCompleted { get; set; } private CreateUserDto Request; @@ -56,7 +62,24 @@ private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { - await OnSubmit.Invoke(Request); + var response = await HttpClient.PostAsJsonAsync( + "/api/admin/users", + Request, + Constants.SerializerOptions + ); + + if (!response.IsSuccessStatusCode) + { + await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); + return false; + } + + await ToastService.SuccessAsync( + "User creation", + $"Successfully created user {Request.Username}" + ); + + await OnCompleted.Invoke(); await CloseAsync(); return true; diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor index 3f2f62e9..b6a34e44 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor @@ -1,14 +1,19 @@ -@using Moonlight.Frontend.Mappers +@using Moonlight.Frontend.Helpers +@using Moonlight.Frontend.Mappers @using Moonlight.Frontend.UI.Admin.Components @using Moonlight.Shared.Http.Requests.ApiKeys @using Moonlight.Shared.Http.Responses.ApiKeys @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 +@inject ToastService ToastService + Update API key @@ -45,7 +50,7 @@ @code { - [Parameter] public Func OnSubmit { get; set; } + [Parameter] public Func OnSubmit { get; set; } [Parameter] public ApiKeyDto Key { get; set; } private UpdateApiKeyDto Request; @@ -60,7 +65,25 @@ private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { Request.Permissions = Permissions.ToArray(); - await OnSubmit.Invoke(Request); + + var response = await HttpClient.PatchAsJsonAsync( + $"/api/admin/apiKeys/{Key.Id}", + Request, + Constants.SerializerOptions + ); + + if (!response.IsSuccessStatusCode) + { + await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); + return false; + } + + await ToastService.SuccessAsync( + "API Key update", + $"Successfully updated API key {Request.Name}" + ); + + await OnSubmit.Invoke(); await CloseAsync(); return true; diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor index 1c5870cb..22130a11 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor @@ -1,14 +1,19 @@ +@using Moonlight.Frontend.Helpers @using Moonlight.Frontend.Mappers @using Moonlight.Frontend.UI.Admin.Components @using Moonlight.Shared.Http.Requests.Roles @using Moonlight.Shared.Http.Responses.Admin @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 +@inject ToastService ToastService + Update @Role.Name @@ -51,7 +56,7 @@ @code { - [Parameter] public Func OnSubmit { get; set; } + [Parameter] public Func OnSubmit { get; set; } [Parameter] public RoleDto Role { get; set; } private UpdateRoleDto Request; @@ -66,7 +71,22 @@ private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { Request.Permissions = Permissions.ToArray(); - await OnSubmit.Invoke(Request); + + var response = await HttpClient.PatchAsJsonAsync( + $"api/admin/roles/{Role.Id}", + Request, + Constants.SerializerOptions + ); + + if (!response.IsSuccessStatusCode) + { + await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); + return false; + } + + await ToastService.SuccessAsync("Role update", $"Role {Request.Name} has been successfully updated"); + + await OnSubmit.Invoke(); await CloseAsync(); return true; diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor index d564202a..145fa3cc 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor @@ -1,13 +1,19 @@ -@using Moonlight.Frontend.Mappers +@using Moonlight.Frontend.Helpers +@using Moonlight.Frontend.Mappers @using Moonlight.Shared.Http.Requests.Users +@using Moonlight.Shared.Http.Responses @using Moonlight.Shared.Http.Responses.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 +@inject ToastService ToastService + Update @User.Username @@ -46,7 +52,7 @@ @code { - [Parameter] public Func OnSubmit { get; set; } + [Parameter] public Func OnCompleted { get; set; } [Parameter] public UserDto User { get; set; } private UpdateUserDto Request; @@ -58,7 +64,23 @@ private async Task OnSubmitAsync(EditContext editContext, ValidationMessageStore validationMessageStore) { - await OnSubmit.Invoke(Request); + var response = await HttpClient.PatchAsJsonAsync( + $"/api/admin/users/{User.Id}", + Request + ); + + if (!response.IsSuccessStatusCode) + { + await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); + return false; + } + + await ToastService.SuccessAsync( + "User update", + $"Successfully updated user {Request.Username}" + ); + + await OnCompleted.Invoke(); await CloseAsync(); return true; diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/ApiKeys.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/ApiKeys.razor index db99b5b2..ff344fd1 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/ApiKeys.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/ApiKeys.razor @@ -123,19 +123,8 @@ { await DialogService.LaunchAsync(parameters => { - parameters[nameof(CreateApiKeyDialog.OnSubmit)] = async (CreateApiKeyDto dto) => + parameters[nameof(CreateApiKeyDialog.OnSubmit)] = async () => { - await HttpClient.PostAsJsonAsync( - "/api/admin/apiKeys", - dto, - Constants.SerializerOptions - ); - - await ToastService.SuccessAsync( - "API Key creation", - $"Successfully created API key {dto.Name}" - ); - await Grid.RefreshAsync(); }; }); @@ -146,19 +135,8 @@ await DialogService.LaunchAsync(parameters => { parameters[nameof(UpdateApiKeyDialog.Key)] = key; - parameters[nameof(UpdateApiKeyDialog.OnSubmit)] = async (UpdateApiKeyDto dto) => + parameters[nameof(UpdateApiKeyDialog.OnSubmit)] = async () => { - await HttpClient.PatchAsJsonAsync( - $"/api/admin/apiKeys/{key.Id}", - dto, - Constants.SerializerOptions - ); - - await ToastService.SuccessAsync( - "API Key update", - $"Successfully updated API key {dto.Name}" - ); - await Grid.RefreshAsync(); }; }); diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor index 1c5fa9e5..759eaa5d 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor @@ -3,6 +3,7 @@ @using Microsoft.AspNetCore.Authorization @using Moonlight.Shared @using LucideBlazor +@using Moonlight.Frontend.Helpers @using Moonlight.Frontend.Services @using Moonlight.Shared.Http.Requests.Themes @using ShadcnBlazor.Buttons @@ -118,11 +119,17 @@ { Request.CssContent = await Editor.GetValueAsync(); - await HttpClient.PostAsJsonAsync( + var response = await HttpClient.PostAsJsonAsync( "/api/admin/themes", Request, Constants.SerializerOptions ); + + if (!response.IsSuccessStatusCode) + { + await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); + return false; + } await ToastService.SuccessAsync( "Theme creation", diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor index eed40f9e..bab7f725 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor @@ -3,6 +3,7 @@ @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.Requests.Themes @@ -132,11 +133,17 @@ { Request.CssContent = await Editor.GetValueAsync(); - await HttpClient.PatchAsJsonAsync( + var response = await HttpClient.PatchAsJsonAsync( $"/api/admin/themes/{Theme.Id}", Request, Constants.SerializerOptions ); + + if (!response.IsSuccessStatusCode) + { + await ProblemDetailsHelper.HandleProblemDetailsAsync(response, Request, validationMessageStore); + return false; + } await ToastService.SuccessAsync( "Theme update", diff --git a/Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor b/Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor index 7d7753ce..195ebae1 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor @@ -134,15 +134,8 @@ { await DialogService.LaunchAsync(parameters => { - parameters[nameof(CreateRoleDialog.OnSubmit)] = async Task (CreateRoleDto request) => + parameters[nameof(CreateRoleDialog.OnSubmit)] = async Task () => { - await HttpClient.PostAsJsonAsync( - "api/admin/roles", - request, - Constants.SerializerOptions - ); - - await ToastService.SuccessAsync("Role creation", $"Role {request.Name} has been successfully created"); await Grid.RefreshAsync(); }; }); @@ -153,15 +146,8 @@ await DialogService.LaunchAsync(parameters => { parameters[nameof(UpdateRoleDialog.Role)] = role; - parameters[nameof(UpdateRoleDialog.OnSubmit)] = async Task (UpdateRoleDto request) => + parameters[nameof(UpdateRoleDialog.OnSubmit)] = async Task () => { - await HttpClient.PatchAsJsonAsync( - $"api/admin/roles/{role.Id}", - request, - Constants.SerializerOptions - ); - - await ToastService.SuccessAsync("Role update", $"Role {request.Name} has been successfully updated"); await Grid.RefreshAsync(); }; }); diff --git a/Moonlight.Frontend/UI/Admin/Views/Users/Users.razor b/Moonlight.Frontend/UI/Admin/Views/Users/Users.razor index 55f49383..d7778005 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Users/Users.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Users/Users.razor @@ -124,19 +124,8 @@ { await DialogService.LaunchAsync(parameters => { - parameters[nameof(CreateUserDialog.OnSubmit)] = async (CreateUserDto dto) => + parameters[nameof(CreateUserDialog.OnCompleted)] = async () => { - await HttpClient.PostAsJsonAsync( - "/api/admin/users", - dto, - Constants.SerializerOptions - ); - - await ToastService.SuccessAsync( - "User creation", - $"Successfully created user {dto.Username}" - ); - await Grid.RefreshAsync(); }; }); @@ -147,18 +136,8 @@ await DialogService.LaunchAsync(parameters => { parameters[nameof(UpdateUserDialog.User)] = user; - parameters[nameof(CreateUserDialog.OnSubmit)] = async (UpdateUserDto dto) => + parameters[nameof(UpdateUserDialog.OnCompleted)] = async () => { - await HttpClient.PatchAsJsonAsync( - $"/api/admin/users/{user.Id}", - dto - ); - - await ToastService.SuccessAsync( - "User update", - $"Successfully updated user {dto.Username}" - ); - await Grid.RefreshAsync(); }; }); diff --git a/Moonlight.Shared/Http/Responses/ProblemDetails.cs b/Moonlight.Shared/Http/Responses/ProblemDetails.cs new file mode 100644 index 00000000..0af3bc50 --- /dev/null +++ b/Moonlight.Shared/Http/Responses/ProblemDetails.cs @@ -0,0 +1,10 @@ +namespace Moonlight.Shared.Http.Responses; + +public class ProblemDetails +{ + public string Type { get; set; } + public string Title { get; set; } + public int Status { get; set; } + public string? Detail { get; set; } + public Dictionary? Errors { get; set; } +} \ No newline at end of file diff --git a/Moonlight.Shared/Http/SerializationContext.cs b/Moonlight.Shared/Http/SerializationContext.cs index 3f22bc9e..d070f7ff 100644 --- a/Moonlight.Shared/Http/SerializationContext.cs +++ b/Moonlight.Shared/Http/SerializationContext.cs @@ -50,6 +50,9 @@ namespace Moonlight.Shared.Http; // Container Helper [JsonSerializable(typeof(ContainerHelperStatusDto))] + +// Misc +[JsonSerializable(typeof(ProblemDetails))] public partial class SerializationContext : JsonSerializerContext { } \ No newline at end of file From e1207b8d9b38dd1b487223228e7be4b22c278143 Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Thu, 29 Jan 2026 11:23:07 +0100 Subject: [PATCH 07/10] Refactored container helper service. Cleaned up event models. Implemented version changing. Added security questions before rebuild --- ...roller.cs => ContainerHelperController.cs} | 16 +++- .../ContainerHelper/Events/RebuildEventDto.cs | 20 +++++ .../ContainerHelper/ProblemDetails.cs | 10 +++ .../ContainerHelper/Requests/SetVersionDto.cs | 3 + .../ContainerHelper/SerializationContext.cs | 28 +++++++ .../Mappers/ContainerHelperMapper.cs | 13 +++ Moonlight.Api/Moonlight.Api.csproj | 4 + .../Services/ContainerHelperService.cs | 74 ++++++++++------- Moonlight.Api/Startup/Startup.Base.cs | 2 +- Moonlight.Frontend/Constants.cs | 2 +- .../UI/Admin/Modals/UpdateInstanceModal.razor | 8 +- .../UI/Admin/Views/Sys/Instance.razor | 83 +++++++++++++++---- .../{RebuildEvent.cs => RebuildEventDto.cs} | 2 +- .../Admin/ContainerHelper/SetVersionDto.cs | 10 +++ ...ntext.cs => SharedSerializationContext.cs} | 22 ++++- 15 files changed, 242 insertions(+), 55 deletions(-) rename Moonlight.Api/Http/Controllers/Admin/{ChController.cs => ContainerHelperController.cs} (63%) create mode 100644 Moonlight.Api/Http/Services/ContainerHelper/Events/RebuildEventDto.cs create mode 100644 Moonlight.Api/Http/Services/ContainerHelper/ProblemDetails.cs create mode 100644 Moonlight.Api/Http/Services/ContainerHelper/Requests/SetVersionDto.cs create mode 100644 Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs create mode 100644 Moonlight.Api/Mappers/ContainerHelperMapper.cs rename Moonlight.Shared/Http/Events/{RebuildEvent.cs => RebuildEventDto.cs} (91%) create mode 100644 Moonlight.Shared/Http/Requests/Admin/ContainerHelper/SetVersionDto.cs rename Moonlight.Shared/Http/{SerializationContext.cs => SharedSerializationContext.cs} (71%) diff --git a/Moonlight.Api/Http/Controllers/Admin/ChController.cs b/Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs similarity index 63% rename from Moonlight.Api/Http/Controllers/Admin/ChController.cs rename to Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs index cb501b41..599351a5 100644 --- a/Moonlight.Api/Http/Controllers/Admin/ChController.cs +++ b/Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs @@ -2,19 +2,21 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using Moonlight.Api.Configuration; +using Moonlight.Api.Mappers; using Moonlight.Api.Services; +using Moonlight.Shared.Http.Requests.Admin.ContainerHelper; using Moonlight.Shared.Http.Responses.Admin; namespace Moonlight.Api.Http.Controllers.Admin; [ApiController] [Route("api/admin/ch")] -public class ChController : Controller +public class ContainerHelperController : Controller { private readonly ContainerHelperService ContainerHelperService; private readonly IOptions Options; - public ChController(ContainerHelperService containerHelperService, IOptions options) + public ContainerHelperController(ContainerHelperService containerHelperService, IOptions options) { ContainerHelperService = containerHelperService; Options = options; @@ -35,9 +37,17 @@ public class ChController : Controller public Task RebuildAsync() { var result = ContainerHelperService.RebuildAsync(); + var mappedResult = result.Select(ContainerHelperMapper.ToDto); return Task.FromResult( - TypedResults.ServerSentEvents(result) + TypedResults.ServerSentEvents(mappedResult) ); } + + [HttpPost("version")] + public async Task SetVersionAsync([FromBody] SetVersionDto request) + { + await ContainerHelperService.SetVersionAsync(request.Version); + return NoContent(); + } } \ No newline at end of file diff --git a/Moonlight.Api/Http/Services/ContainerHelper/Events/RebuildEventDto.cs b/Moonlight.Api/Http/Services/ContainerHelper/Events/RebuildEventDto.cs new file mode 100644 index 00000000..1742b643 --- /dev/null +++ b/Moonlight.Api/Http/Services/ContainerHelper/Events/RebuildEventDto.cs @@ -0,0 +1,20 @@ +using System.Text.Json.Serialization; + +namespace Moonlight.Api.Http.Services.ContainerHelper.Events; + +public struct RebuildEventDto +{ + [JsonPropertyName("type")] + public RebuildEventType Type { get; set; } + + [JsonPropertyName("data")] + public string Data { get; set; } +} + +public enum RebuildEventType +{ + Log = 0, + Failed = 1, + Succeeded = 2, + Step = 3 +} \ No newline at end of file diff --git a/Moonlight.Api/Http/Services/ContainerHelper/ProblemDetails.cs b/Moonlight.Api/Http/Services/ContainerHelper/ProblemDetails.cs new file mode 100644 index 00000000..925672c6 --- /dev/null +++ b/Moonlight.Api/Http/Services/ContainerHelper/ProblemDetails.cs @@ -0,0 +1,10 @@ +namespace Moonlight.Api.Http.Services.ContainerHelper; + +public class ProblemDetails +{ + public string Type { get; set; } + public string Title { get; set; } + public int Status { get; set; } + public string? Detail { get; set; } + public Dictionary? Errors { get; set; } +} \ No newline at end of file diff --git a/Moonlight.Api/Http/Services/ContainerHelper/Requests/SetVersionDto.cs b/Moonlight.Api/Http/Services/ContainerHelper/Requests/SetVersionDto.cs new file mode 100644 index 00000000..4c462fbc --- /dev/null +++ b/Moonlight.Api/Http/Services/ContainerHelper/Requests/SetVersionDto.cs @@ -0,0 +1,3 @@ +namespace Moonlight.Api.Http.Services.ContainerHelper.Requests; + +public record SetVersionDto(string Version); \ No newline at end of file diff --git a/Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs b/Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs new file mode 100644 index 00000000..182f44d1 --- /dev/null +++ b/Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs @@ -0,0 +1,28 @@ +using System.Text.Json; +using System.Text.Json.Serialization; +using Moonlight.Api.Http.Services.ContainerHelper.Events; +using Moonlight.Api.Http.Services.ContainerHelper.Requests; + +namespace Moonlight.Api.Http.Services.ContainerHelper; + +[JsonSerializable(typeof(SetVersionDto))] +[JsonSerializable(typeof(ProblemDetails))] +[JsonSerializable(typeof(RebuildEventDto))] +public partial class SerializationContext : JsonSerializerContext +{ + private static JsonSerializerOptions? InternalTunedOptions; + + public static JsonSerializerOptions TunedOptions + { + get + { + if (InternalTunedOptions != null) + return InternalTunedOptions; + + InternalTunedOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); + InternalTunedOptions.TypeInfoResolverChain.Add(Default); + + return InternalTunedOptions; + } + } +} \ No newline at end of file diff --git a/Moonlight.Api/Mappers/ContainerHelperMapper.cs b/Moonlight.Api/Mappers/ContainerHelperMapper.cs new file mode 100644 index 00000000..26cc39b4 --- /dev/null +++ b/Moonlight.Api/Mappers/ContainerHelperMapper.cs @@ -0,0 +1,13 @@ +using System.Diagnostics.CodeAnalysis; +using Moonlight.Shared.Http.Events; +using Riok.Mapperly.Abstractions; + +namespace Moonlight.Api.Mappers; + +[Mapper] +[SuppressMessage("Mapper", "RMG020:No members are mapped in an object mapping")] +[SuppressMessage("Mapper", "RMG012:No members are mapped in an object mapping")] +public static partial class ContainerHelperMapper +{ + public static partial RebuildEventDto ToDto(Http.Services.ContainerHelper.Events.RebuildEventDto rebuildEventDto); +} \ No newline at end of file diff --git a/Moonlight.Api/Moonlight.Api.csproj b/Moonlight.Api/Moonlight.Api.csproj index dcf0ef3e..10a62a6c 100644 --- a/Moonlight.Api/Moonlight.Api.csproj +++ b/Moonlight.Api/Moonlight.Api.csproj @@ -35,4 +35,8 @@ false + + + + \ No newline at end of file diff --git a/Moonlight.Api/Services/ContainerHelperService.cs b/Moonlight.Api/Services/ContainerHelperService.cs index feb6a142..5467fe94 100644 --- a/Moonlight.Api/Services/ContainerHelperService.cs +++ b/Moonlight.Api/Services/ContainerHelperService.cs @@ -1,6 +1,8 @@ -using System.Text.Json; -using Moonlight.Shared.Http; -using Moonlight.Shared.Http.Events; +using System.Net.Http.Json; +using System.Text.Json; +using Moonlight.Api.Http.Services.ContainerHelper; +using Moonlight.Api.Http.Services.ContainerHelper.Requests; +using Moonlight.Api.Http.Services.ContainerHelper.Events; namespace Moonlight.Api.Services; @@ -30,61 +32,73 @@ public class ContainerHelperService } } - public async IAsyncEnumerable RebuildAsync() + public async IAsyncEnumerable RebuildAsync() { - var options = new JsonSerializerOptions() - { - PropertyNameCaseInsensitive = true - }; - - options.TypeInfoResolverChain.Add(SerializationContext.Default); - var client = HttpClientFactory.CreateClient("ContainerHelper"); - + var response = await client.GetAsync("api/rebuild", HttpCompletionOption.ResponseHeadersRead); if (!response.IsSuccessStatusCode) { var responseText = await response.Content.ReadAsStringAsync(); - - yield return new RebuildEvent() + + yield return new RebuildEventDto() { - Type = RebuildEventType.Failed, + Type = RebuildEventType.Failed, Data = responseText }; - + yield break; } await using var responseStream = await response.Content.ReadAsStreamAsync(); using var streamReader = new StreamReader(responseStream); - + do { var line = await streamReader.ReadLineAsync(); - - if(line == null) + + if (line == null) break; - - if(string.IsNullOrWhiteSpace(line)) + + if (string.IsNullOrWhiteSpace(line)) continue; - + var data = line.Trim("data: "); - - var deserializedData = JsonSerializer.Deserialize(data, options); - + var deserializedData = JsonSerializer.Deserialize(data, SerializationContext.TunedOptions); + yield return deserializedData; - + // Exit if service will go down for a clean exit - if(deserializedData is {Type: RebuildEventType.Step, Data: "ServiceDown"}) + if (deserializedData is { Type: RebuildEventType.Step, Data: "ServiceDown" }) yield break; - } while (true); - - yield return new RebuildEvent() + + yield return new RebuildEventDto() { Type = RebuildEventType.Succeeded, Data = string.Empty }; } + + public async Task SetVersionAsync(string version) + { + var client = HttpClientFactory.CreateClient("ContainerHelper"); + + var response = await client.PostAsJsonAsync( + "api/configuration/version", + new SetVersionDto(version), + SerializationContext.TunedOptions + ); + + if(response.IsSuccessStatusCode) + return; + + var problemDetails = await response.Content.ReadFromJsonAsync(SerializationContext.TunedOptions); + + if(problemDetails == null) + throw new HttpRequestException($"Failed to set version: {response.ReasonPhrase}"); + + throw new HttpRequestException($"Failed to set version: {problemDetails.Detail ?? problemDetails.Title}"); + } } \ No newline at end of file diff --git a/Moonlight.Api/Startup/Startup.Base.cs b/Moonlight.Api/Startup/Startup.Base.cs index 25c97ea6..a40e42b3 100644 --- a/Moonlight.Api/Startup/Startup.Base.cs +++ b/Moonlight.Api/Startup/Startup.Base.cs @@ -19,7 +19,7 @@ public partial class Startup { builder.Services.AddControllers().AddJsonOptions(options => { - options.JsonSerializerOptions.TypeInfoResolverChain.Add(SerializationContext.Default); + options.JsonSerializerOptions.TypeInfoResolverChain.Add(SharedSerializationContext.Default); }); builder.Logging.ClearProviders(); diff --git a/Moonlight.Frontend/Constants.cs b/Moonlight.Frontend/Constants.cs index 5c42627f..685cc859 100644 --- a/Moonlight.Frontend/Constants.cs +++ b/Moonlight.Frontend/Constants.cs @@ -18,7 +18,7 @@ public static class Constants }; // Add source generated options from shared project - InternalOptions.TypeInfoResolverChain.Add(SerializationContext.Default); + InternalOptions.TypeInfoResolverChain.Add(SharedSerializationContext.Default); return InternalOptions; } diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor index a4f10c1c..7bbc6ffc 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor @@ -3,6 +3,7 @@ @using System.Text.Json @using LucideBlazor @using Moonlight.Shared.Http.Events +@using Moonlight.Shared.Http.Requests.Admin.ContainerHelper @using ShadcnBlazor.Buttons @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Progresses @@ -110,7 +111,10 @@ else Progress = 20; await InvokeAsync(StateHasChanged); - await Task.Delay(2000); + await HttpClient.PostAsJsonAsync("api/admin/ch/version", new SetVersionDto() + { + Version = Version + }); // Starting rebuild task CurrentStep = 2; @@ -138,7 +142,7 @@ else continue; var data = line.Trim("data: "); - var deserializedData = JsonSerializer.Deserialize(data, Constants.SerializerOptions); + var deserializedData = JsonSerializer.Deserialize(data, Constants.SerializerOptions); switch (deserializedData.Type) { diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor index fd2c865a..13fc0438 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor @@ -1,3 +1,4 @@ +@using System.Text.RegularExpressions @using LucideBlazor @using Moonlight.Frontend.UI.Admin.Modals @using Moonlight.Shared.Http.Responses.Admin @@ -39,14 +40,15 @@ v2.1 - v2.1.1 + feat/ContainerHelper +
- +
@@ -116,20 +118,73 @@ private async Task ApplyAsync() { - await AlertDialogService.ConfirmDangerAsync( - "Moonlight Rebuild", - "If you continue the moonlight instance will become unavailable during the rebuild process. This will impact users on this instance", - async () => + await DialogService.LaunchAsync( + parameters => { parameters[nameof(UpdateInstanceModal.Version)] = SelectedVersion; }, + onConfigure: model => { - await DialogService.LaunchAsync( - parameters => { parameters[nameof(UpdateInstanceModal.Version)] = SelectedVersion; }, - onConfigure: model => - { - model.ShowCloseButton = false; - model.ClassName = "sm:max-w-4xl!"; - } - ); + model.ShowCloseButton = false; + model.ClassName = "sm:max-w-4xl!"; } ); } + + private async Task AskApplyAsync() + { + if(string.IsNullOrWhiteSpace(SelectedVersion)) + return; + + var shouldContinue = await ConfirmRiskyVersionAsync( + "Moonlight Rebuild", + "If you continue the moonlight instance will become unavailable during the rebuild process. This will impact users on this instance" + ); + + if(!shouldContinue) + return; + + if (!Regex.IsMatch(SelectedVersion, @"^v\d+(\.\d+)*b?$")) + { + shouldContinue = await ConfirmRiskyVersionAsync( + "Development Version", + "You are about to install development a version. This can break your instance. Continue at your own risk" + ); + } + else + { + if (SelectedVersion.EndsWith('b')) + { + shouldContinue = await ConfirmRiskyVersionAsync( + "Beta / Pre-Release Version", + "You are about to install a version marked as pre-release / beta. This can break your instance. Continue at your own risk" + ); + } + else + shouldContinue = true; + } + + if (!shouldContinue) + return; + + await ApplyAsync(); + } + + private async Task ConfirmRiskyVersionAsync(string title, string message) + { + var tcs = new TaskCompletionSource(); + var confirmed = false; + + await AlertDialogService.ConfirmDangerAsync( + title, + message, + () => + { + confirmed = true; + tcs.SetResult(); + return Task.CompletedTask; + } + ); + + await tcs.Task; + + return confirmed; + } } diff --git a/Moonlight.Shared/Http/Events/RebuildEvent.cs b/Moonlight.Shared/Http/Events/RebuildEventDto.cs similarity index 91% rename from Moonlight.Shared/Http/Events/RebuildEvent.cs rename to Moonlight.Shared/Http/Events/RebuildEventDto.cs index c3edab82..ecfdefb8 100644 --- a/Moonlight.Shared/Http/Events/RebuildEvent.cs +++ b/Moonlight.Shared/Http/Events/RebuildEventDto.cs @@ -2,7 +2,7 @@ namespace Moonlight.Shared.Http.Events; -public struct RebuildEvent +public struct RebuildEventDto { [JsonPropertyName("type")] public RebuildEventType Type { get; set; } diff --git a/Moonlight.Shared/Http/Requests/Admin/ContainerHelper/SetVersionDto.cs b/Moonlight.Shared/Http/Requests/Admin/ContainerHelper/SetVersionDto.cs new file mode 100644 index 00000000..fab46fd1 --- /dev/null +++ b/Moonlight.Shared/Http/Requests/Admin/ContainerHelper/SetVersionDto.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations; + +namespace Moonlight.Shared.Http.Requests.Admin.ContainerHelper; + +public class SetVersionDto +{ + [Required] + [RegularExpression(@"^(?!\/|.*\/\/|.*\.\.|.*\/$)[A-Za-z0-9._/-]+$", ErrorMessage = "Invalid version format")] + public string Version { get; set; } +} \ No newline at end of file diff --git a/Moonlight.Shared/Http/SerializationContext.cs b/Moonlight.Shared/Http/SharedSerializationContext.cs similarity index 71% rename from Moonlight.Shared/Http/SerializationContext.cs rename to Moonlight.Shared/Http/SharedSerializationContext.cs index d070f7ff..3fa23a66 100644 --- a/Moonlight.Shared/Http/SerializationContext.cs +++ b/Moonlight.Shared/Http/SharedSerializationContext.cs @@ -1,4 +1,5 @@ -using System.Text.Json.Serialization; +using System.Text.Json; +using System.Text.Json.Serialization; using Moonlight.Shared.Http.Events; using Moonlight.Shared.Http.Requests.ApiKeys; using Moonlight.Shared.Http.Requests.Roles; @@ -46,13 +47,28 @@ namespace Moonlight.Shared.Http; [JsonSerializable(typeof(ThemeDto))] // Events -[JsonSerializable(typeof(RebuildEvent))] +[JsonSerializable(typeof(RebuildEventDto))] // Container Helper [JsonSerializable(typeof(ContainerHelperStatusDto))] // Misc [JsonSerializable(typeof(ProblemDetails))] -public partial class SerializationContext : JsonSerializerContext +public partial class SharedSerializationContext : JsonSerializerContext { + private static JsonSerializerOptions? InternalTunedOptions; + + public static JsonSerializerOptions TunedOptions + { + get + { + if (InternalTunedOptions != null) + return InternalTunedOptions; + + InternalTunedOptions = new JsonSerializerOptions(JsonSerializerDefaults.Web); + InternalTunedOptions.TypeInfoResolverChain.Add(Default); + + return InternalTunedOptions; + } + } } \ No newline at end of file From 8181404f0c8fcf04d5c8c8d811a4047e9eebb4b9 Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Thu, 29 Jan 2026 12:45:09 +0100 Subject: [PATCH 08/10] Moved request and responses dtos to correct namespace --- .../Http/Controllers/Admin/ApiKeyController.cs | 4 ++-- .../Controllers/Admin/RoleMembersController.cs | 2 +- .../Http/Controllers/Admin/RolesController.cs | 2 +- .../Http/Controllers/Admin/ThemesController.cs | 4 ++-- .../Http/Controllers/Admin/UsersController.cs | 4 ++-- Moonlight.Api/Http/Controllers/AuthController.cs | 2 +- .../Http/Controllers/FrontendController.cs | 2 +- Moonlight.Api/Mappers/ApiKeyMapper.cs | 4 ++-- Moonlight.Api/Mappers/FrontendConfigMapper.cs | 2 +- Moonlight.Api/Mappers/RoleMapper.cs | 2 +- Moonlight.Api/Mappers/ThemeMapper.cs | 4 ++-- Moonlight.Api/Mappers/UserMapper.cs | 4 ++-- Moonlight.Frontend/Mappers/ApiKeyMapper.cs | 4 ++-- Moonlight.Frontend/Mappers/RoleMapper.cs | 2 +- Moonlight.Frontend/Mappers/ThemeMapper.cs | 4 ++-- Moonlight.Frontend/Mappers/UserMapper.cs | 4 ++-- .../Services/RemoteAuthProvider.cs | 2 +- .../UI/Admin/Modals/CreateApiKeyDialog.razor | 2 +- .../UI/Admin/Modals/CreateRoleDialog.razor | 2 +- .../UI/Admin/Modals/CreateUserDialog.razor | 2 +- .../Admin/Modals/ManageRoleMembersDialog.razor | 2 +- .../UI/Admin/Modals/UpdateApiKeyDialog.razor | 4 ++-- .../UI/Admin/Modals/UpdateRoleDialog.razor | 2 +- .../UI/Admin/Modals/UpdateUserDialog.razor | 4 ++-- .../UI/Admin/Views/Sys/ApiKeys.razor | 5 ++--- .../UI/Admin/Views/Sys/Themes/Create.razor | 2 +- .../UI/Admin/Views/Sys/Themes/Index.razor | 2 +- .../UI/Admin/Views/Sys/Themes/Update.razor | 4 ++-- .../UI/Admin/Views/Users/Roles.razor | 1 - .../UI/Admin/Views/Users/Users.razor | 3 +-- .../Shared/Components/Auth/Authentication.razor | 4 ++-- .../{ => Admin}/ApiKeys/CreateApiKeyDto.cs | 2 +- .../{ => Admin}/ApiKeys/UpdateApiKeyDto.cs | 2 +- .../Requests/{ => Admin}/Roles/CreateRoleDto.cs | 2 +- .../Requests/{ => Admin}/Roles/UpdateRoleDto.cs | 2 +- .../{ => Admin}/Themes/CreateThemeDto.cs | 2 +- .../{ => Admin}/Themes/UpdateThemeDto.cs | 2 +- .../Requests/{ => Admin}/Users/CreateUserDto.cs | 2 +- .../Requests/{ => Admin}/Users/UpdateUserDto.cs | 2 +- .../Responses/{ => Admin}/ApiKeys/ApiKeyDto.cs | 2 +- .../Http/Responses/Admin/Auth/ClaimDto.cs | 3 +++ .../Http/Responses/{ => Admin}/Auth/SchemeDto.cs | 2 +- .../{ => Admin}/Frontend/FrontendConfigDto.cs | 2 +- .../Responses/{ => Admin}/Themes/ThemeDto.cs | 2 +- .../Http/Responses/{ => Admin}/Users/UserDto.cs | 2 +- Moonlight.Shared/Http/Responses/Auth/ClaimDto.cs | 3 --- .../Http/SharedSerializationContext.cs | 16 ++++++++-------- 47 files changed, 68 insertions(+), 71 deletions(-) rename Moonlight.Shared/Http/Requests/{ => Admin}/ApiKeys/CreateApiKeyDto.cs (84%) rename Moonlight.Shared/Http/Requests/{ => Admin}/ApiKeys/UpdateApiKeyDto.cs (83%) rename Moonlight.Shared/Http/Requests/{ => Admin}/Roles/CreateRoleDto.cs (83%) rename Moonlight.Shared/Http/Requests/{ => Admin}/Roles/UpdateRoleDto.cs (83%) rename Moonlight.Shared/Http/Requests/{ => Admin}/Themes/CreateThemeDto.cs (88%) rename Moonlight.Shared/Http/Requests/{ => Admin}/Themes/UpdateThemeDto.cs (88%) rename Moonlight.Shared/Http/Requests/{ => Admin}/Users/CreateUserDto.cs (81%) rename Moonlight.Shared/Http/Requests/{ => Admin}/Users/UpdateUserDto.cs (81%) rename Moonlight.Shared/Http/Responses/{ => Admin}/ApiKeys/ApiKeyDto.cs (71%) create mode 100644 Moonlight.Shared/Http/Responses/Admin/Auth/ClaimDto.cs rename Moonlight.Shared/Http/Responses/{ => Admin}/Auth/SchemeDto.cs (50%) rename Moonlight.Shared/Http/Responses/{ => Admin}/Frontend/FrontendConfigDto.cs (52%) rename Moonlight.Shared/Http/Responses/{ => Admin}/Themes/ThemeDto.cs (66%) rename Moonlight.Shared/Http/Responses/{ => Admin}/Users/UserDto.cs (66%) delete mode 100644 Moonlight.Shared/Http/Responses/Auth/ClaimDto.cs diff --git a/Moonlight.Api/Http/Controllers/Admin/ApiKeyController.cs b/Moonlight.Api/Http/Controllers/Admin/ApiKeyController.cs index e1c27afd..23c47e95 100644 --- a/Moonlight.Api/Http/Controllers/Admin/ApiKeyController.cs +++ b/Moonlight.Api/Http/Controllers/Admin/ApiKeyController.cs @@ -6,9 +6,9 @@ using Moonlight.Api.Database.Entities; using Moonlight.Api.Mappers; using Moonlight.Shared; using Moonlight.Shared.Http.Requests; -using Moonlight.Shared.Http.Requests.ApiKeys; +using Moonlight.Shared.Http.Requests.Admin.ApiKeys; using Moonlight.Shared.Http.Responses; -using Moonlight.Shared.Http.Responses.ApiKeys; +using Moonlight.Shared.Http.Responses.Admin.ApiKeys; namespace Moonlight.Api.Http.Controllers.Admin; diff --git a/Moonlight.Api/Http/Controllers/Admin/RoleMembersController.cs b/Moonlight.Api/Http/Controllers/Admin/RoleMembersController.cs index 662516a4..ea2619c0 100644 --- a/Moonlight.Api/Http/Controllers/Admin/RoleMembersController.cs +++ b/Moonlight.Api/Http/Controllers/Admin/RoleMembersController.cs @@ -6,7 +6,7 @@ using Moonlight.Api.Database.Entities; using Moonlight.Api.Mappers; using Moonlight.Shared; using Moonlight.Shared.Http.Responses; -using Moonlight.Shared.Http.Responses.Users; +using Moonlight.Shared.Http.Responses.Admin.Users; namespace Moonlight.Api.Http.Controllers.Admin; diff --git a/Moonlight.Api/Http/Controllers/Admin/RolesController.cs b/Moonlight.Api/Http/Controllers/Admin/RolesController.cs index 9e828f9b..af1bdbff 100644 --- a/Moonlight.Api/Http/Controllers/Admin/RolesController.cs +++ b/Moonlight.Api/Http/Controllers/Admin/RolesController.cs @@ -6,7 +6,7 @@ using Moonlight.Api.Database.Entities; using Moonlight.Api.Mappers; using Moonlight.Shared; using Moonlight.Shared.Http.Requests; -using Moonlight.Shared.Http.Requests.Roles; +using Moonlight.Shared.Http.Requests.Admin.Roles; using Moonlight.Shared.Http.Responses; using Moonlight.Shared.Http.Responses.Admin; diff --git a/Moonlight.Api/Http/Controllers/Admin/ThemesController.cs b/Moonlight.Api/Http/Controllers/Admin/ThemesController.cs index 0c46ae39..8c9b08e9 100644 --- a/Moonlight.Api/Http/Controllers/Admin/ThemesController.cs +++ b/Moonlight.Api/Http/Controllers/Admin/ThemesController.cs @@ -7,9 +7,9 @@ using Moonlight.Api.Mappers; using Moonlight.Api.Services; using Moonlight.Shared; using Moonlight.Shared.Http.Requests; -using Moonlight.Shared.Http.Requests.Themes; +using Moonlight.Shared.Http.Requests.Admin.Themes; using Moonlight.Shared.Http.Responses; -using Moonlight.Shared.Http.Responses.Themes; +using Moonlight.Shared.Http.Responses.Admin.Themes; namespace Moonlight.Api.Http.Controllers.Admin; diff --git a/Moonlight.Api/Http/Controllers/Admin/UsersController.cs b/Moonlight.Api/Http/Controllers/Admin/UsersController.cs index 79110804..f4500f3d 100644 --- a/Moonlight.Api/Http/Controllers/Admin/UsersController.cs +++ b/Moonlight.Api/Http/Controllers/Admin/UsersController.cs @@ -6,9 +6,9 @@ using Moonlight.Api.Database.Entities; using Moonlight.Api.Mappers; using Moonlight.Shared; using Moonlight.Shared.Http.Requests; -using Moonlight.Shared.Http.Requests.Users; +using Moonlight.Shared.Http.Requests.Admin.Users; using Moonlight.Shared.Http.Responses; -using Moonlight.Shared.Http.Responses.Users; +using Moonlight.Shared.Http.Responses.Admin.Users; namespace Moonlight.Api.Http.Controllers.Admin; diff --git a/Moonlight.Api/Http/Controllers/AuthController.cs b/Moonlight.Api/Http/Controllers/AuthController.cs index a5ff547a..34dc18e7 100644 --- a/Moonlight.Api/Http/Controllers/AuthController.cs +++ b/Moonlight.Api/Http/Controllers/AuthController.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Moonlight.Shared.Http.Responses.Auth; +using Moonlight.Shared.Http.Responses.Admin.Auth; namespace Moonlight.Api.Http.Controllers; diff --git a/Moonlight.Api/Http/Controllers/FrontendController.cs b/Moonlight.Api/Http/Controllers/FrontendController.cs index cdf201ee..6fffb0aa 100644 --- a/Moonlight.Api/Http/Controllers/FrontendController.cs +++ b/Moonlight.Api/Http/Controllers/FrontendController.cs @@ -1,7 +1,7 @@ using Microsoft.AspNetCore.Mvc; using Moonlight.Api.Mappers; using Moonlight.Api.Services; -using Moonlight.Shared.Http.Responses.Frontend; +using Moonlight.Shared.Http.Responses.Admin.Frontend; namespace Moonlight.Api.Http.Controllers; diff --git a/Moonlight.Api/Mappers/ApiKeyMapper.cs b/Moonlight.Api/Mappers/ApiKeyMapper.cs index f4f694ad..55dd62e1 100644 --- a/Moonlight.Api/Mappers/ApiKeyMapper.cs +++ b/Moonlight.Api/Mappers/ApiKeyMapper.cs @@ -1,7 +1,7 @@ using System.Diagnostics.CodeAnalysis; using Moonlight.Api.Database.Entities; -using Moonlight.Shared.Http.Requests.ApiKeys; -using Moonlight.Shared.Http.Responses.ApiKeys; +using Moonlight.Shared.Http.Requests.Admin.ApiKeys; +using Moonlight.Shared.Http.Responses.Admin.ApiKeys; using Riok.Mapperly.Abstractions; namespace Moonlight.Api.Mappers; diff --git a/Moonlight.Api/Mappers/FrontendConfigMapper.cs b/Moonlight.Api/Mappers/FrontendConfigMapper.cs index 85118685..e731d714 100644 --- a/Moonlight.Api/Mappers/FrontendConfigMapper.cs +++ b/Moonlight.Api/Mappers/FrontendConfigMapper.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; using Moonlight.Api.Models; -using Moonlight.Shared.Http.Responses.Frontend; +using Moonlight.Shared.Http.Responses.Admin.Frontend; using Riok.Mapperly.Abstractions; namespace Moonlight.Api.Mappers; diff --git a/Moonlight.Api/Mappers/RoleMapper.cs b/Moonlight.Api/Mappers/RoleMapper.cs index 7ac52dad..b4a4e0ad 100644 --- a/Moonlight.Api/Mappers/RoleMapper.cs +++ b/Moonlight.Api/Mappers/RoleMapper.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; using Moonlight.Api.Database.Entities; -using Moonlight.Shared.Http.Requests.Roles; +using Moonlight.Shared.Http.Requests.Admin.Roles; using Moonlight.Shared.Http.Responses.Admin; using Riok.Mapperly.Abstractions; diff --git a/Moonlight.Api/Mappers/ThemeMapper.cs b/Moonlight.Api/Mappers/ThemeMapper.cs index ad266092..4496a329 100644 --- a/Moonlight.Api/Mappers/ThemeMapper.cs +++ b/Moonlight.Api/Mappers/ThemeMapper.cs @@ -1,7 +1,7 @@ using System.Diagnostics.CodeAnalysis; using Moonlight.Api.Database.Entities; -using Moonlight.Shared.Http.Requests.Themes; -using Moonlight.Shared.Http.Responses.Themes; +using Moonlight.Shared.Http.Requests.Admin.Themes; +using Moonlight.Shared.Http.Responses.Admin.Themes; using Riok.Mapperly.Abstractions; namespace Moonlight.Api.Mappers; diff --git a/Moonlight.Api/Mappers/UserMapper.cs b/Moonlight.Api/Mappers/UserMapper.cs index 2d150bc5..ef9673d3 100644 --- a/Moonlight.Api/Mappers/UserMapper.cs +++ b/Moonlight.Api/Mappers/UserMapper.cs @@ -1,8 +1,8 @@ using System.Diagnostics.CodeAnalysis; using Riok.Mapperly.Abstractions; -using Moonlight.Shared.Http.Requests.Users; -using Moonlight.Shared.Http.Responses.Users; using Moonlight.Api.Database.Entities; +using Moonlight.Shared.Http.Requests.Admin.Users; +using Moonlight.Shared.Http.Responses.Admin.Users; namespace Moonlight.Api.Mappers; diff --git a/Moonlight.Frontend/Mappers/ApiKeyMapper.cs b/Moonlight.Frontend/Mappers/ApiKeyMapper.cs index 77dde21e..b1bb2ad6 100644 --- a/Moonlight.Frontend/Mappers/ApiKeyMapper.cs +++ b/Moonlight.Frontend/Mappers/ApiKeyMapper.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Shared.Http.Requests.ApiKeys; -using Moonlight.Shared.Http.Responses.ApiKeys; +using Moonlight.Shared.Http.Requests.Admin.ApiKeys; +using Moonlight.Shared.Http.Responses.Admin.ApiKeys; using Riok.Mapperly.Abstractions; namespace Moonlight.Frontend.Mappers; diff --git a/Moonlight.Frontend/Mappers/RoleMapper.cs b/Moonlight.Frontend/Mappers/RoleMapper.cs index 3495f872..4c4861f1 100644 --- a/Moonlight.Frontend/Mappers/RoleMapper.cs +++ b/Moonlight.Frontend/Mappers/RoleMapper.cs @@ -1,5 +1,5 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Shared.Http.Requests.Roles; +using Moonlight.Shared.Http.Requests.Admin.Roles; using Moonlight.Shared.Http.Responses.Admin; using Riok.Mapperly.Abstractions; diff --git a/Moonlight.Frontend/Mappers/ThemeMapper.cs b/Moonlight.Frontend/Mappers/ThemeMapper.cs index 8ddff698..2e1747e7 100644 --- a/Moonlight.Frontend/Mappers/ThemeMapper.cs +++ b/Moonlight.Frontend/Mappers/ThemeMapper.cs @@ -1,6 +1,6 @@ using System.Diagnostics.CodeAnalysis; -using Moonlight.Shared.Http.Requests.Themes; -using Moonlight.Shared.Http.Responses.Themes; +using Moonlight.Shared.Http.Requests.Admin.Themes; +using Moonlight.Shared.Http.Responses.Admin.Themes; using Riok.Mapperly.Abstractions; namespace Moonlight.Frontend.Mappers; diff --git a/Moonlight.Frontend/Mappers/UserMapper.cs b/Moonlight.Frontend/Mappers/UserMapper.cs index 0762ba58..c20a8c8f 100644 --- a/Moonlight.Frontend/Mappers/UserMapper.cs +++ b/Moonlight.Frontend/Mappers/UserMapper.cs @@ -1,7 +1,7 @@ using System.Diagnostics.CodeAnalysis; +using Moonlight.Shared.Http.Requests.Admin.Users; +using Moonlight.Shared.Http.Responses.Admin.Users; using Riok.Mapperly.Abstractions; -using Moonlight.Shared.Http.Requests.Users; -using Moonlight.Shared.Http.Responses.Users; namespace Moonlight.Frontend.Mappers; diff --git a/Moonlight.Frontend/Services/RemoteAuthProvider.cs b/Moonlight.Frontend/Services/RemoteAuthProvider.cs index 22cdee35..8e17d6e4 100644 --- a/Moonlight.Frontend/Services/RemoteAuthProvider.cs +++ b/Moonlight.Frontend/Services/RemoteAuthProvider.cs @@ -3,7 +3,7 @@ using System.Net.Http.Json; using System.Security.Claims; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.Extensions.Logging; -using Moonlight.Shared.Http.Responses.Auth; +using Moonlight.Shared.Http.Responses.Admin.Auth; namespace Moonlight.Frontend.Services; diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor index a0e0e899..459164c5 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/CreateApiKeyDialog.razor @@ -1,6 +1,6 @@ @using Moonlight.Frontend.Helpers @using Moonlight.Frontend.UI.Admin.Components -@using Moonlight.Shared.Http.Requests.ApiKeys +@using Moonlight.Shared.Http.Requests.Admin.ApiKeys @using Moonlight.Shared.Http.Responses @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Extras.Forms diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor index 671e8317..942e79b8 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/CreateRoleDialog.razor @@ -1,6 +1,6 @@ @using Moonlight.Frontend.Helpers @using Moonlight.Frontend.UI.Admin.Components -@using Moonlight.Shared.Http.Requests.Roles +@using Moonlight.Shared.Http.Requests.Admin.Roles @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Extras.Forms @using ShadcnBlazor.Extras.Toasts diff --git a/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor index 55c1f566..ff9113de 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/CreateUserDialog.razor @@ -1,5 +1,5 @@ @using Moonlight.Frontend.Helpers -@using Moonlight.Shared.Http.Requests.Users +@using Moonlight.Shared.Http.Requests.Admin.Users @using Moonlight.Shared.Http.Responses @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Extras.Forms diff --git a/Moonlight.Frontend/UI/Admin/Modals/ManageRoleMembersDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/ManageRoleMembersDialog.razor index 4dc004fa..403d9c3f 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/ManageRoleMembersDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/ManageRoleMembersDialog.razor @@ -1,7 +1,7 @@ @using LucideBlazor @using Moonlight.Shared.Http.Responses @using Moonlight.Shared.Http.Responses.Admin -@using Moonlight.Shared.Http.Responses.Users +@using Moonlight.Shared.Http.Responses.Admin.Users @using ShadcnBlazor.Buttons @using ShadcnBlazor.DataGrids @using ShadcnBlazor.Dialogs diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor index b6a34e44..f9e4aef9 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateApiKeyDialog.razor @@ -1,8 +1,8 @@ @using Moonlight.Frontend.Helpers @using Moonlight.Frontend.Mappers @using Moonlight.Frontend.UI.Admin.Components -@using Moonlight.Shared.Http.Requests.ApiKeys -@using Moonlight.Shared.Http.Responses.ApiKeys +@using Moonlight.Shared.Http.Requests.Admin.ApiKeys +@using Moonlight.Shared.Http.Responses.Admin.ApiKeys @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Extras.Forms @using ShadcnBlazor.Extras.Toasts diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor index 22130a11..288d8a71 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateRoleDialog.razor @@ -1,7 +1,7 @@ @using Moonlight.Frontend.Helpers @using Moonlight.Frontend.Mappers @using Moonlight.Frontend.UI.Admin.Components -@using Moonlight.Shared.Http.Requests.Roles +@using Moonlight.Shared.Http.Requests.Admin.Roles @using Moonlight.Shared.Http.Responses.Admin @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Extras.Forms diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor index 145fa3cc..f23a2ec7 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateUserDialog.razor @@ -1,8 +1,8 @@ @using Moonlight.Frontend.Helpers @using Moonlight.Frontend.Mappers -@using Moonlight.Shared.Http.Requests.Users +@using Moonlight.Shared.Http.Requests.Admin.Users @using Moonlight.Shared.Http.Responses -@using Moonlight.Shared.Http.Responses.Users +@using Moonlight.Shared.Http.Responses.Admin.Users @using ShadcnBlazor.Dialogs @using ShadcnBlazor.Extras.Forms @using ShadcnBlazor.Extras.Toasts diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/ApiKeys.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/ApiKeys.razor index ff344fd1..9b76f917 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/ApiKeys.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/ApiKeys.razor @@ -1,12 +1,11 @@ -@using Moonlight.Shared.Http.Requests.ApiKeys -@using Moonlight.Shared.Http.Responses.ApiKeys -@using LucideBlazor +@using LucideBlazor @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @using Moonlight.Frontend.UI.Admin.Modals @using Moonlight.Shared @using Moonlight.Shared.Http.Requests @using Moonlight.Shared.Http.Responses +@using Moonlight.Shared.Http.Responses.Admin.ApiKeys @using ShadcnBlazor.DataGrids @using ShadcnBlazor.Dropdowns @using ShadcnBlazor.Extras.AlertDialogs diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor index 759eaa5d..be2711df 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Create.razor @@ -5,7 +5,7 @@ @using LucideBlazor @using Moonlight.Frontend.Helpers @using Moonlight.Frontend.Services -@using Moonlight.Shared.Http.Requests.Themes +@using Moonlight.Shared.Http.Requests.Admin.Themes @using ShadcnBlazor.Buttons @using ShadcnBlazor.Cards @using ShadcnBlazor.Extras.Editors diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Index.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Index.razor index 17208173..c90c0dfd 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Index.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Index.razor @@ -4,7 +4,7 @@ @using Moonlight.Shared @using Moonlight.Shared.Http.Requests @using Moonlight.Shared.Http.Responses -@using Moonlight.Shared.Http.Responses.Themes +@using Moonlight.Shared.Http.Responses.Admin.Themes @using ShadcnBlazor.DataGrids @using ShadcnBlazor.Dropdowns @using ShadcnBlazor.Extras.AlertDialogs diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor index bab7f725..4c19541f 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Themes/Update.razor @@ -6,8 +6,8 @@ @using Moonlight.Frontend.Helpers @using Moonlight.Frontend.Mappers @using Moonlight.Frontend.Services -@using Moonlight.Shared.Http.Requests.Themes -@using Moonlight.Shared.Http.Responses.Themes +@using Moonlight.Shared.Http.Requests.Admin.Themes +@using Moonlight.Shared.Http.Responses.Admin.Themes @using ShadcnBlazor.Buttons @using ShadcnBlazor.Cards @using ShadcnBlazor.Extras.Common diff --git a/Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor b/Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor index 195ebae1..a84bf8ba 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Users/Roles.razor @@ -4,7 +4,6 @@ @using Moonlight.Frontend.UI.Admin.Modals @using Moonlight.Shared @using Moonlight.Shared.Http.Requests -@using Moonlight.Shared.Http.Requests.Roles @using Moonlight.Shared.Http.Responses @using Moonlight.Shared.Http.Responses.Admin @using ShadcnBlazor.DataGrids diff --git a/Moonlight.Frontend/UI/Admin/Views/Users/Users.razor b/Moonlight.Frontend/UI/Admin/Views/Users/Users.razor index d7778005..c6a4e752 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Users/Users.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Users/Users.razor @@ -10,9 +10,8 @@ @using ShadcnBlazor.Extras.Toasts @using ShadcnBlazor.Tabels @using Moonlight.Shared.Http.Requests -@using Moonlight.Shared.Http.Requests.Users @using Moonlight.Shared.Http.Responses -@using Moonlight.Shared.Http.Responses.Users +@using Moonlight.Shared.Http.Responses.Admin.Users @using ShadcnBlazor.Extras.Dialogs @inject HttpClient HttpClient diff --git a/Moonlight.Frontend/UI/Shared/Components/Auth/Authentication.razor b/Moonlight.Frontend/UI/Shared/Components/Auth/Authentication.razor index 1278c182..22a2f7eb 100644 --- a/Moonlight.Frontend/UI/Shared/Components/Auth/Authentication.razor +++ b/Moonlight.Frontend/UI/Shared/Components/Auth/Authentication.razor @@ -1,7 +1,7 @@ -@using ShadcnBlazor.Cards +@using Moonlight.Shared.Http.Responses.Admin.Auth +@using ShadcnBlazor.Cards @using ShadcnBlazor.Spinners @using ShadcnBlazor.Buttons -@using Moonlight.Shared.Http.Responses.Auth @inject HttpClient HttpClient @inject NavigationManager Navigation diff --git a/Moonlight.Shared/Http/Requests/ApiKeys/CreateApiKeyDto.cs b/Moonlight.Shared/Http/Requests/Admin/ApiKeys/CreateApiKeyDto.cs similarity index 84% rename from Moonlight.Shared/Http/Requests/ApiKeys/CreateApiKeyDto.cs rename to Moonlight.Shared/Http/Requests/Admin/ApiKeys/CreateApiKeyDto.cs index 0f5e2e65..2b60a525 100644 --- a/Moonlight.Shared/Http/Requests/ApiKeys/CreateApiKeyDto.cs +++ b/Moonlight.Shared/Http/Requests/Admin/ApiKeys/CreateApiKeyDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.ApiKeys; +namespace Moonlight.Shared.Http.Requests.Admin.ApiKeys; public class CreateApiKeyDto { diff --git a/Moonlight.Shared/Http/Requests/ApiKeys/UpdateApiKeyDto.cs b/Moonlight.Shared/Http/Requests/Admin/ApiKeys/UpdateApiKeyDto.cs similarity index 83% rename from Moonlight.Shared/Http/Requests/ApiKeys/UpdateApiKeyDto.cs rename to Moonlight.Shared/Http/Requests/Admin/ApiKeys/UpdateApiKeyDto.cs index d9fcbfc2..3c154ec7 100644 --- a/Moonlight.Shared/Http/Requests/ApiKeys/UpdateApiKeyDto.cs +++ b/Moonlight.Shared/Http/Requests/Admin/ApiKeys/UpdateApiKeyDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.ApiKeys; +namespace Moonlight.Shared.Http.Requests.Admin.ApiKeys; public class UpdateApiKeyDto { diff --git a/Moonlight.Shared/Http/Requests/Roles/CreateRoleDto.cs b/Moonlight.Shared/Http/Requests/Admin/Roles/CreateRoleDto.cs similarity index 83% rename from Moonlight.Shared/Http/Requests/Roles/CreateRoleDto.cs rename to Moonlight.Shared/Http/Requests/Admin/Roles/CreateRoleDto.cs index 638673fd..6573aedd 100644 --- a/Moonlight.Shared/Http/Requests/Roles/CreateRoleDto.cs +++ b/Moonlight.Shared/Http/Requests/Admin/Roles/CreateRoleDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Roles; +namespace Moonlight.Shared.Http.Requests.Admin.Roles; public class CreateRoleDto { diff --git a/Moonlight.Shared/Http/Requests/Roles/UpdateRoleDto.cs b/Moonlight.Shared/Http/Requests/Admin/Roles/UpdateRoleDto.cs similarity index 83% rename from Moonlight.Shared/Http/Requests/Roles/UpdateRoleDto.cs rename to Moonlight.Shared/Http/Requests/Admin/Roles/UpdateRoleDto.cs index d7a03ee6..57538cc2 100644 --- a/Moonlight.Shared/Http/Requests/Roles/UpdateRoleDto.cs +++ b/Moonlight.Shared/Http/Requests/Admin/Roles/UpdateRoleDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Roles; +namespace Moonlight.Shared.Http.Requests.Admin.Roles; public class UpdateRoleDto { diff --git a/Moonlight.Shared/Http/Requests/Themes/CreateThemeDto.cs b/Moonlight.Shared/Http/Requests/Admin/Themes/CreateThemeDto.cs similarity index 88% rename from Moonlight.Shared/Http/Requests/Themes/CreateThemeDto.cs rename to Moonlight.Shared/Http/Requests/Admin/Themes/CreateThemeDto.cs index 01ebf5b0..36374de0 100644 --- a/Moonlight.Shared/Http/Requests/Themes/CreateThemeDto.cs +++ b/Moonlight.Shared/Http/Requests/Admin/Themes/CreateThemeDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Themes; +namespace Moonlight.Shared.Http.Requests.Admin.Themes; public class CreateThemeDto { diff --git a/Moonlight.Shared/Http/Requests/Themes/UpdateThemeDto.cs b/Moonlight.Shared/Http/Requests/Admin/Themes/UpdateThemeDto.cs similarity index 88% rename from Moonlight.Shared/Http/Requests/Themes/UpdateThemeDto.cs rename to Moonlight.Shared/Http/Requests/Admin/Themes/UpdateThemeDto.cs index 0d22d223..ead52a32 100644 --- a/Moonlight.Shared/Http/Requests/Themes/UpdateThemeDto.cs +++ b/Moonlight.Shared/Http/Requests/Admin/Themes/UpdateThemeDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Themes; +namespace Moonlight.Shared.Http.Requests.Admin.Themes; public class UpdateThemeDto { diff --git a/Moonlight.Shared/Http/Requests/Users/CreateUserDto.cs b/Moonlight.Shared/Http/Requests/Admin/Users/CreateUserDto.cs similarity index 81% rename from Moonlight.Shared/Http/Requests/Users/CreateUserDto.cs rename to Moonlight.Shared/Http/Requests/Admin/Users/CreateUserDto.cs index 826b7129..0c3b9d1b 100644 --- a/Moonlight.Shared/Http/Requests/Users/CreateUserDto.cs +++ b/Moonlight.Shared/Http/Requests/Admin/Users/CreateUserDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Users; +namespace Moonlight.Shared.Http.Requests.Admin.Users; public class CreateUserDto { diff --git a/Moonlight.Shared/Http/Requests/Users/UpdateUserDto.cs b/Moonlight.Shared/Http/Requests/Admin/Users/UpdateUserDto.cs similarity index 81% rename from Moonlight.Shared/Http/Requests/Users/UpdateUserDto.cs rename to Moonlight.Shared/Http/Requests/Admin/Users/UpdateUserDto.cs index c2182bc1..96b33e87 100644 --- a/Moonlight.Shared/Http/Requests/Users/UpdateUserDto.cs +++ b/Moonlight.Shared/Http/Requests/Admin/Users/UpdateUserDto.cs @@ -1,6 +1,6 @@ using System.ComponentModel.DataAnnotations; -namespace Moonlight.Shared.Http.Requests.Users; +namespace Moonlight.Shared.Http.Requests.Admin.Users; public class UpdateUserDto { diff --git a/Moonlight.Shared/Http/Responses/ApiKeys/ApiKeyDto.cs b/Moonlight.Shared/Http/Responses/Admin/ApiKeys/ApiKeyDto.cs similarity index 71% rename from Moonlight.Shared/Http/Responses/ApiKeys/ApiKeyDto.cs rename to Moonlight.Shared/Http/Responses/Admin/ApiKeys/ApiKeyDto.cs index 8561d083..85158f42 100644 --- a/Moonlight.Shared/Http/Responses/ApiKeys/ApiKeyDto.cs +++ b/Moonlight.Shared/Http/Responses/Admin/ApiKeys/ApiKeyDto.cs @@ -1,3 +1,3 @@ -namespace Moonlight.Shared.Http.Responses.ApiKeys; +namespace Moonlight.Shared.Http.Responses.Admin.ApiKeys; public record ApiKeyDto(int Id, string Name, string Description, string[] Permissions, string Key, DateTimeOffset CreatedAt, DateTimeOffset UpdatedAt); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Admin/Auth/ClaimDto.cs b/Moonlight.Shared/Http/Responses/Admin/Auth/ClaimDto.cs new file mode 100644 index 00000000..7d9ee7c1 --- /dev/null +++ b/Moonlight.Shared/Http/Responses/Admin/Auth/ClaimDto.cs @@ -0,0 +1,3 @@ +namespace Moonlight.Shared.Http.Responses.Admin.Auth; + +public record ClaimDto(string Type, string Value); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Auth/SchemeDto.cs b/Moonlight.Shared/Http/Responses/Admin/Auth/SchemeDto.cs similarity index 50% rename from Moonlight.Shared/Http/Responses/Auth/SchemeDto.cs rename to Moonlight.Shared/Http/Responses/Admin/Auth/SchemeDto.cs index bd9fa7ce..4c2218bf 100644 --- a/Moonlight.Shared/Http/Responses/Auth/SchemeDto.cs +++ b/Moonlight.Shared/Http/Responses/Admin/Auth/SchemeDto.cs @@ -1,3 +1,3 @@ -namespace Moonlight.Shared.Http.Responses.Auth; +namespace Moonlight.Shared.Http.Responses.Admin.Auth; public record SchemeDto(string Name, string DisplayName); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Frontend/FrontendConfigDto.cs b/Moonlight.Shared/Http/Responses/Admin/Frontend/FrontendConfigDto.cs similarity index 52% rename from Moonlight.Shared/Http/Responses/Frontend/FrontendConfigDto.cs rename to Moonlight.Shared/Http/Responses/Admin/Frontend/FrontendConfigDto.cs index 747e5d39..f1c7dd5a 100644 --- a/Moonlight.Shared/Http/Responses/Frontend/FrontendConfigDto.cs +++ b/Moonlight.Shared/Http/Responses/Admin/Frontend/FrontendConfigDto.cs @@ -1,3 +1,3 @@ -namespace Moonlight.Shared.Http.Responses.Frontend; +namespace Moonlight.Shared.Http.Responses.Admin.Frontend; public record FrontendConfigDto(string Name, string? ThemeCss); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Themes/ThemeDto.cs b/Moonlight.Shared/Http/Responses/Admin/Themes/ThemeDto.cs similarity index 66% rename from Moonlight.Shared/Http/Responses/Themes/ThemeDto.cs rename to Moonlight.Shared/Http/Responses/Admin/Themes/ThemeDto.cs index adc167dd..854bfd6e 100644 --- a/Moonlight.Shared/Http/Responses/Themes/ThemeDto.cs +++ b/Moonlight.Shared/Http/Responses/Admin/Themes/ThemeDto.cs @@ -1,3 +1,3 @@ -namespace Moonlight.Shared.Http.Responses.Themes; +namespace Moonlight.Shared.Http.Responses.Admin.Themes; public record ThemeDto(int Id, string Name, string Author, string Version, string CssContent, bool IsEnabled); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Users/UserDto.cs b/Moonlight.Shared/Http/Responses/Admin/Users/UserDto.cs similarity index 66% rename from Moonlight.Shared/Http/Responses/Users/UserDto.cs rename to Moonlight.Shared/Http/Responses/Admin/Users/UserDto.cs index 80a824ab..1060b50c 100644 --- a/Moonlight.Shared/Http/Responses/Users/UserDto.cs +++ b/Moonlight.Shared/Http/Responses/Admin/Users/UserDto.cs @@ -1,3 +1,3 @@ -namespace Moonlight.Shared.Http.Responses.Users; +namespace Moonlight.Shared.Http.Responses.Admin.Users; public record UserDto(int Id, string Username, string Email, DateTimeOffset CreatedAt, DateTimeOffset UpdatedAt); \ No newline at end of file diff --git a/Moonlight.Shared/Http/Responses/Auth/ClaimDto.cs b/Moonlight.Shared/Http/Responses/Auth/ClaimDto.cs deleted file mode 100644 index 0b3c73a1..00000000 --- a/Moonlight.Shared/Http/Responses/Auth/ClaimDto.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Moonlight.Shared.Http.Responses.Auth; - -public record ClaimDto(string Type, string Value); \ No newline at end of file diff --git a/Moonlight.Shared/Http/SharedSerializationContext.cs b/Moonlight.Shared/Http/SharedSerializationContext.cs index 3fa23a66..8bb4e776 100644 --- a/Moonlight.Shared/Http/SharedSerializationContext.cs +++ b/Moonlight.Shared/Http/SharedSerializationContext.cs @@ -1,16 +1,16 @@ using System.Text.Json; using System.Text.Json.Serialization; using Moonlight.Shared.Http.Events; -using Moonlight.Shared.Http.Requests.ApiKeys; -using Moonlight.Shared.Http.Requests.Roles; -using Moonlight.Shared.Http.Requests.Themes; -using Moonlight.Shared.Http.Requests.Users; +using Moonlight.Shared.Http.Requests.Admin.ApiKeys; +using Moonlight.Shared.Http.Requests.Admin.Roles; +using Moonlight.Shared.Http.Requests.Admin.Themes; +using Moonlight.Shared.Http.Requests.Admin.Users; using Moonlight.Shared.Http.Responses; using Moonlight.Shared.Http.Responses.Admin; -using Moonlight.Shared.Http.Responses.ApiKeys; -using Moonlight.Shared.Http.Responses.Auth; -using Moonlight.Shared.Http.Responses.Themes; -using Moonlight.Shared.Http.Responses.Users; +using Moonlight.Shared.Http.Responses.Admin.ApiKeys; +using Moonlight.Shared.Http.Responses.Admin.Auth; +using Moonlight.Shared.Http.Responses.Admin.Themes; +using Moonlight.Shared.Http.Responses.Admin.Users; namespace Moonlight.Shared.Http; From 660319afec9bd1a4ffb4ce043ced341fe9f00aa7 Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Thu, 29 Jan 2026 13:59:24 +0100 Subject: [PATCH 09/10] Renamed SharedSerializationContext to SerializationContext. Added error handling and no build cache functionality --- .../Admin/ContainerHelperController.cs | 5 +- .../Requests/RequestRebuildDto.cs | 3 ++ .../ContainerHelper/SerializationContext.cs | 1 + .../Services/ContainerHelperService.cs | 33 +++++++++---- Moonlight.Api/Startup/Startup.Base.cs | 2 +- Moonlight.Frontend/Constants.cs | 2 +- .../UI/Admin/Modals/UpdateInstanceModal.razor | 49 ++++++++++++++----- .../UI/Admin/Views/Sys/Instance.razor | 31 ++++++++---- .../ContainerHelper/RequestRebuildDto.cs | 15 ++++++ ...tionContext.cs => SerializationContext.cs} | 5 +- 10 files changed, 109 insertions(+), 37 deletions(-) create mode 100644 Moonlight.Api/Http/Services/ContainerHelper/Requests/RequestRebuildDto.cs create mode 100644 Moonlight.Shared/Http/Requests/Admin/ContainerHelper/RequestRebuildDto.cs rename Moonlight.Shared/Http/{SharedSerializationContext.cs => SerializationContext.cs} (91%) diff --git a/Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs b/Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs index 599351a5..7fed23c7 100644 --- a/Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs +++ b/Moonlight.Api/Http/Controllers/Admin/ContainerHelperController.cs @@ -4,6 +4,7 @@ using Microsoft.Extensions.Options; using Moonlight.Api.Configuration; using Moonlight.Api.Mappers; using Moonlight.Api.Services; +using Moonlight.Shared.Http.Events; using Moonlight.Shared.Http.Requests.Admin.ContainerHelper; using Moonlight.Shared.Http.Responses.Admin; @@ -34,9 +35,9 @@ public class ContainerHelperController : Controller } [HttpPost("rebuild")] - public Task RebuildAsync() + public Task RebuildAsync([FromBody] RequestRebuildDto request) { - var result = ContainerHelperService.RebuildAsync(); + var result = ContainerHelperService.RebuildAsync(request.NoBuildCache); var mappedResult = result.Select(ContainerHelperMapper.ToDto); return Task.FromResult( diff --git a/Moonlight.Api/Http/Services/ContainerHelper/Requests/RequestRebuildDto.cs b/Moonlight.Api/Http/Services/ContainerHelper/Requests/RequestRebuildDto.cs new file mode 100644 index 00000000..c7dda283 --- /dev/null +++ b/Moonlight.Api/Http/Services/ContainerHelper/Requests/RequestRebuildDto.cs @@ -0,0 +1,3 @@ +namespace Moonlight.Api.Http.Services.ContainerHelper.Requests; + +public record RequestRebuildDto(bool NoBuildCache); \ No newline at end of file diff --git a/Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs b/Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs index 182f44d1..371fb761 100644 --- a/Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs +++ b/Moonlight.Api/Http/Services/ContainerHelper/SerializationContext.cs @@ -8,6 +8,7 @@ namespace Moonlight.Api.Http.Services.ContainerHelper; [JsonSerializable(typeof(SetVersionDto))] [JsonSerializable(typeof(ProblemDetails))] [JsonSerializable(typeof(RebuildEventDto))] +[JsonSerializable(typeof(RequestRebuildDto))] public partial class SerializationContext : JsonSerializerContext { private static JsonSerializerOptions? InternalTunedOptions; diff --git a/Moonlight.Api/Services/ContainerHelperService.cs b/Moonlight.Api/Services/ContainerHelperService.cs index 5467fe94..434857bd 100644 --- a/Moonlight.Api/Services/ContainerHelperService.cs +++ b/Moonlight.Api/Services/ContainerHelperService.cs @@ -1,4 +1,5 @@ -using System.Net.Http.Json; +using System.Net.Http.Headers; +using System.Net.Http.Json; using System.Text.Json; using Moonlight.Api.Http.Services.ContainerHelper; using Moonlight.Api.Http.Services.ContainerHelper.Requests; @@ -32,11 +33,22 @@ public class ContainerHelperService } } - public async IAsyncEnumerable RebuildAsync() + public async IAsyncEnumerable RebuildAsync(bool noBuildCache) { var client = HttpClientFactory.CreateClient("ContainerHelper"); - var response = await client.GetAsync("api/rebuild", HttpCompletionOption.ResponseHeadersRead); + var request = new HttpRequestMessage(HttpMethod.Post, "api/rebuild"); + + request.Content = JsonContent.Create( + new RequestRebuildDto(noBuildCache), + null, + SerializationContext.TunedOptions + ); + + var response = await client.SendAsync( + request, + HttpCompletionOption.ResponseHeadersRead + ); if (!response.IsSuccessStatusCode) { @@ -90,15 +102,16 @@ public class ContainerHelperService new SetVersionDto(version), SerializationContext.TunedOptions ); - - if(response.IsSuccessStatusCode) + + if (response.IsSuccessStatusCode) return; - - var problemDetails = await response.Content.ReadFromJsonAsync(SerializationContext.TunedOptions); - - if(problemDetails == null) + + var problemDetails = + await response.Content.ReadFromJsonAsync(SerializationContext.TunedOptions); + + if (problemDetails == null) throw new HttpRequestException($"Failed to set version: {response.ReasonPhrase}"); - + throw new HttpRequestException($"Failed to set version: {problemDetails.Detail ?? problemDetails.Title}"); } } \ No newline at end of file diff --git a/Moonlight.Api/Startup/Startup.Base.cs b/Moonlight.Api/Startup/Startup.Base.cs index a40e42b3..25c97ea6 100644 --- a/Moonlight.Api/Startup/Startup.Base.cs +++ b/Moonlight.Api/Startup/Startup.Base.cs @@ -19,7 +19,7 @@ public partial class Startup { builder.Services.AddControllers().AddJsonOptions(options => { - options.JsonSerializerOptions.TypeInfoResolverChain.Add(SharedSerializationContext.Default); + options.JsonSerializerOptions.TypeInfoResolverChain.Add(SerializationContext.Default); }); builder.Logging.ClearProviders(); diff --git a/Moonlight.Frontend/Constants.cs b/Moonlight.Frontend/Constants.cs index 685cc859..5c42627f 100644 --- a/Moonlight.Frontend/Constants.cs +++ b/Moonlight.Frontend/Constants.cs @@ -18,7 +18,7 @@ public static class Constants }; // Add source generated options from shared project - InternalOptions.TypeInfoResolverChain.Add(SharedSerializationContext.Default); + InternalOptions.TypeInfoResolverChain.Add(SerializationContext.Default); return InternalOptions; } diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor index 7bbc6ffc..96668c25 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor @@ -2,6 +2,7 @@ @using System.Text.Json @using LucideBlazor +@using Moonlight.Shared.Http @using Moonlight.Shared.Http.Events @using Moonlight.Shared.Http.Requests.Admin.ContainerHelper @using ShadcnBlazor.Buttons @@ -18,13 +19,20 @@
-
+
@for (var i = 0; i < Steps.Length; i++) { if (CurrentStep == i) { -
- +
+ @if (IsFailed) + { + + } + else + { + + } @Steps[i] @@ -34,8 +42,8 @@ { if (i < CurrentStep) { -
- +
+ @Steps[i] @@ -43,8 +51,8 @@ } else { -
- +
+ @Steps[i]
} @@ -61,7 +69,7 @@
-@if (CurrentStep == Steps.Length) +@if (CurrentStep == Steps.Length || IsFailed) { @@ -77,7 +85,9 @@ else @code { [Parameter] public string Version { get; set; } - + [Parameter] public bool NoBuildCache { get; set; } + + private bool IsFailed; private int Progress; private int CurrentStep; @@ -114,15 +124,23 @@ else await HttpClient.PostAsJsonAsync("api/admin/ch/version", new SetVersionDto() { Version = Version - }); + }, SerializationContext.TunedOptions); // Starting rebuild task CurrentStep = 2; Progress = 30; await InvokeAsync(StateHasChanged); + var request = new HttpRequestMessage(HttpMethod.Post, "api/admin/ch/rebuild"); + + request.Content = JsonContent.Create( + new RequestRebuildDto(NoBuildCache), + null, + SerializationContext.TunedOptions + ); + var response = await HttpClient.SendAsync( - new HttpRequestMessage(HttpMethod.Post, "api/admin/ch/rebuild"), + request, HttpCompletionOption.ResponseHeadersRead ); @@ -176,6 +194,13 @@ else } break; + + case RebuildEventType.Failed: + + IsFailed = true; + await InvokeAsync(StateHasChanged); + + return; } await InvokeAsync(StateHasChanged); @@ -187,7 +212,7 @@ else } while (true); // Waiting for container instance to start up - + CurrentStep = 5; Progress = 90; await InvokeAsync(StateHasChanged); diff --git a/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor b/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor index 13fc0438..6f0bd3cc 100644 --- a/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor +++ b/Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor @@ -10,6 +10,7 @@ @using ShadcnBlazor.Extras.Dialogs @using ShadcnBlazor.Fields @using ShadcnBlazor.Selects +@using ShadcnBlazor.Switches @inject HttpClient HttpClient @inject DialogService DialogService @@ -30,9 +31,7 @@
- - Version - + Version / Branch + + Bypass Build Cache + + + +
@@ -110,6 +116,7 @@ { private ContainerHelperStatusDto StatusDto; private string SelectedVersion = "v2.1"; + private bool NoBuildCache; private async Task LoadAsync(LazyLoader _) { @@ -119,7 +126,11 @@ private async Task ApplyAsync() { await DialogService.LaunchAsync( - parameters => { parameters[nameof(UpdateInstanceModal.Version)] = SelectedVersion; }, + parameters => + { + parameters[nameof(UpdateInstanceModal.Version)] = SelectedVersion; + parameters[nameof(UpdateInstanceModal.NoBuildCache)] = NoBuildCache; + }, onConfigure: model => { model.ShowCloseButton = false; @@ -130,17 +141,17 @@ private async Task AskApplyAsync() { - if(string.IsNullOrWhiteSpace(SelectedVersion)) + if (string.IsNullOrWhiteSpace(SelectedVersion)) return; - + var shouldContinue = await ConfirmRiskyVersionAsync( "Moonlight Rebuild", "If you continue the moonlight instance will become unavailable during the rebuild process. This will impact users on this instance" ); - - if(!shouldContinue) + + if (!shouldContinue) return; - + if (!Regex.IsMatch(SelectedVersion, @"^v\d+(\.\d+)*b?$")) { shouldContinue = await ConfirmRiskyVersionAsync( @@ -163,7 +174,7 @@ if (!shouldContinue) return; - + await ApplyAsync(); } diff --git a/Moonlight.Shared/Http/Requests/Admin/ContainerHelper/RequestRebuildDto.cs b/Moonlight.Shared/Http/Requests/Admin/ContainerHelper/RequestRebuildDto.cs new file mode 100644 index 00000000..335f7be5 --- /dev/null +++ b/Moonlight.Shared/Http/Requests/Admin/ContainerHelper/RequestRebuildDto.cs @@ -0,0 +1,15 @@ +namespace Moonlight.Shared.Http.Requests.Admin.ContainerHelper; + +public class RequestRebuildDto +{ + public bool NoBuildCache { get; set; } + + public RequestRebuildDto() + { + } + + public RequestRebuildDto(bool noBuildCache) + { + NoBuildCache = noBuildCache; + } +} \ No newline at end of file diff --git a/Moonlight.Shared/Http/SharedSerializationContext.cs b/Moonlight.Shared/Http/SerializationContext.cs similarity index 91% rename from Moonlight.Shared/Http/SharedSerializationContext.cs rename to Moonlight.Shared/Http/SerializationContext.cs index 8bb4e776..0d5a3a22 100644 --- a/Moonlight.Shared/Http/SharedSerializationContext.cs +++ b/Moonlight.Shared/Http/SerializationContext.cs @@ -2,6 +2,7 @@ using System.Text.Json.Serialization; using Moonlight.Shared.Http.Events; using Moonlight.Shared.Http.Requests.Admin.ApiKeys; +using Moonlight.Shared.Http.Requests.Admin.ContainerHelper; using Moonlight.Shared.Http.Requests.Admin.Roles; using Moonlight.Shared.Http.Requests.Admin.Themes; using Moonlight.Shared.Http.Requests.Admin.Users; @@ -51,10 +52,12 @@ namespace Moonlight.Shared.Http; // Container Helper [JsonSerializable(typeof(ContainerHelperStatusDto))] +[JsonSerializable(typeof(RequestRebuildDto))] +[JsonSerializable(typeof(SetVersionDto))] // Misc [JsonSerializable(typeof(ProblemDetails))] -public partial class SharedSerializationContext : JsonSerializerContext +public partial class SerializationContext : JsonSerializerContext { private static JsonSerializerOptions? InternalTunedOptions; From 09b11cc4ad3570d8890749594bfb07e25436a0f1 Mon Sep 17 00:00:00 2001 From: ChiaraBm Date: Thu, 29 Jan 2026 14:07:02 +0100 Subject: [PATCH 10/10] Improved update instance model text design --- Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor index 96668c25..8a79aa15 100644 --- a/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor +++ b/Moonlight.Frontend/UI/Admin/Modals/UpdateInstanceModal.razor @@ -42,7 +42,7 @@ { if (i < CurrentStep) { -
+
@Steps[i]