Fixed smaller issues. Upgraded server node ui

This commit is contained in:
Marcel Baumgartner
2024-06-26 10:59:14 +02:00
parent 95a5eafec2
commit 53509ecf63
8 changed files with 257 additions and 121 deletions

View File

@@ -169,8 +169,6 @@ else
if (TryGetAttribute(customAttributes, out DisplayNameAttribute nameAttribute)) if (TryGetAttribute(customAttributes, out DisplayNameAttribute nameAttribute))
propConfig.WithName(nameAttribute.DisplayName); propConfig.WithName(nameAttribute.DisplayName);
else
propConfig.WithName(Formatter.ConvertCamelCaseToSpaces(property.Name));
if (TryGetAttribute(customAttributes, out DescriptionAttribute descriptionAttribute)) if (TryGetAttribute(customAttributes, out DescriptionAttribute descriptionAttribute))
propConfig.WithDescription(descriptionAttribute.Description); propConfig.WithDescription(descriptionAttribute.Description);

View File

@@ -53,7 +53,7 @@
private void OnConfigure(FastCrudConfiguration<User> configuration) private void OnConfigure(FastCrudConfiguration<User> configuration)
{ {
configuration.CustomCreate += async user => configuration.CustomCreate = async user =>
{ {
var result = await AuthenticationProvider.Register(user.Username, user.Email, user.Password); var result = await AuthenticationProvider.Register(user.Username, user.Email, user.Password);
@@ -61,7 +61,7 @@
throw new DisplayException("An unknown error occured while creating user"); throw new DisplayException("An unknown error occured while creating user");
}; };
configuration.ValidateEdit += async user => configuration.ValidateEdit = async user =>
{ {
await AuthenticationProvider.ChangeDetails(user, user.Email, user.Username); await AuthenticationProvider.ChangeDetails(user, user.Email, user.Username);
}; };

View File

@@ -3,7 +3,7 @@ namespace Moonlight.Features.Servers.Entities;
public class ServerAllocation public class ServerAllocation
{ {
public int Id { get; set; } public int Id { get; set; }
public string IpAddress { get; set; } = ""; public string IpAddress { get; set; } = "0.0.0.0";
public int Port { get; set; } public int Port { get; set; }
public string Note { get; set; } = ""; public string Note { get; set; } = "";
} }

View File

@@ -1,7 +1,10 @@
@using System.ComponentModel.DataAnnotations
@using Moonlight.Features.Servers.Entities @using Moonlight.Features.Servers.Entities
@using Moonlight.Features.Servers.Models.Forms.Admin.Nodes @using Moonlight.Features.Servers.Models.Forms.Admin.Nodes
@using BlazorTable @using BlazorTable
@using MoonCore.Abstractions @using MoonCore.Abstractions
@using MoonCore.Blazor.Models.Fast
@using MoonCore.Blazor.Models.Fast.Validators
@using MoonCore.Exceptions @using MoonCore.Exceptions
@@ -27,38 +30,31 @@
<input @bind="AllocationEnd" class="form-control w-25" type="number"/> <input @bind="AllocationEnd" class="form-control w-25" type="number"/>
</div> </div>
<div class="d-flex justify-content-end"> <div class="d-flex justify-content-end">
<WButton OnClick="AddAllocations" Text="Add" CssClasses="btn btn-primary"/> <WButton OnClick="AddAllocations" CssClasses="btn btn-primary">
Add
</WButton>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="col-md-8 col-12">@* <div class="col-md-8 col-12">
<AutoListCrud TRootItem="ServerNode" <FastCrud TItem="ServerAllocation"
TItem="ServerAllocation" Loader="Loader"
TCreateForm="CreateAllocationForm" OnConfigure="OnConfigure"
TUpdateForm="UpdateAllocationForm" OnConfigureCreate="OnConfigureCreate"
Title="" OnConfigureEdit="OnConfigureEdit"
Field="@(x => x.Allocations)" @ref="Crud">
RootItem="Node" <View>
@ref="Crud" <MCBColumn TItem="ServerAllocation" Field="@(x => x.Id)" Title="Id"/>
ValidateDelete="ValidateDelete" <MCBColumn TItem="ServerAllocation" Field="@(x => x.IpAddress)" Title="Ip address"/>
ValidateAdd="ValidateAdd"> <MCBColumn TItem="ServerAllocation" Field="@(x => x.Port)" Title="Port"/>
<Toolbar> </View>
<WButton CssClasses="btn btn-icon btn-danger" OnClick="DeleteAllAllocations"> <ViewToolbar>
<WButton CssClasses="btn btn-icon btn-danger me-2" OnClick="DeleteAllAllocations">
<i class="bx bx-sm bx-trash"></i> <i class="bx bx-sm bx-trash"></i>
</WButton> </WButton>
</Toolbar> </ViewToolbar>
<View> </FastCrud>
<CrudColumn TItem="ServerAllocation" Field="@(x => x.Id)" Title="Id"/>
<CrudColumn TItem="ServerAllocation" Field="@(x => x.IpAddress)" Title="Ip address"/>
<CrudColumn TItem="ServerAllocation" Field="@(x => x.Port)" Title="Port"/>
</View>
<NoItemsView>
<IconAlert Title="No allocations found" Color="primary" Icon="bx-search-alt">
In order for a server to be deployed on this node allocations need to be created here
</IconAlert>
</NoItemsView>
</AutoListCrud>*@
</div> </div>
</div> </div>
@@ -66,8 +62,7 @@
{ {
[Parameter] public ServerNode Node { get; set; } [Parameter] public ServerNode Node { get; set; }
// A bit long, lol private FastCrud<ServerAllocation> Crud;
//private AutoListCrud<ServerAllocation, ServerNode, CreateAllocationForm, UpdateAllocationForm> Crud;
// Quick add values // Quick add values
private string IpAddress = "0.0.0.0"; private string IpAddress = "0.0.0.0";
@@ -101,7 +96,7 @@
NodeRepository.Update(Node!); NodeRepository.Update(Node!);
await ToastService.Success($"Added {added} allocations and skipped {skipped} ports due to existing allocations"); await ToastService.Success($"Added {added} allocations and skipped {skipped} ports due to existing allocations");
//await Crud.Reload(); await Crud.Refresh();
} }
private async Task DeleteAllAllocations() private async Task DeleteAllAllocations()
@@ -124,11 +119,34 @@
} }
await ToastService.Success("Successfully deleted allocations"); await ToastService.Success("Successfully deleted allocations");
//await Crud.Reload(); await Crud.Refresh();
}); });
} }
private Task ValidateDelete(ServerAllocation allocation) private IEnumerable<ServerAllocation> Loader(Repository<ServerAllocation> _)
{
return Node.Allocations;
}
private void OnConfigure(FastCrudConfiguration<ServerAllocation> configuration)
{
configuration.ValidateCreate = allocation =>
{
if (Node.Allocations.Any(x => x.Port == allocation.Port && x.IpAddress == allocation.IpAddress))
throw new DisplayException("A allocation with these ip and port does already exist");
return Task.CompletedTask;
};
configuration.ValidateEdit = allocation =>
{
if (Node.Allocations.Any(x => x.Port == allocation.Port && x.IpAddress == allocation.IpAddress && x.Id != allocation.Id))
throw new DisplayException("A allocation with these ip and port does already exist");
return Task.CompletedTask;
};
configuration.ValidateDelete = allocation =>
{ {
// Check if allocation is associated with a server // Check if allocation is associated with a server
var serverWithThisAllocation = ServerRepository var serverWithThisAllocation = ServerRepository
@@ -141,13 +159,51 @@
} }
return Task.CompletedTask; return Task.CompletedTask;
} };
private Task ValidateAdd(ServerAllocation allocation) configuration.CustomCreate = allocation =>
{ {
if (Node!.Allocations.Any(x => x.Port == allocation.Port && x.IpAddress == allocation.IpAddress)) Node.Allocations.Add(allocation);
throw new DisplayException("A allocation with these ip and port does already exist"); NodeRepository.Update(Node);
return Task.CompletedTask; return Task.CompletedTask;
};
configuration.CustomEdit = allocation =>
{
AllocationRepository.Update(allocation);
return Task.CompletedTask;
};
configuration.CustomDelete = allocation =>
{
Node.Allocations.Remove(allocation);
NodeRepository.Update(Node);
try
{
AllocationRepository.Delete(allocation);
} }
catch (Exception)
{
/* do not fail here */
}
return Task.CompletedTask;
};
}
private void OnConfigureCreate(FastConfiguration<ServerAllocation> configuration)
{
configuration.AddProperty(x => x.IpAddress)
.WithDefaultComponent()
.WithValidation(FastValidators.Required)
.WithValidation(RegexValidator.Create("^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$", "You need to provide a valid ipv4 address"));
configuration.AddProperty(x => x.Port)
.WithDefaultComponent()
.WithValidation<int>(x => x >= 1 && x <= 65535 ? ValidationResult.Success : new ValidationResult("You need to provide a valid port"));
}
private void OnConfigureEdit(FastConfiguration<ServerAllocation> configuration, ServerAllocation _) => OnConfigureCreate(configuration);
} }

View File

@@ -8,7 +8,7 @@
@implements IDisposable @implements IDisposable
<LazyLoader Load="Load"> <LazyLoader Load="Load">
<div class="row g-5 mt-5"> <div class="row g-5">
<div class="col-md-3 col-12"> <div class="col-md-3 col-12">
@{ @{
var cpuName = Status.Hardware.Cores.Any() ? Status.Hardware.Cores.First().Name : "N/A"; var cpuName = Status.Hardware.Cores.Any() ? Status.Hardware.Cores.First().Name : "N/A";

View File

@@ -1,5 +1,6 @@
@page "/admin/servers/nodes" @page "/admin/servers/nodes"
@using System.ComponentModel.DataAnnotations
@using Moonlight.Features.Servers.Models.Forms.Admin.Nodes @using Moonlight.Features.Servers.Models.Forms.Admin.Nodes
@using Moonlight.Features.Servers.UI.Components @using Moonlight.Features.Servers.UI.Components
@using Moonlight.Features.Servers.Entities @using Moonlight.Features.Servers.Entities
@@ -8,8 +9,11 @@
@using MoonCore.Exceptions @using MoonCore.Exceptions
@using MoonCore.Helpers @using MoonCore.Helpers
@using System.Text.RegularExpressions; @using System.Text.RegularExpressions;
@using MoonCore.Blazor.Forms.Fast.Components
@using MoonCore.Blazor.Models.Fast
@using Moonlight.Features.Servers.Api.Resources @using Moonlight.Features.Servers.Api.Resources
@using Moonlight.Features.Servers.Services @using Moonlight.Features.Servers.Services
@using Moonlight.Features.Servers.UI.NodeComponents
@inject Repository<Server> ServerRepository @inject Repository<Server> ServerRepository
@inject Repository<ServerNode> NodeRepository @inject Repository<ServerNode> NodeRepository
@@ -24,18 +28,18 @@
<AdminServersNavigation Index="1"/> <AdminServersNavigation Index="1"/>
<LazyLoader Load="Load"> <LazyLoader Load="Load">
<AutoCrud TItem="ServerNode" <FastCrud TItem="ServerNode"
TCreateForm="CreateNodeForm" Loader="Loader"
TUpdateForm="UpdateNodeForm" OnConfigure="OnConfigure"
Loader="LoadData" OnConfigureCreate="OnConfigureCreate"
ValidateAdd="ValidateAdd" OnConfigureEdit="OnConfigureEdit">
ValidateUpdate="ValidateUpdate"
ValidateDelete="ValidateDelete">
<View> <View>
<MCBColumn TItem="ServerNode" Field="@(x => x.Id)" Title="Id"/> <MCBColumn TItem="ServerNode" Field="@(x => x.Id)" Title="Id"/>
<MCBColumn TItem="ServerNode" Field="@(x => x.Name)" Title="Name"> <MCBColumn TItem="ServerNode" Field="@(x => x.Name)" Title="Name">
<Template> <Template>
<a href="/admin/servers/nodes/view/@(context!.Id)">@context!.Name</a> @*<a href="/admin/servers/nodes/view/@(context!.Id)"></a> TODO: Make this work again*@
@context!.Name
</Template> </Template>
</MCBColumn> </MCBColumn>
<MCBColumn TItem="ServerNode" Field="@(x => x.Fqdn)" Title="Fqdn"/> <MCBColumn TItem="ServerNode" Field="@(x => x.Fqdn)" Title="Fqdn"/>
@@ -108,13 +112,7 @@
</Template> </Template>
</MCBColumn> </MCBColumn>
</View> </View>
@* </FastCrud>
<NoItemsView>
<IconAlert Title="No nodes found" Color="primary" Icon="bx-search-alt">
Add a new node in order to get started. Need help? Check out our <a href="https://docs.moonlightpanel.xyz">documentation</a>
</IconAlert>
</NoItemsView>*@
</AutoCrud>
</LazyLoader> </LazyLoader>
@code @code
@@ -125,6 +123,8 @@
private Task Load(LazyLoader lazyLoader) private Task Load(LazyLoader lazyLoader)
{ {
UpdateTimer = new(async _ => UpdateTimer = new(async _ =>
{
try
{ {
NodeStats.Clear(); NodeStats.Clear();
@@ -149,18 +149,26 @@
await InvokeAsync(StateHasChanged); await InvokeAsync(StateHasChanged);
} }
}
catch (Exception e)
{
Logger.LogError("Unable to update node stats due to an unhandled error: {e}", e);
}
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(1)); }, null, TimeSpan.Zero, TimeSpan.FromSeconds(1));
return Task.CompletedTask; return Task.CompletedTask;
} }
private IEnumerable<ServerNode> LoadData(Repository<ServerNode> repository) private IEnumerable<ServerNode> Loader(Repository<ServerNode> repository)
{ {
return repository return repository
.Get(); .Get()
.Include(x => x.Allocations);
} }
private Task ValidateDelete(ServerNode node) private void OnConfigure(FastCrudConfiguration<ServerNode> configuration)
{
configuration.ValidateDelete = node =>
{ {
if (ServerRepository if (ServerRepository
.Get() .Get()
@@ -180,22 +188,96 @@
} }
return Task.CompletedTask; return Task.CompletedTask;
} };
private Task ValidateAdd(ServerNode node) configuration.ValidateCreate = node =>
{ {
ValidateFqdn(node); ValidateFqdn(node);
node.Token = Formatter.GenerateString(32); node.Token = Formatter.GenerateString(32);
return Task.CompletedTask; return Task.CompletedTask;
} };
private Task ValidateUpdate(ServerNode node) configuration.ValidateEdit = node =>
{ {
ValidateFqdn(node); ValidateFqdn(node);
return Task.CompletedTask; return Task.CompletedTask;
};
}
private void OnConfigureCreate(FastConfiguration<ServerNode> configuration)
{
configuration.AddProperty(x => x.Name)
.WithDefaultComponent()
.WithValidation(FastValidators.Required);
configuration.AddProperty(x => x.Fqdn)
.WithDefaultComponent()
.WithDescription("This needs to be the ip or domain of the node depending on the ssl settings")
.WithValidation(FastValidators.Required);
configuration.AddProperty(x => x.Ssl)
.WithComponent<bool, SwitchComponent>()
.WithDescription("This enables ssl for the http connections to the node. Only enable this if you have the cert installed on the node");
configuration.AddProperty(x => x.HttpPort)
.WithDefaultComponent()
.WithDescription("This is the http(s) port used by the node to allow communication to the node from the panel");
configuration.AddProperty(x => x.FtpPort)
.WithDefaultComponent()
.WithDescription("This is the ftp port users can use to access their servers filesystem via their ftp client");
}
private void OnConfigureEdit(FastConfiguration<ServerNode> configuration, ServerNode node)
{
configuration.AddProperty(x => x.Name)
.WithDefaultComponent()
.WithPage("Settings")
.WithValidation(FastValidators.Required);
configuration.AddProperty(x => x.Fqdn)
.WithDefaultComponent()
.WithPage("Settings")
.WithDescription("This needs to be the ip or domain of the node depending on the ssl settings")
.WithValidation(FastValidators.Required);
configuration.AddProperty(x => x.Ssl)
.WithComponent<bool, SwitchComponent>()
.WithPage("Settings")
.WithDescription("This enables ssl for the http connections to the node. Only enable this if you have the cert installed on the node");
configuration.AddProperty(x => x.HttpPort)
.WithDefaultComponent()
.WithPage("Settings")
.WithDescription("This is the http(s) port used by the node to allow communication to the node from the panel");
configuration.AddProperty(x => x.FtpPort)
.WithDefaultComponent()
.WithPage("Settings")
.WithDescription("This is the ftp port users can use to access their servers filesystem via their ftp client");
configuration.AddCustomPage("Overview", ComponentHelper.FromType<NodeOverview>(parameters =>
{
parameters.Add("Node", node);
}));
configuration.AddCustomPage("Allocations", ComponentHelper.FromType<NodeAllocations>(parameters =>
{
parameters.Add("Node", node);
}));
configuration.AddCustomPage("Setup", ComponentHelper.FromType<NodeSetup>(parameters =>
{
parameters.Add("Node", node);
}));
configuration.AddCustomPage("Logs", ComponentHelper.FromType<NodeLogs>(parameters =>
{
parameters.Add("Node", node);
}));
} }
private void ValidateFqdn(ServerNode node) private void ValidateFqdn(ServerNode node)

View File

@@ -74,7 +74,7 @@
private void OnConfigure(FastCrudConfiguration<ServerNetwork> configuration) private void OnConfigure(FastCrudConfiguration<ServerNetwork> configuration)
{ {
configuration.ValidateCreate += network => configuration.ValidateCreate = network =>
{ {
if (!ServerRepository if (!ServerRepository
.Get() .Get()

View File

@@ -94,7 +94,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="MoonCore" Version="1.4.1" /> <PackageReference Include="MoonCore" Version="1.4.1" />
<PackageReference Include="MoonCore.Blazor" Version="1.0.9" /> <PackageReference Include="MoonCore.Blazor" Version="1.1.0" />
<PackageReference Include="Otp.NET" Version="1.3.0" /> <PackageReference Include="Otp.NET" Version="1.3.0" />
<PackageReference Include="QRCoder" Version="1.4.3" /> <PackageReference Include="QRCoder" Version="1.4.3" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.6.2" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.6.2" />