Merge pull request #168 from Moonlight-Panel/AddServerArchive

Added archive system. Added ml debug menu and related stuff
This commit is contained in:
Marcel Baumgartner 2023-06-16 17:21:05 +02:00 committed by GitHub
commit 0e04942111
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 1868 additions and 14 deletions

View file

@ -13,6 +13,8 @@ public class Server
public string OverrideStartup { get; set; } = "";
public bool Installing { get; set; } = false;
public bool Suspended { get; set; } = false;
public bool IsArchived { get; set; } = false;
public ServerBackup? Archive { get; set; } = null;
public List<ServerVariable> Variables { get; set; } = new();
public List<ServerBackup> Backups { get; set; } = new();

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,59 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.App.Database.Migrations
{
/// <inheritdoc />
public partial class AddedServerAchive : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "ArchiveId",
table: "Servers",
type: "int",
nullable: true);
migrationBuilder.AddColumn<bool>(
name: "IsArchived",
table: "Servers",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
migrationBuilder.CreateIndex(
name: "IX_Servers_ArchiveId",
table: "Servers",
column: "ArchiveId");
migrationBuilder.AddForeignKey(
name: "FK_Servers_ServerBackups_ArchiveId",
table: "Servers",
column: "ArchiveId",
principalTable: "ServerBackups",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Servers_ServerBackups_ArchiveId",
table: "Servers");
migrationBuilder.DropIndex(
name: "IX_Servers_ArchiveId",
table: "Servers");
migrationBuilder.DropColumn(
name: "ArchiveId",
table: "Servers");
migrationBuilder.DropColumn(
name: "IsArchived",
table: "Servers");
}
}
}

View file

@ -496,6 +496,9 @@ namespace Moonlight.App.Database.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<int?>("ArchiveId")
.HasColumnType("int");
b.Property<int>("Cpu")
.HasColumnType("int");
@ -511,6 +514,9 @@ namespace Moonlight.App.Database.Migrations
b.Property<bool>("Installing")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsArchived")
.HasColumnType("tinyint(1)");
b.Property<bool>("IsCleanupException")
.HasColumnType("tinyint(1)");
@ -542,6 +548,8 @@ namespace Moonlight.App.Database.Migrations
b.HasKey("Id");
b.HasIndex("ArchiveId");
b.HasIndex("ImageId");
b.HasIndex("MainAllocationId");
@ -935,6 +943,10 @@ namespace Moonlight.App.Database.Migrations
modelBuilder.Entity("Moonlight.App.Database.Entities.Server", b =>
{
b.HasOne("Moonlight.App.Database.Entities.ServerBackup", "Archive")
.WithMany()
.HasForeignKey("ArchiveId");
b.HasOne("Moonlight.App.Database.Entities.Image", "Image")
.WithMany()
.HasForeignKey("ImageId")
@ -957,6 +969,8 @@ namespace Moonlight.App.Database.Migrations
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Archive");
b.Navigation("Image");
b.Navigation("MainAllocation");

View file

@ -112,4 +112,22 @@ public class EventSystem
return Task.CompletedTask;
}
public Task<T> WaitForEvent<T>(string id, object handle, Func<T, bool> filter)
{
var taskCompletionSource = new TaskCompletionSource<T>();
Func<T, Task> action = async data =>
{
if (filter.Invoke(data))
{
taskCompletionSource.SetResult(data);
await Off(id, handle);
}
};
On<T>(id, handle, action);
return taskCompletionSource.Task;
}
}

View file

@ -0,0 +1,8 @@
namespace Moonlight.App.Models.Forms;
public class ServerImageDataModel
{
public string OverrideStartup { get; set; }
public int DockerImageIndex { get; set; }
}

View file

@ -0,0 +1,14 @@
using System.ComponentModel.DataAnnotations;
using Moonlight.App.Database.Entities;
namespace Moonlight.App.Models.Forms;
public class ServerOverviewDataModel
{
[Required(ErrorMessage = "You need to enter a name")]
[MaxLength(32, ErrorMessage = "The name cannot be longer that 32 characters")]
public string Name { get; set; }
[Required(ErrorMessage = "You need to specify a owner")]
public User Owner { get; set; }
}

View file

@ -0,0 +1,15 @@
using System.ComponentModel.DataAnnotations;
namespace Moonlight.App.Models.Forms;
public class ServerResourcesDataModel
{
[Required(ErrorMessage = "You need to specify the cpu cores")]
public int Cpu { get; set; }
[Required(ErrorMessage = "You need to specify the memory")]
public long Memory { get; set; }
[Required(ErrorMessage = "You need to specify the disk")]
public long Disk { get; set; }
}

View file

@ -72,7 +72,7 @@ public class NodeService
{
try
{
await GetSystemMetrics(node);
await GetStatus(node);
return true;
}

View file

@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore;
using Logging.Net;
using Microsoft.EntityFrameworkCore;
using Moonlight.App.ApiClients.Wings;
using Moonlight.App.ApiClients.Wings.Requests;
using Moonlight.App.ApiClients.Wings.Resources;
@ -446,4 +447,65 @@ public class ServerService
return await NodeService.IsHostUp(server.Node);
}
public async Task ArchiveServer(Server server)
{
if (server.IsArchived)
throw new DisplayException("Unable to archive an already archived server");
// Archive server
var backup = await CreateBackup(server);
server.IsArchived = true;
server.Archive = backup;
ServerRepository.Update(server);
await Event.WaitForEvent<ServerBackup>("wings.backups.create", this, x => backup.Id == x.Id);
// Reset server
var access = await CreateFileAccess(server, null!);
var files = await access.Ls();
foreach (var file in files)
{
try
{
await access.Delete(file);
}
catch (Exception)
{
// ignored
}
}
await Event.Emit($"server.{server.Uuid}.archiveStatusChanged", server);
}
public async Task UnArchiveServer(Server s)
{
if (!s.IsArchived)
throw new DisplayException("Unable to unarchive a server which is not archived");
var server = ServerRepository
.Get()
.Include(x => x.Archive)
.First(x => x.Id == s.Id);
if (server.Archive == null)
throw new DisplayException("Archive from server not found");
if (!server.Archive.Created)
throw new DisplayException("Creating the server archive is in progress");
await RestoreBackup(server, server.Archive);
await Event.WaitForEvent<ServerBackup>("wings.backups.restore", this,
x => x.Id == server.Archive.Id);
server.IsArchived = false;
ServerRepository.Update(server);
await Event.Emit($"server.{server.Uuid}.archiveStatusChanged", server);
}
}

View file

@ -0,0 +1,51 @@
@using Moonlight.App.Database.Entities
<div class="card mb-5 mb-xl-10">
<div class="card-body pt-0 pb-0">
<ul class="nav nav-stretch nav-line-tabs nav-line-tabs-2x border-transparent fs-5 fw-bold">
<li class="nav-item mt-2">
<a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 0 ? "active" : "")" href="/admin/servers/view/@(Server.Id)">
<TL>Overview</TL>
</a>
</li>
<li class="nav-item mt-2">
<a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 1 ? "active" : "")" href="/admin/servers/view/@(Server.Id)/image">
<TL>Image</TL>
</a>
</li>
<li class="nav-item mt-2">
<a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 2 ? "active" : "")" href="/admin/servers/view/@(Server.Id)/resources">
<TL>Resources</TL>
</a>
</li>
<li class="nav-item mt-2">
<a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 3 ? "active" : "")" href="/admin/servers/view/@(Server.Id)/allocations">
<TL>Allocations</TL>
</a>
</li>
<li class="nav-item mt-2">
<a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 4 ? "active" : "")" href="/admin/servers/view/@(Server.Id)/archive">
<TL>Archive</TL>
</a>
</li>
<li class="nav-item mt-2">
<a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 5 ? "active" : "")" href="/admin/servers/view/@(Server.Id)/debug">
<TL>Debug</TL>
</a>
</li>
<li class="nav-item mt-2">
<a class="nav-link text-active-primary ms-0 me-10 py-5 @(Index == 6 ? "active" : "")" href="/admin/servers/view/@(Server.Id)/delete">
<TL>Delete</TL>
</a>
</li>
</ul>
</div>
</div>
@code
{
[Parameter]
public int Index { get; set; }
[Parameter]
public Server Server { get; set; }
}

View file

@ -0,0 +1,20 @@
@{
var route = "/" + (Router.Route ?? "");
}
@if (route == Path)
{
@ChildContent
}
@code
{
[CascadingParameter]
public SmartRouter Router { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
[Parameter]
public string Path { get; set; }
}

View file

@ -0,0 +1,12 @@
<CascadingValue TValue="SmartRouter" Value="@this">
@ChildContent
</CascadingValue>
@code
{
[Parameter]
public string? Route { get; set; }
[Parameter]
public RenderFragment ChildContent { get; set; }
}

View file

@ -57,7 +57,7 @@
<span class="ms-1 text-muted">
@if (User.Admin)
{
<a href="/admin/servers/edit/@(CurrentServer.Id)">@(CurrentServer.Id)</a>
<a href="/admin/servers/view/@(CurrentServer.Id)">@(CurrentServer.Id)</a>
}
else
{

View file

@ -1,4 +1,4 @@
@page "/admin/servers/edit/{id:int}"
@page "/admin/servers/editx/{id:int}"
@using Moonlight.App.Services
@using Moonlight.App.Repositories.Servers

View file

@ -44,7 +44,7 @@
</Column>
<Column TableItem="Server" Title="" Field="@(x => x.Id)" Sortable="false" Filterable="false">
<Template>
<a href="/admin/servers/edit/@(context.Id)">
<a href="/admin/servers/view/@(context.Id)">
@(SmartTranslateService.Translate("Manage"))
</a>
</Template>

View file

@ -0,0 +1,68 @@
@using Moonlight.App.Database.Entities
@using Moonlight.App.Services
@using Moonlight.App.Services.Interop
@inject ServerService ServerService
@inject SmartTranslateService SmartTranslateService
@inject AlertService AlertService
<div class="card">
<div class="card-body">
@if (Server.IsArchived)
{
<span class="fs-5 text-warning"><TL>Server is currently archived</TL></span>
}
else
{
<span class="fs-5"><TL>Server is currently not archived</TL></span>
}
</div>
<div class="card-footer">
<div class="text-end">
@if (Server.IsArchived)
{
<WButton Text="@(SmartTranslateService.Translate("Unarchive"))"
WorkingText="@(SmartTranslateService.Translate("Unarchiving"))"
CssClasses="btn-success"
OnClick="UnArchiveServer">
</WButton>
}
else
{
<WButton Text="@(SmartTranslateService.Translate("Archive"))"
WorkingText="@(SmartTranslateService.Translate("Archiving"))"
CssClasses="btn-danger"
OnClick="ArchiveServer">
</WButton>
}
</div>
</div>
</div>
@code
{
[CascadingParameter]
public Server Server { get; set; }
private async Task ArchiveServer()
{
await ServerService.ArchiveServer(Server);
await InvokeAsync(StateHasChanged);
await AlertService.Success(
SmartTranslateService.Translate("Successfully archived the server")
);
}
private async Task UnArchiveServer()
{
await ServerService.UnArchiveServer(Server);
await InvokeAsync(StateHasChanged);
await AlertService.Success(
SmartTranslateService.Translate("Successfully unarchived the server")
);
}
}

View file

@ -0,0 +1,31 @@
@using Moonlight.App.Database.Entities
@using Moonlight.App.Services
@inject ServerService ServerService
@inject SmartTranslateService SmartTranslateService
<div class="card">
<div class="card-header">
<span class="card-title">
<TL>Reinstall</TL>
</span>
</div>
<div class="card-footer">
<WButton Text="@(SmartTranslateService.Translate("Reinstall"))"
WorkingText="@(SmartTranslateService.Translate("Reinstalling"))"
CssClasses="btn-warning"
OnClick="Reinstall">
</WButton>
</div>
</div>
@code
{
[CascadingParameter]
public Server Server { get; set; }
private async Task Reinstall()
{
await ServerService.Reinstall(Server!);
}
}

View file

@ -0,0 +1,111 @@
@using Moonlight.App.Database.Entities
@using Moonlight.App.Repositories
@using Microsoft.EntityFrameworkCore
@using Moonlight.App.Models.Forms
@using Mappy.Net
@using Moonlight.App.Services
@using Moonlight.App.Services.Interop
@inject Repository<Moonlight.App.Database.Entities.Image> ImageRepository
@inject Repository<Server> ServerRepository
@inject SmartTranslateService SmartTranslateService
@inject ToastService ToastService
<LazyLoader Load="Load">
<SmartForm Model="Model" OnValidSubmit="OnValidSubmit">
<div class="card">
<div class="card-body p-10">
<label class="form-label">
<TL>Override startup command</TL>
</label>
<div class="input-group mb-5">
<span class="input-group-text">
<i class="bx bx-terminal"></i>
</span>
<InputText @bind-Value="Model.OverrideStartup" type="text" class="form-control" placeholder="@(Server.Image.Startup)"></InputText>
</div>
<label class="form-label">
<TL>Docker image</TL>
</label>
<select @bind="Model.DockerImageIndex" class="form-select">
@foreach (var image in DockerImages)
{
<option value="@(DockerImages.IndexOf(image))">@(image.Name)</option>
}
</select>
</div>
<div class="card-body">
@foreach (var vars in Server.Variables.Chunk(4))
{
<div class="row mb-3">
@foreach (var variable in vars)
{
<div class="col">
<div class="card card-body">
<label class="form-label">
<TL>Name</TL>
</label>
<div class="input-group mb-5">
<input @bind="variable.Key" type="text" class="form-control disabled" disabled="">
</div>
<label class="form-label">
<TL>Value</TL>
</label>
<div class="input-group mb-5">
<input @bind="variable.Value" type="text" class="form-control">
</div>
</div>
</div>
}
</div>
}
</div>
<div class="card-footer">
<div class="text-end">
<button type="submit" class="btn btn-success">
<TL>Save changes</TL>
</button>
</div>
</div>
</div>
</SmartForm>
</LazyLoader>
@code
{
[CascadingParameter]
public Server Server { get; set; }
private List<DockerImage> DockerImages;
private List<Moonlight.App.Database.Entities.Image> Images;
private ServerImageDataModel Model;
private Task Load(LazyLoader arg)
{
Images = ImageRepository
.Get()
.Include(x => x.Variables)
.Include(x => x.DockerImages)
.ToList();
DockerImages = Images
.First(x => x.Id == Server.Image.Id).DockerImages
.ToList();
Model = Mapper.Map<ServerImageDataModel>(Server);
return Task.CompletedTask;
}
private async Task OnValidSubmit()
{
Server = Mapper.Map(Server, Model);
ServerRepository.Update(Server);
await ToastService.Success(
SmartTranslateService.Translate("Successfully saved changes")
);
}
}

View file

@ -0,0 +1,79 @@
@page "/admin/servers/view/{Id:int}/{Route?}"
@using Moonlight.App.Repositories
@using Moonlight.App.Database.Entities
@using Microsoft.EntityFrameworkCore
@using Moonlight.Shared.Components.Navigations
@inject Repository<Server> ServerRepository
<OnlyAdmin>
<LazyLoader @ref="LazyLoader" Load="Load">
@if (Server == null)
{
<div class="alert alert-danger">
<TL>No server with this id found</TL>
</div>
}
else
{
<CascadingValue TValue="Server" Value="Server">
<SmartRouter Route="@Route">
<Route Path="/">
<AdminServersViewNavigation Index="0" Server="Server"/>
<Overview/>
</Route>
<Route Path="/image">
<AdminServersViewNavigation Index="1" Server="Server"/>
<Image/>
</Route>
<Route Path="/resources">
<AdminServersViewNavigation Index="2" Server="Server"/>
<Resources/>
</Route>
<Route Path="/allocations">
<AdminServersViewNavigation Index="3" Server="Server"/>
</Route>
<Route Path="/archive">
<AdminServersViewNavigation Index="4" Server="Server"/>
<Archive/>
</Route>
<Route Path="/debug">
<AdminServersViewNavigation Index="5" Server="Server"/>
<Debug/>
</Route>
<Route Path="/delete">
<AdminServersViewNavigation Index="6" Server="Server"/>
</Route>
</SmartRouter>
</CascadingValue>
}
</LazyLoader>
</OnlyAdmin>
@code
{
[Parameter]
public string? Route { get; set; }
[Parameter]
public int Id { get; set; }
private LazyLoader LazyLoader;
private Server? Server;
private Task Load(LazyLoader arg)
{
Server = ServerRepository
.Get()
.Include(x => x.Image)
.Include(x => x.Owner)
.Include(x => x.Archive)
.Include(x => x.Allocations)
.Include(x => x.MainAllocation)
.Include(x => x.Variables)
.FirstOrDefault(x => x.Id == Id);
return Task.CompletedTask;
}
}

View file

@ -0,0 +1,91 @@
@using Moonlight.App.Repositories
@using Moonlight.App.Database.Entities
@using Moonlight.App.Models.Forms
@using Moonlight.App.Services
@using Moonlight.App.Services.Interop
@using Mappy.Net
@inject Repository<User> UserRepository
@inject Repository<Server> ServerRepository
@inject ToastService ToastService
@inject SmartTranslateService SmartTranslateService
<LazyLoader Load="Load">
<SmartForm Model="Model" OnValidSubmit="OnValidSubmit">
<div class="card">
<div class="card-body p-10">
<label class="form-label">
<TL>Identifier</TL>
</label>
<div class="input-group mb-5">
<span class="input-group-text">
<i class="bx bx-id-card"></i>
</span>
<input type="number" class="form-control disabled" disabled="" value="@(Server.Id)">
</div>
<label class="form-label">
<TL>UuidIdentifier</TL>
</label>
<div class="input-group mb-5">
<span class="input-group-text">
<i class="bx bx-id-card"></i>
</span>
<input type="text" class="form-control disabled" disabled="" value="@(Server.Uuid)">
</div>
<label class="form-label">
<TL>Server name</TL>
</label>
<div class="input-group mb-5">
<span class="input-group-text">
<i class="bx bx-purchase-tag-alt"></i>
</span>
<InputText @bind-Value="Model.Name" type="text" class="form-control" placeholder="@(SmartTranslateService.Translate("Server name"))"></InputText>
</div>
<label class="form-label">
<TL>Owner</TL>
</label>
<div class="input-group mb-5">
<SmartDropdown T="User"
@bind-Value="Model.Owner"
Items="Users"
DisplayFunc="@(x => x.Email)"
SearchProp="@(x => x.Email)">
</SmartDropdown>
</div>
</div>
<div class="card-footer">
<div class="text-end">
<button type="submit" class="btn btn-success"><TL>Save changes</TL></button>
</div>
</div>
</div>
</SmartForm>
</LazyLoader>
@code
{
[CascadingParameter]
public Server Server { get; set; }
private ServerOverviewDataModel Model;
private User[] Users;
private Task Load(LazyLoader arg)
{
Users = UserRepository.Get().ToArray();
Model = Mapper.Map<ServerOverviewDataModel>(Server);
return Task.CompletedTask;
}
private async Task OnValidSubmit()
{
Server = Mapper.Map(Server, Model);
ServerRepository.Update(Server);
await ToastService.Success(
SmartTranslateService.Translate("Successfully saved changes")
);
}
}

View file

@ -0,0 +1,88 @@
@using Moonlight.App.Database.Entities
@using Moonlight.App.Models.Forms
@using Moonlight.App.Repositories
@using Moonlight.App.Services
@using Moonlight.App.Services.Interop
@using Mappy.Net
@inject Repository<Server> ServerRepository
@inject SmartTranslateService SmartTranslateService
@inject ToastService ToastService
<LazyLoader Load="Load">
<SmartForm Model="Model" OnValidSubmit="OnValidSubmit">
<div class="card">
<div class="card-body p-10">
<label class="form-label">
<TL>Cpu cores</TL>
</label>
<div class="input-group mb-5">
<span class="input-group-text">
<i class="bx bx-chip"></i>
</span>
<InputNumber @bind-Value="Model.Cpu" type="number" class="form-control"></InputNumber>
<span class="input-group-text">
<TL>CPU Cores (100% = 1 Core)</TL>
</span>
</div>
<label class="form-label">
<TL>Memory</TL>
</label>
<div class="input-group mb-5">
<span class="input-group-text">
<i class="bx bx-microchip"></i>
</span>
<InputNumber @bind-Value="Model.Memory" type="number" class="form-control"></InputNumber>
<span class="input-group-text">
MB
</span>
</div>
<label class="form-label">
<TL>Disk</TL>
</label>
<div class="input-group mb-5">
<span class="input-group-text">
<i class="bx bx-hdd"></i>
</span>
<InputNumber @bind-Value="Model.Disk" type="number" class="form-control"></InputNumber>
<span class="input-group-text">
MB
</span>
</div>
</div>
<div class="card-footer">
<div class="text-end">
<button type="submit" class="btn btn-success">
<TL>Save changes</TL>
</button>
</div>
</div>
</div>
</SmartForm>
</LazyLoader>
@code
{
[CascadingParameter]
public Server Server { get; set; }
private ServerResourcesDataModel Model;
private Task Load(LazyLoader arg)
{
Model = Mapper.Map<ServerResourcesDataModel>(Server);
return Task.CompletedTask;
}
private async Task OnValidSubmit()
{
Server = Mapper.Map(Server, Model);
ServerRepository.Update(Server);
await ToastService.Success(
SmartTranslateService.Translate("Successfully saved changes")
);
}
}

View file

@ -22,6 +22,7 @@
@inject ServerService ServerService
@inject NavigationManager NavigationManager
@inject DynamicBackgroundService DynamicBackgroundService
@inject SmartTranslateService SmartTranslateService
@implements IDisposable
@ -78,6 +79,28 @@
</div>
</div>
}
else if (CurrentServer.IsArchived)
{
<div class="d-flex justify-content-center flex-center">
<div class="card">
<img src="/assets/media/svg/archive.svg" class="card-img-top w-50 mx-auto pt-5" alt="Not found image"/>
<div class="card-body text-center">
<h1 class="card-title">
<TL>Server is currently archived</TL>
</h1>
<p class="card-text fs-4">
<TL>This server is archived. The data of this server is stored as a backup. To restore click the unarchive button an be patient</TL>
</p>
<WButton Text="@(SmartTranslateService.Translate("Unarchive"))"
WorkingText="@(SmartTranslateService.Translate("Please wait"))"
CssClasses="btn-primary"
OnClick="UnArchive">
</WButton>
</div>
</div>
</div>
}
else
{
<CascadingValue Value="Console">
@ -236,7 +259,7 @@
}
catch (Exception)
{
// ignored
// ignored
}
if (CurrentServer != null)
@ -260,8 +283,8 @@
.Include(x => x.Variables)
.First(x => x.Id == CurrentServer.Image.Id);
// Live variable migration
// Live variable migration
foreach (var variable in image.Variables)
{
if (!CurrentServer.Variables.Any(x => x.Key == variable.Key))
@ -271,13 +294,13 @@
Key = variable.Key,
Value = variable.DefaultValue
});
ServerRepository.Update(CurrentServer);
}
}
// Tags
// Tags
await lazyLoader.SetText("Requesting tags");
Tags = JsonConvert.DeserializeObject<string[]>(image.TagsJson) ?? Array.Empty<string>();
@ -294,6 +317,13 @@
return Task.CompletedTask;
});
await Event.On<Server>($"server.{CurrentServer.Uuid}.archiveStatusChanged", this, server =>
{
NavigationManager.NavigateTo(NavigationManager.Uri, true);
return Task.CompletedTask;
});
if (string.IsNullOrEmpty(Image.BackgroundImageUrl))
await DynamicBackgroundService.Reset();
else
@ -305,7 +335,7 @@
Logger.Debug("Server is null");
}
}
private async Task ReconnectConsole()
{
await Console!.Disconnect();
@ -317,6 +347,7 @@
if (CurrentServer != null)
{
await Event.Off($"server.{CurrentServer.Uuid}.installComplete", this);
await Event.Off($"server.{CurrentServer.Uuid}.archiveStatusChanged", this);
}
if (Console != null)
@ -324,4 +355,9 @@
Console.Dispose();
}
}
private async Task UnArchive()
{
await ServerService.UnArchiveServer(CurrentServer!);
}
}

View file

@ -11,4 +11,5 @@
@using Moonlight.Shared.Components.StateLogic
@using Moonlight.Shared.Components.Alerts
@using Moonlight.Shared.Components.Forms
@using Moonlight.Shared.Components.Partials
@using Moonlight.Shared.Components.Partials
@using Moonlight.Shared.Components.Router

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.3 KiB