Fixed smaller issues. Upgraded server node ui
This commit is contained in:
@@ -169,8 +169,6 @@ else
|
||||
|
||||
if (TryGetAttribute(customAttributes, out DisplayNameAttribute nameAttribute))
|
||||
propConfig.WithName(nameAttribute.DisplayName);
|
||||
else
|
||||
propConfig.WithName(Formatter.ConvertCamelCaseToSpaces(property.Name));
|
||||
|
||||
if (TryGetAttribute(customAttributes, out DescriptionAttribute descriptionAttribute))
|
||||
propConfig.WithDescription(descriptionAttribute.Description);
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
|
||||
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);
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
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);
|
||||
};
|
||||
|
||||
@@ -3,7 +3,7 @@ namespace Moonlight.Features.Servers.Entities;
|
||||
public class ServerAllocation
|
||||
{
|
||||
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 string Note { get; set; } = "";
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using Moonlight.Features.Servers.Entities
|
||||
@using Moonlight.Features.Servers.Models.Forms.Admin.Nodes
|
||||
@using BlazorTable
|
||||
@using MoonCore.Abstractions
|
||||
@using MoonCore.Blazor.Models.Fast
|
||||
@using MoonCore.Blazor.Models.Fast.Validators
|
||||
@using MoonCore.Exceptions
|
||||
|
||||
|
||||
@@ -27,38 +30,31 @@
|
||||
<input @bind="AllocationEnd" class="form-control w-25" type="number"/>
|
||||
</div>
|
||||
<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 class="col-md-8 col-12">@*
|
||||
<AutoListCrud TRootItem="ServerNode"
|
||||
TItem="ServerAllocation"
|
||||
TCreateForm="CreateAllocationForm"
|
||||
TUpdateForm="UpdateAllocationForm"
|
||||
Title=""
|
||||
Field="@(x => x.Allocations)"
|
||||
RootItem="Node"
|
||||
@ref="Crud"
|
||||
ValidateDelete="ValidateDelete"
|
||||
ValidateAdd="ValidateAdd">
|
||||
<Toolbar>
|
||||
<WButton CssClasses="btn btn-icon btn-danger" OnClick="DeleteAllAllocations">
|
||||
<div class="col-md-8 col-12">
|
||||
<FastCrud TItem="ServerAllocation"
|
||||
Loader="Loader"
|
||||
OnConfigure="OnConfigure"
|
||||
OnConfigureCreate="OnConfigureCreate"
|
||||
OnConfigureEdit="OnConfigureEdit"
|
||||
@ref="Crud">
|
||||
<View>
|
||||
<MCBColumn TItem="ServerAllocation" Field="@(x => x.Id)" Title="Id"/>
|
||||
<MCBColumn TItem="ServerAllocation" Field="@(x => x.IpAddress)" Title="Ip address"/>
|
||||
<MCBColumn TItem="ServerAllocation" Field="@(x => x.Port)" Title="Port"/>
|
||||
</View>
|
||||
<ViewToolbar>
|
||||
<WButton CssClasses="btn btn-icon btn-danger me-2" OnClick="DeleteAllAllocations">
|
||||
<i class="bx bx-sm bx-trash"></i>
|
||||
</WButton>
|
||||
</Toolbar>
|
||||
<View>
|
||||
<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>*@
|
||||
</ViewToolbar>
|
||||
</FastCrud>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -66,8 +62,7 @@
|
||||
{
|
||||
[Parameter] public ServerNode Node { get; set; }
|
||||
|
||||
// A bit long, lol
|
||||
//private AutoListCrud<ServerAllocation, ServerNode, CreateAllocationForm, UpdateAllocationForm> Crud;
|
||||
private FastCrud<ServerAllocation> Crud;
|
||||
|
||||
// Quick add values
|
||||
private string IpAddress = "0.0.0.0";
|
||||
@@ -101,7 +96,7 @@
|
||||
NodeRepository.Update(Node!);
|
||||
|
||||
await ToastService.Success($"Added {added} allocations and skipped {skipped} ports due to existing allocations");
|
||||
//await Crud.Reload();
|
||||
await Crud.Refresh();
|
||||
}
|
||||
|
||||
private async Task DeleteAllAllocations()
|
||||
@@ -124,30 +119,91 @@
|
||||
}
|
||||
|
||||
await ToastService.Success("Successfully deleted allocations");
|
||||
//await Crud.Reload();
|
||||
await Crud.Refresh();
|
||||
});
|
||||
}
|
||||
|
||||
private Task ValidateDelete(ServerAllocation allocation)
|
||||
private IEnumerable<ServerAllocation> Loader(Repository<ServerAllocation> _)
|
||||
{
|
||||
// Check if allocation is associated with a server
|
||||
var serverWithThisAllocation = ServerRepository
|
||||
.Get()
|
||||
.FirstOrDefault(x => x.Allocations.Any(y => y.Id == allocation.Id));
|
||||
return Node.Allocations;
|
||||
}
|
||||
|
||||
if (serverWithThisAllocation != null)
|
||||
private void OnConfigure(FastCrudConfiguration<ServerAllocation> configuration)
|
||||
{
|
||||
configuration.ValidateCreate = allocation =>
|
||||
{
|
||||
throw new DisplayException($"The server '{serverWithThisAllocation.Name}' (ID: {serverWithThisAllocation.Id}) is using this allocation. Delete the server in order to delete this 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;
|
||||
};
|
||||
|
||||
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
|
||||
var serverWithThisAllocation = ServerRepository
|
||||
.Get()
|
||||
.FirstOrDefault(x => x.Allocations.Any(y => y.Id == allocation.Id));
|
||||
|
||||
if (serverWithThisAllocation != null)
|
||||
{
|
||||
throw new DisplayException($"The server '{serverWithThisAllocation.Name}' (ID: {serverWithThisAllocation.Id}) is using this allocation. Delete the server in order to delete this allocation");
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
configuration.CustomCreate = allocation =>
|
||||
{
|
||||
Node.Allocations.Add(allocation);
|
||||
NodeRepository.Update(Node);
|
||||
|
||||
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 Task ValidateAdd(ServerAllocation allocation)
|
||||
private void OnConfigureCreate(FastConfiguration<ServerAllocation> configuration)
|
||||
{
|
||||
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");
|
||||
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"));
|
||||
|
||||
return Task.CompletedTask;
|
||||
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);
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
@implements IDisposable
|
||||
|
||||
<LazyLoader Load="Load">
|
||||
<div class="row g-5 mt-5">
|
||||
<div class="row g-5">
|
||||
<div class="col-md-3 col-12">
|
||||
@{
|
||||
var cpuName = Status.Hardware.Cores.Any() ? Status.Hardware.Cores.First().Name : "N/A";
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@page "/admin/servers/nodes"
|
||||
|
||||
@using System.ComponentModel.DataAnnotations
|
||||
@using Moonlight.Features.Servers.Models.Forms.Admin.Nodes
|
||||
@using Moonlight.Features.Servers.UI.Components
|
||||
@using Moonlight.Features.Servers.Entities
|
||||
@@ -8,8 +9,11 @@
|
||||
@using MoonCore.Exceptions
|
||||
@using MoonCore.Helpers
|
||||
@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.Services
|
||||
@using Moonlight.Features.Servers.UI.NodeComponents
|
||||
|
||||
@inject Repository<Server> ServerRepository
|
||||
@inject Repository<ServerNode> NodeRepository
|
||||
@@ -24,18 +28,18 @@
|
||||
<AdminServersNavigation Index="1"/>
|
||||
|
||||
<LazyLoader Load="Load">
|
||||
<AutoCrud TItem="ServerNode"
|
||||
TCreateForm="CreateNodeForm"
|
||||
TUpdateForm="UpdateNodeForm"
|
||||
Loader="LoadData"
|
||||
ValidateAdd="ValidateAdd"
|
||||
ValidateUpdate="ValidateUpdate"
|
||||
ValidateDelete="ValidateDelete">
|
||||
<FastCrud TItem="ServerNode"
|
||||
Loader="Loader"
|
||||
OnConfigure="OnConfigure"
|
||||
OnConfigureCreate="OnConfigureCreate"
|
||||
OnConfigureEdit="OnConfigureEdit">
|
||||
<View>
|
||||
<MCBColumn TItem="ServerNode" Field="@(x => x.Id)" Title="Id"/>
|
||||
<MCBColumn TItem="ServerNode" Field="@(x => x.Name)" Title="Name">
|
||||
<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>
|
||||
</MCBColumn>
|
||||
<MCBColumn TItem="ServerNode" Field="@(x => x.Fqdn)" Title="Fqdn"/>
|
||||
@@ -63,7 +67,7 @@
|
||||
@if (NodeStats.ContainsKey(context!.Id) && NodeStats[context.Id] != null)
|
||||
{
|
||||
var cores = NodeStats[context!.Id]!.Hardware.Cores;
|
||||
var percent = cores.Any() ? Math.Round(cores.Average(x => x.Usage), 2) : 0;
|
||||
var percent = cores.Any() ? Math.Round(cores.Average(x => x.Usage), 2) : 0;
|
||||
|
||||
<ColoredBar Value="percent"/>
|
||||
}
|
||||
@@ -78,10 +82,10 @@
|
||||
@if (NodeStats.ContainsKey(context!.Id) && NodeStats[context.Id] != null)
|
||||
{
|
||||
var memory = NodeStats[context!.Id]!.Hardware.Memory;
|
||||
|
||||
|
||||
var used = memory.Total - (memory.Available + memory.Cached);
|
||||
var percent = Math.Round((float) used / memory.Total * 100F, 2);
|
||||
|
||||
var percent = Math.Round((float)used / memory.Total * 100F, 2);
|
||||
|
||||
//Logger.Debug($"Used: {used} Total: {memory.Total} => {percent}% ({Formatter.FormatSize(used)} / {Formatter.FormatSize(memory.Total)})");
|
||||
|
||||
<ColoredBar Value="percent"/>
|
||||
@@ -108,13 +112,7 @@
|
||||
</Template>
|
||||
</MCBColumn>
|
||||
</View>
|
||||
@*
|
||||
<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>
|
||||
</FastCrud>
|
||||
</LazyLoader>
|
||||
|
||||
@code
|
||||
@@ -126,78 +124,162 @@
|
||||
{
|
||||
UpdateTimer = new(async _ =>
|
||||
{
|
||||
NodeStats.Clear();
|
||||
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
var nodeRepo = scope.ServiceProvider.GetRequiredService<Repository<ServerNode>>();
|
||||
var nodes = nodeRepo.Get().ToArray();
|
||||
|
||||
foreach (var node in nodes)
|
||||
try
|
||||
{
|
||||
try
|
||||
NodeStats.Clear();
|
||||
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
var nodeRepo = scope.ServiceProvider.GetRequiredService<Repository<ServerNode>>();
|
||||
var nodes = nodeRepo.Get().ToArray();
|
||||
|
||||
foreach (var node in nodes)
|
||||
{
|
||||
var status = await NodeService.GetStatus(node);
|
||||
try
|
||||
{
|
||||
var status = await NodeService.GetStatus(node);
|
||||
|
||||
NodeStats[node.Id] = status;
|
||||
NodeStats[node.Id] = status;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogWarning("Unable to fetch system status for node '{name}': {e}", node.Name, e);
|
||||
|
||||
NodeStats[node.Id] = null;
|
||||
}
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogWarning("Unable to fetch system status for node '{name}': {e}", node.Name, e);
|
||||
|
||||
NodeStats[node.Id] = null;
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private IEnumerable<ServerNode> LoadData(Repository<ServerNode> repository)
|
||||
|
||||
private IEnumerable<ServerNode> Loader(Repository<ServerNode> repository)
|
||||
{
|
||||
return repository
|
||||
.Get();
|
||||
}
|
||||
|
||||
private Task ValidateDelete(ServerNode node)
|
||||
{
|
||||
if (ServerRepository
|
||||
.Get()
|
||||
.Any(x => x.Node.Id == node.Id))
|
||||
{
|
||||
throw new DisplayException("There are still servers on this node. Delete the servers in order to delete the node");
|
||||
}
|
||||
|
||||
if (NodeRepository
|
||||
.Get()
|
||||
.Include(x => x.Allocations)
|
||||
.First(x => x.Id == node.Id)
|
||||
.Allocations
|
||||
.Any())
|
||||
{
|
||||
throw new DisplayException("There are still allocations on this node. Delete the allocations in order to delete the node");
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
.Include(x => x.Allocations);
|
||||
}
|
||||
|
||||
private Task ValidateAdd(ServerNode node)
|
||||
private void OnConfigure(FastCrudConfiguration<ServerNode> configuration)
|
||||
{
|
||||
ValidateFqdn(node);
|
||||
configuration.ValidateDelete = node =>
|
||||
{
|
||||
if (ServerRepository
|
||||
.Get()
|
||||
.Any(x => x.Node.Id == node.Id))
|
||||
{
|
||||
throw new DisplayException("There are still servers on this node. Delete the servers in order to delete the node");
|
||||
}
|
||||
|
||||
node.Token = Formatter.GenerateString(32);
|
||||
if (NodeRepository
|
||||
.Get()
|
||||
.Include(x => x.Allocations)
|
||||
.First(x => x.Id == node.Id)
|
||||
.Allocations
|
||||
.Any())
|
||||
{
|
||||
throw new DisplayException("There are still allocations on this node. Delete the allocations in order to delete the node");
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
configuration.ValidateCreate = node =>
|
||||
{
|
||||
ValidateFqdn(node);
|
||||
|
||||
node.Token = Formatter.GenerateString(32);
|
||||
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
configuration.ValidateEdit = node =>
|
||||
{
|
||||
ValidateFqdn(node);
|
||||
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
}
|
||||
|
||||
private Task ValidateUpdate(ServerNode node)
|
||||
private void OnConfigureCreate(FastConfiguration<ServerNode> configuration)
|
||||
{
|
||||
ValidateFqdn(node);
|
||||
configuration.AddProperty(x => x.Name)
|
||||
.WithDefaultComponent()
|
||||
.WithValidation(FastValidators.Required);
|
||||
|
||||
return Task.CompletedTask;
|
||||
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)
|
||||
{
|
||||
if (node.Ssl)
|
||||
@@ -213,7 +295,7 @@
|
||||
// Is it a valid domain?
|
||||
if (Regex.IsMatch(node.Fqdn, "^(?!-)(?:[a-zA-Z\\d-]{0,62}[a-zA-Z\\d]\\.)+(?:[a-zA-Z]{2,})$"))
|
||||
return;
|
||||
|
||||
|
||||
// Is it a valid ip?
|
||||
if (Regex.IsMatch(node.Fqdn, "^(?:(?: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]?)$"))
|
||||
return;
|
||||
@@ -221,7 +303,7 @@
|
||||
throw new DisplayException("The fqdn needs to be either a domain or an ip");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
UpdateTimer?.Dispose();
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
|
||||
private void OnConfigure(FastCrudConfiguration<ServerNetwork> configuration)
|
||||
{
|
||||
configuration.ValidateCreate += network =>
|
||||
configuration.ValidateCreate = network =>
|
||||
{
|
||||
if (!ServerRepository
|
||||
.Get()
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<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="QRCoder" Version="1.4.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.6.2" />
|
||||
|
||||
Reference in New Issue
Block a user