Implemented container helper status checked. Started implementing container helper ui. Improved update modal
This commit is contained in:
@@ -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<ContainerHelperOptions> Options;
|
||||
|
||||
public ChController(ContainerHelperService containerHelperService)
|
||||
public ChController(ContainerHelperService containerHelperService, IOptions<ContainerHelperOptions> options)
|
||||
{
|
||||
ContainerHelperService = containerHelperService;
|
||||
Options = options;
|
||||
}
|
||||
|
||||
[HttpGet("status")]
|
||||
public async Task<ActionResult<ContainerHelperStatusDto>> GetStatusAsync()
|
||||
{
|
||||
if (!Options.Value.IsEnabled)
|
||||
return new ContainerHelperStatusDto(false, false);
|
||||
|
||||
var status = await ContainerHelperService.CheckConnectionAsync();
|
||||
|
||||
return new ContainerHelperStatusDto(true, status);
|
||||
}
|
||||
|
||||
[HttpPost("rebuild")]
|
||||
|
||||
@@ -13,6 +13,23 @@ public class ContainerHelperService
|
||||
HttpClientFactory = httpClientFactory;
|
||||
}
|
||||
|
||||
public async Task<bool> 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<RebuildEvent> 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<RebuildEvent>(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()
|
||||
|
||||
@@ -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
|
||||
|
||||
<DialogHeader>
|
||||
@@ -62,46 +60,57 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<DialogFooter>
|
||||
<Progress Value="@Progress"></Progress>
|
||||
@if (CurrentStep == Steps.Length)
|
||||
{
|
||||
<DialogFooter ClassName="justify-end">
|
||||
<Button Variant="ButtonVariant.Outline" @onclick="CloseAsync">Close</Button>
|
||||
</DialogFooter>
|
||||
}
|
||||
else
|
||||
{
|
||||
<DialogFooter>
|
||||
<Progress ClassName="my-1" Value="@Progress"></Progress>
|
||||
</DialogFooter>
|
||||
}
|
||||
|
||||
@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<string?> LogLines = new();
|
||||
private readonly List<string?> 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)
|
||||
{
|
||||
@@ -190,17 +205,9 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
<HeartPulseIcon/>
|
||||
Diagnose
|
||||
</TabsTrigger>
|
||||
<TabsTrigger Value="instance">
|
||||
<ContainerIcon/>
|
||||
Instance
|
||||
</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent Value="settings">
|
||||
<Card ClassName="mt-5">
|
||||
@@ -65,6 +69,9 @@
|
||||
<Moonlight.Frontend.UI.Admin.Views.Sys.Themes.Index />
|
||||
</TabsContent>
|
||||
}
|
||||
<TabsContent Value="instance">
|
||||
<Instance />
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
|
||||
@code
|
||||
|
||||
56
Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor
Normal file
56
Moonlight.Frontend/UI/Admin/Views/Sys/Instance.razor
Normal file
@@ -0,0 +1,56 @@
|
||||
@using LucideBlazor
|
||||
@using Moonlight.Shared.Http.Responses.Admin
|
||||
@using ShadcnBlazor.Emptys
|
||||
@using ShadcnBlazor.Extras.Common
|
||||
|
||||
@inject HttpClient HttpClient
|
||||
|
||||
<div class="mt-5">
|
||||
<LazyLoader Load="LoadAsync">
|
||||
@if (StatusDto.IsEnabled)
|
||||
{
|
||||
if (StatusDto.IsReachable)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
<Empty>
|
||||
<EmptyHeader>
|
||||
<EmptyMedia Variant="EmptyMediaVariant.Icon">
|
||||
<CircleAlertIcon ClassName="text-red-500"/>
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>Container Helper unreachable</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
The container helper is unreachable. No management actions are available
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
</Empty>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
<Empty>
|
||||
<EmptyHeader>
|
||||
<EmptyMedia Variant="EmptyMediaVariant.Icon">
|
||||
<ToggleLeftIcon/>
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>Container Helper is disabled</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
The container helper is disabled on this instance.
|
||||
This might be due to running a multiple container moonlight setup
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
</Empty>
|
||||
}
|
||||
</LazyLoader>
|
||||
</div>
|
||||
|
||||
@code
|
||||
{
|
||||
private ContainerHelperStatusDto StatusDto;
|
||||
|
||||
private async Task LoadAsync(LazyLoader _)
|
||||
{
|
||||
StatusDto = (await HttpClient.GetFromJsonAsync<ContainerHelperStatusDto>("api/admin/ch/status"))!;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
namespace Moonlight.Shared.Http.Responses.Admin;
|
||||
|
||||
public record ContainerHelperStatusDto(bool IsEnabled, bool IsReachable);
|
||||
@@ -47,6 +47,9 @@ namespace Moonlight.Shared.Http;
|
||||
|
||||
// Events
|
||||
[JsonSerializable(typeof(RebuildEvent))]
|
||||
|
||||
// Container Helper
|
||||
[JsonSerializable(typeof(ContainerHelperStatusDto))]
|
||||
public partial class SerializationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user