Implemented server list and power state display
This commit is contained in:
@@ -0,0 +1,20 @@
|
|||||||
|
using MoonlightServers.DaemonShared.Enums;
|
||||||
|
using MoonlightServers.Shared.Enums;
|
||||||
|
|
||||||
|
namespace MoonlightServers.ApiServer.Extensions;
|
||||||
|
|
||||||
|
public static class ServerStateExtensions
|
||||||
|
{
|
||||||
|
public static ServerPowerState ToServerPowerState(this ServerState state)
|
||||||
|
{
|
||||||
|
return state switch
|
||||||
|
{
|
||||||
|
ServerState.Installing => ServerPowerState.Installing,
|
||||||
|
ServerState.Stopping => ServerPowerState.Stopping,
|
||||||
|
ServerState.Online => ServerPowerState.Online,
|
||||||
|
ServerState.Starting => ServerPowerState.Starting,
|
||||||
|
ServerState.Offline => ServerPowerState.Offline,
|
||||||
|
_ => ServerPowerState.Offline
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,9 +9,7 @@ using MoonCore.Models;
|
|||||||
using Moonlight.ApiServer.Database.Entities;
|
using Moonlight.ApiServer.Database.Entities;
|
||||||
using MoonlightServers.ApiServer.Database.Entities;
|
using MoonlightServers.ApiServer.Database.Entities;
|
||||||
using MoonlightServers.Shared.Http.Requests.Admin.Servers;
|
using MoonlightServers.Shared.Http.Requests.Admin.Servers;
|
||||||
using MoonlightServers.Shared.Http.Responses.Admin.NodeAllocations;
|
|
||||||
using MoonlightServers.Shared.Http.Responses.Admin.Servers;
|
using MoonlightServers.Shared.Http.Responses.Admin.Servers;
|
||||||
using MoonlightServers.Shared.Http.Responses.Admin.ServerVariables;
|
|
||||||
|
|
||||||
namespace MoonlightServers.ApiServer.Http.Controllers.Admin.Servers;
|
namespace MoonlightServers.ApiServer.Http.Controllers.Admin.Servers;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using MoonCore.Attributes;
|
||||||
|
using MoonCore.Exceptions;
|
||||||
|
using MoonCore.Extended.Abstractions;
|
||||||
|
using MoonCore.Extensions;
|
||||||
|
using MoonCore.Models;
|
||||||
|
using Moonlight.ApiServer.Database.Entities;
|
||||||
|
using MoonlightServers.ApiServer.Database.Entities;
|
||||||
|
using MoonlightServers.ApiServer.Extensions;
|
||||||
|
using MoonlightServers.ApiServer.Services;
|
||||||
|
using MoonlightServers.Shared.Http.Responses.User.Allocations;
|
||||||
|
using MoonlightServers.Shared.Http.Responses.Users.Servers;
|
||||||
|
|
||||||
|
namespace MoonlightServers.ApiServer.Http.Controllers.Users;
|
||||||
|
|
||||||
|
[ApiController]
|
||||||
|
[Route("api/servers")]
|
||||||
|
public class ServersController : Controller
|
||||||
|
{
|
||||||
|
private readonly DatabaseRepository<Server> ServerRepository;
|
||||||
|
private readonly NodeService NodeService;
|
||||||
|
|
||||||
|
public ServersController(DatabaseRepository<Server> serverRepository, NodeService nodeService)
|
||||||
|
{
|
||||||
|
ServerRepository = serverRepository;
|
||||||
|
NodeService = nodeService;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("list")]
|
||||||
|
[RequirePermission("meta.authenticated")]
|
||||||
|
public async Task<PagedData<ServerDetailResponse>> List([FromQuery] int page, [FromQuery] int pageSize)
|
||||||
|
{
|
||||||
|
var user = User.AsIdentity<User>();
|
||||||
|
|
||||||
|
var query = ServerRepository
|
||||||
|
.Get()
|
||||||
|
.Include(x => x.Allocations)
|
||||||
|
.Include(x => x.Star)
|
||||||
|
.Include(x => x.Node)
|
||||||
|
.Where(x => x.OwnerId == user.Id);
|
||||||
|
|
||||||
|
var count = await query.CountAsync();
|
||||||
|
var items = await query.Skip(page * pageSize).Take(pageSize).ToArrayAsync();
|
||||||
|
|
||||||
|
var mappedItems = items.Select(x => new ServerDetailResponse()
|
||||||
|
{
|
||||||
|
Id = x.Id,
|
||||||
|
Name = x.Name,
|
||||||
|
NodeName = x.Node.Name,
|
||||||
|
StarName = x.Star.Name,
|
||||||
|
Allocations = x.Allocations.Select(y => new AllocationDetailResponse()
|
||||||
|
{
|
||||||
|
Id = y.Id,
|
||||||
|
Port = y.Port,
|
||||||
|
IpAddress = y.IpAddress
|
||||||
|
}).ToArray()
|
||||||
|
}).ToArray();
|
||||||
|
|
||||||
|
return new PagedData<ServerDetailResponse>()
|
||||||
|
{
|
||||||
|
Items = mappedItems,
|
||||||
|
CurrentPage = page,
|
||||||
|
PageSize = pageSize,
|
||||||
|
TotalItems = count,
|
||||||
|
TotalPages = count == 0 ? 0 : count / pageSize
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet("{serverId:int}/status")]
|
||||||
|
[RequirePermission("meta.authenticated")]
|
||||||
|
public async Task<ServerStatusResponse> GetStatus([FromRoute] int serverId)
|
||||||
|
{
|
||||||
|
var server = await GetServerWithPermCheck(serverId);
|
||||||
|
|
||||||
|
var apiClient = await NodeService.CreateApiClient(server.Node);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var data = await apiClient.GetJson<DaemonShared.DaemonSide.Http.Responses.Servers.ServerStatusResponse>(
|
||||||
|
$"api/servers/{server.Id}/status"
|
||||||
|
);
|
||||||
|
|
||||||
|
return new ServerStatusResponse()
|
||||||
|
{
|
||||||
|
PowerState = data.State.ToServerPowerState()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
catch (HttpRequestException e)
|
||||||
|
{
|
||||||
|
throw new HttpApiException("Unable to access the node the server is running on", 502);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Server> GetServerWithPermCheck(int serverId)
|
||||||
|
{
|
||||||
|
var user = User.AsIdentity<User>();
|
||||||
|
|
||||||
|
var server = await ServerRepository
|
||||||
|
.Get()
|
||||||
|
.Include(x => x.Node)
|
||||||
|
.FirstOrDefaultAsync(x => x.Id == serverId);
|
||||||
|
|
||||||
|
if (server == null)
|
||||||
|
throw new HttpApiException("No server with this id found", 404);
|
||||||
|
|
||||||
|
if (server.OwnerId == user.Id) // The current user is the owner
|
||||||
|
return server;
|
||||||
|
|
||||||
|
if (User.HasPermission("admin.servers.get")) // The current user is an admin
|
||||||
|
return server;
|
||||||
|
|
||||||
|
throw new HttpApiException("No server with this id found", 404);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,13 @@ public class SidebarImplementation : ISidebarItemProvider
|
|||||||
{
|
{
|
||||||
return
|
return
|
||||||
[
|
[
|
||||||
|
new SidebarItem()
|
||||||
|
{
|
||||||
|
Name = "Servers",
|
||||||
|
Path = "/servers",
|
||||||
|
Icon = "icon-server",
|
||||||
|
Priority = 4
|
||||||
|
},
|
||||||
new SidebarItem()
|
new SidebarItem()
|
||||||
{
|
{
|
||||||
Name = "Servers",
|
Name = "Servers",
|
||||||
|
|||||||
174
MoonlightServers.Frontend/UI/Components/Servers/ServerCard.razor
Normal file
174
MoonlightServers.Frontend/UI/Components/Servers/ServerCard.razor
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
@using MoonCore.Helpers
|
||||||
|
@using MoonlightServers.Shared.Enums
|
||||||
|
@using MoonlightServers.Shared.Http.Responses.Users.Servers
|
||||||
|
|
||||||
|
@inject HttpApiClient ApiClient
|
||||||
|
@inject ILogger<ServerCard> Logger
|
||||||
|
|
||||||
|
@{
|
||||||
|
var gradient = "from-gray-600/20";
|
||||||
|
var border = "border-gray-600";
|
||||||
|
|
||||||
|
if (IsLoaded && !IsFailed)
|
||||||
|
{
|
||||||
|
gradient = Status.PowerState switch
|
||||||
|
{
|
||||||
|
ServerPowerState.Installing => "from-primary-600/20",
|
||||||
|
ServerPowerState.Offline => "from-danger-600/20",
|
||||||
|
ServerPowerState.Starting => "from-warning-600/20",
|
||||||
|
ServerPowerState.Stopping => "from-warning-600/20",
|
||||||
|
ServerPowerState.Online => "from-success-600/20",
|
||||||
|
_ => "from-gray-600/20"
|
||||||
|
};
|
||||||
|
|
||||||
|
border = Status.PowerState switch
|
||||||
|
{
|
||||||
|
ServerPowerState.Installing => "border-primary-600",
|
||||||
|
ServerPowerState.Offline => "border-danger-600",
|
||||||
|
ServerPowerState.Starting => "border-warning-600",
|
||||||
|
ServerPowerState.Stopping => "border-warning-600",
|
||||||
|
ServerPowerState.Online => "border-success-600",
|
||||||
|
_ => "border-gray-600"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
<a href="/servers/@Server.Id"
|
||||||
|
class="w-full bg-gradient-to-r @gradient to-gray-750/65 to-25% px-5 py-3.5 rounded-xl border-l-8 @border">
|
||||||
|
<div class="grid grid-cols-6">
|
||||||
|
<div class="flex items-center col-span-6 sm:col-span-2 2xl:col-span-1">
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex items-center">
|
||||||
|
<i class="icon-server me-3 align-middle"></i>
|
||||||
|
<div class="text-lg align-middle">
|
||||||
|
@Server.Name
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden sm:flex items-center justify-end gap-x-3 sm:col-span-4 2xl:col-span-3">
|
||||||
|
@if (
|
||||||
|
IsLoaded &&
|
||||||
|
!IsFailed &&
|
||||||
|
Status.PowerState is ServerPowerState.Starting or ServerPowerState.Stopping or ServerPowerState.Online
|
||||||
|
)
|
||||||
|
{
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
|
||||||
|
<div>
|
||||||
|
<i class="icon-cpu"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">56,8%</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
|
||||||
|
<div>
|
||||||
|
<i class="icon-memory-stick"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">4,2 GB / 8 GB</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
|
||||||
|
<div>
|
||||||
|
<i class="icon-hard-drive"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">53 GB / 100GB</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!IsLoaded)
|
||||||
|
{
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row text-gray-700">
|
||||||
|
<div>
|
||||||
|
<i class="icon-loader"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">Loading</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else if (IsFailed)
|
||||||
|
{
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row text-danger-500">
|
||||||
|
<div>
|
||||||
|
<i class="icon-cable"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">Unreachable</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else if (IsLoaded && !IsFailed && Status.PowerState is ServerPowerState.Offline)
|
||||||
|
{
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row text-danger-500">
|
||||||
|
<div>
|
||||||
|
<i class="icon-power-off"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">Offline</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else if (IsLoaded && !IsFailed && Status.PowerState is ServerPowerState.Installing)
|
||||||
|
{
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row text-primary-500">
|
||||||
|
<div>
|
||||||
|
<i class="icon-hammer"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">Installing</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden 2xl:flex items-center justify-end gap-x-3 2xl:col-span-2">
|
||||||
|
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
|
||||||
|
<div>
|
||||||
|
<i class="icon-sparkles"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">@Server.StarName</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
|
||||||
|
<div>
|
||||||
|
<i class="icon-database"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">@Server.NodeName</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
[Parameter] public ServerDetailResponse Server { get; set; }
|
||||||
|
|
||||||
|
private ServerStatusResponse Status;
|
||||||
|
|
||||||
|
private bool IsFailed = false;
|
||||||
|
private bool IsLoaded = false;
|
||||||
|
|
||||||
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
||||||
|
{
|
||||||
|
if (!firstRender)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Status = await ApiClient.GetJson<ServerStatusResponse>(
|
||||||
|
$"api/servers/{Server.Id}/status"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
IsFailed = true;
|
||||||
|
Logger.LogWarning("Unable to fetch status from server {id}: {e}", Server.Id, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
IsLoaded = true;
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
@using MoonlightServers.Shared.Http.Responses.Users.Servers
|
||||||
|
@{
|
||||||
|
var gradient = Status switch
|
||||||
|
{
|
||||||
|
4 => "from-primary-600/20",
|
||||||
|
3 => "from-danger-600/20",
|
||||||
|
2 => "from-warning-600/20",
|
||||||
|
1 => "from-success-600/20",
|
||||||
|
_ => "from-gray-600/20"
|
||||||
|
};
|
||||||
|
|
||||||
|
var border = Status switch
|
||||||
|
{
|
||||||
|
4 => "border-primary-600",
|
||||||
|
3 => "border-danger-600",
|
||||||
|
2 => "border-warning-600",
|
||||||
|
1 => "border-success-600",
|
||||||
|
_ => "border-gray-600"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
<a href="/servers/@Server.Id" class="w-full bg-gradient-to-r @gradient to-gray-750/65 to-25% px-5 py-3.5 rounded-xl border-l-8 @border">
|
||||||
|
<div class="grid grid-cols-6">
|
||||||
|
<div class="flex items-center col-span-6 sm:col-span-2 2xl:col-span-1">
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex items-center">
|
||||||
|
<i class="icon-server me-3 align-middle"></i>
|
||||||
|
<div class="text-lg align-middle">
|
||||||
|
@Server.Name
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden sm:flex items-center justify-end gap-x-3 sm:col-span-4 2xl:col-span-3">
|
||||||
|
@if (Status >= 1 && Status <= 2)
|
||||||
|
{
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
|
||||||
|
<div>
|
||||||
|
<i class="icon-cpu"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">56,8%</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
|
||||||
|
<div>
|
||||||
|
<i class="icon-memory-stick"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">4,2 GB / 8 GB</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
|
||||||
|
<div>
|
||||||
|
<i class="icon-hard-drive"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">53 GB / 100GB</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Status == 0)
|
||||||
|
{
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row text-gray-700">
|
||||||
|
<div>
|
||||||
|
<i class="icon-loader"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">Loading</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else if (Status == 3)
|
||||||
|
{
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row text-danger-500">
|
||||||
|
<div>
|
||||||
|
<i class="icon-power-off"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">Offline</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
else if (Status == 4)
|
||||||
|
{
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row text-primary-500">
|
||||||
|
<div>
|
||||||
|
<i class="icon-hammer"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">Installing</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="hidden 2xl:flex items-center justify-end gap-x-3 2xl:col-span-2">
|
||||||
|
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
|
||||||
|
<div>
|
||||||
|
<i class="icon-sparkles"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">@Server.StarName</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
|
||||||
|
<div>
|
||||||
|
<i class="icon-database"></i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="ms-3">@Server.NodeName</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</a>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
[Parameter]
|
||||||
|
public ServerDetailResponse Server { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public int Status { get; set; }
|
||||||
|
}
|
||||||
32
MoonlightServers.Frontend/UI/Views/User/Index.razor
Normal file
32
MoonlightServers.Frontend/UI/Views/User/Index.razor
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
@page "/servers"
|
||||||
|
|
||||||
|
@using MoonCore.Helpers
|
||||||
|
@using MoonlightServers.Frontend.UI.Components.Servers
|
||||||
|
@using MoonCore.Blazor.Tailwind.Components
|
||||||
|
@using MoonCore.Models
|
||||||
|
@using MoonlightServers.Shared.Http.Responses.Users.Servers
|
||||||
|
|
||||||
|
@inject HttpApiClient ApiClient
|
||||||
|
|
||||||
|
<LazyLoader Load="Load">
|
||||||
|
<div class="flex flex-col gap-y-5">
|
||||||
|
@foreach (var server in Servers)
|
||||||
|
{
|
||||||
|
<ServerCard Server="server" />
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</LazyLoader>
|
||||||
|
|
||||||
|
@code
|
||||||
|
{
|
||||||
|
private ServerDetailResponse[] Servers;
|
||||||
|
|
||||||
|
private async Task Load(LazyLoader lazyLoader)
|
||||||
|
{
|
||||||
|
Servers = await PagedData<ServerDetailResponse>.All(async (page, pageSize) =>
|
||||||
|
await ApiClient.GetJson<PagedData<ServerDetailResponse>>(
|
||||||
|
$"api/servers/list?page={page}&pageSize={pageSize}"
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
10
MoonlightServers.Shared/Enums/ServerPowerState.cs
Normal file
10
MoonlightServers.Shared/Enums/ServerPowerState.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace MoonlightServers.Shared.Enums;
|
||||||
|
|
||||||
|
public enum ServerPowerState
|
||||||
|
{
|
||||||
|
Offline = 0,
|
||||||
|
Starting = 1,
|
||||||
|
Online = 2,
|
||||||
|
Stopping = 3,
|
||||||
|
Installing = 4
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace MoonlightServers.Shared.Http.Responses.User.Allocations;
|
||||||
|
|
||||||
|
public class AllocationDetailResponse
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string IpAddress { get; set; }
|
||||||
|
public int Port { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using MoonlightServers.Shared.Http.Responses.User.Allocations;
|
||||||
|
|
||||||
|
namespace MoonlightServers.Shared.Http.Responses.Users.Servers;
|
||||||
|
|
||||||
|
public class ServerDetailResponse
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string NodeName { get; set; }
|
||||||
|
public string StarName { get; set; }
|
||||||
|
|
||||||
|
public AllocationDetailResponse[] Allocations { get; set; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
using MoonlightServers.Shared.Enums;
|
||||||
|
|
||||||
|
namespace MoonlightServers.Shared.Http.Responses.Users.Servers;
|
||||||
|
|
||||||
|
public class ServerStatusResponse
|
||||||
|
{
|
||||||
|
public ServerPowerState PowerState { get; set; }
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user