Removed old typeahead. Added own solution. Lang file, notes
This commit is contained in:
@@ -46,7 +46,7 @@ public class WingsServerConverter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Build
|
// Build
|
||||||
wingsServer.Settings.Build.Swap = server.Memory * 2;
|
wingsServer.Settings.Build.Swap = server.Memory * 2; //TODO: Add config option
|
||||||
wingsServer.Settings.Build.Threads = null!;
|
wingsServer.Settings.Build.Threads = null!;
|
||||||
wingsServer.Settings.Build.Cpu_Limit = server.Cpu;
|
wingsServer.Settings.Build.Cpu_Limit = server.Cpu;
|
||||||
wingsServer.Settings.Build.Disk_Space = server.Disk;
|
wingsServer.Settings.Build.Disk_Space = server.Disk;
|
||||||
|
|||||||
18
Moonlight/App/Models/Forms/DomainDataModel.cs
Normal file
18
Moonlight/App/Models/Forms/DomainDataModel.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Forms;
|
||||||
|
|
||||||
|
public class DomainDataModel
|
||||||
|
{
|
||||||
|
[Required(ErrorMessage = "You need to specify a name")]
|
||||||
|
[MaxLength(32, ErrorMessage = "The max lenght for the name is 32 characters")]
|
||||||
|
[RegularExpression(@"^[a-z]+$", ErrorMessage = "The name should only consist of lower case characters")]
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "You need to specify a shared domain")]
|
||||||
|
public SharedDomain SharedDomain { get; set; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "You need to specify a owner")]
|
||||||
|
public User Owner { get; set; }
|
||||||
|
}
|
||||||
30
Moonlight/App/Models/Forms/ServerDataModel.cs
Normal file
30
Moonlight/App/Models/Forms/ServerDataModel.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Forms;
|
||||||
|
|
||||||
|
public class ServerDataModel
|
||||||
|
{
|
||||||
|
[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; }
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "You need to specify cpu amount")]
|
||||||
|
public int Cpu { get; set; } = 100;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "You need to specify a memory amount")]
|
||||||
|
public int Memory { get; set; } = 1024;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "You need to specify a disk amount")]
|
||||||
|
public int Disk { get; set; } = 1024;
|
||||||
|
|
||||||
|
[Required(ErrorMessage = "You need to specify a image")]
|
||||||
|
public Image Image { get; set; }
|
||||||
|
|
||||||
|
public string OverrideStartup { get; set; } = "";
|
||||||
|
|
||||||
|
public int DockerImageIndex { get; set; }
|
||||||
|
}
|
||||||
10
Moonlight/App/Models/Forms/TestDataModel.cs
Normal file
10
Moonlight/App/Models/Forms/TestDataModel.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Moonlight.App.Database.Entities;
|
||||||
|
|
||||||
|
namespace Moonlight.App.Models.Forms;
|
||||||
|
|
||||||
|
public class TestDataModel
|
||||||
|
{
|
||||||
|
[Required]
|
||||||
|
public User User { get; set; }
|
||||||
|
}
|
||||||
@@ -9,12 +9,10 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="aaPanelSharp" Version="1.0.0" />
|
|
||||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||||
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
<PackageReference Include="Ben.Demystifier" Version="0.4.1" />
|
||||||
<PackageReference Include="Blazor.ContextMenu" Version="1.15.0" />
|
<PackageReference Include="Blazor.ContextMenu" Version="1.15.0" />
|
||||||
<PackageReference Include="BlazorDownloadFile" Version="2.4.0.2" />
|
<PackageReference Include="BlazorDownloadFile" Version="2.4.0.2" />
|
||||||
<PackageReference Include="Blazored.Typeahead" Version="4.7.0" />
|
|
||||||
<PackageReference Include="BlazorMonaco" Version="2.1.0" />
|
<PackageReference Include="BlazorMonaco" Version="2.1.0" />
|
||||||
<PackageReference Include="BlazorTable" Version="1.17.0" />
|
<PackageReference Include="BlazorTable" Version="1.17.0" />
|
||||||
<PackageReference Include="CloudFlare.Client" Version="6.1.4" />
|
<PackageReference Include="CloudFlare.Client" Version="6.1.4" />
|
||||||
@@ -24,6 +22,7 @@
|
|||||||
<PackageReference Include="GravatarSharp.Core" Version="1.0.1.2" />
|
<PackageReference Include="GravatarSharp.Core" Version="1.0.1.2" />
|
||||||
<PackageReference Include="JWT" Version="10.0.2" />
|
<PackageReference Include="JWT" Version="10.0.2" />
|
||||||
<PackageReference Include="Logging.Net" Version="1.1.0" />
|
<PackageReference Include="Logging.Net" Version="1.1.0" />
|
||||||
|
<PackageReference Include="Mappy.Net" Version="1.0.2" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.3">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.3">
|
||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
|||||||
@@ -45,7 +45,6 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="/_content/XtermBlazor/XtermBlazor.css"/>
|
<link rel="stylesheet" type="text/css" href="/_content/XtermBlazor/XtermBlazor.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.css"/>
|
<link rel="stylesheet" type="text/css" href="/_content/BlazorMonaco/lib/monaco-editor/min/vs/editor/editor.main.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/_content/Blazor.ContextMenu/blazorContextMenu.min.css"/>
|
<link rel="stylesheet" type="text/css" href="/_content/Blazor.ContextMenu/blazorContextMenu.min.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/_content/Blazored.Typeahead/blazored-typeahead.css" />
|
|
||||||
|
|
||||||
<link href="/assets/plugins/global/plugins.bundle.css" rel="stylesheet" type="text/css"/>
|
<link href="/assets/plugins/global/plugins.bundle.css" rel="stylesheet" type="text/css"/>
|
||||||
|
|
||||||
@@ -87,7 +86,6 @@
|
|||||||
<script src="/_content/BlazorInputFile/inputfile.js"></script>
|
<script src="/_content/BlazorInputFile/inputfile.js"></script>
|
||||||
<script src="/_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js"></script>
|
<script src="/_content/CurrieTechnologies.Razor.SweetAlert2/sweetAlert2.min.js"></script>
|
||||||
<script src="/_content/Blazor.ContextMenu/blazorContextMenu.min.js"></script>
|
<script src="/_content/Blazor.ContextMenu/blazorContextMenu.min.js"></script>
|
||||||
<script src="/_content/Blazored.Typeahead/blazored-typeahead.js"></script>
|
|
||||||
|
|
||||||
<script src="https://www.google.com/recaptcha/api.js"></script>
|
<script src="https://www.google.com/recaptcha/api.js"></script>
|
||||||
|
|
||||||
|
|||||||
93
Moonlight/Shared/Components/Forms/SmartDropdown.razor
Normal file
93
Moonlight/Shared/Components/Forms/SmartDropdown.razor
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
@typeparam T
|
||||||
|
@using Logging.Net
|
||||||
|
@inherits InputBase<T>
|
||||||
|
|
||||||
|
<div class="dropdown w-100">
|
||||||
|
<div class="input-group">
|
||||||
|
@if (CurrentValue == null)
|
||||||
|
{
|
||||||
|
<input class="form-control" type="text" @bind-value="SearchTerm" @bind-value:event="oninput" placeholder="Search...">
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
<input class="form-control" type="text" value="@(DisplayFunc(CurrentValue))">
|
||||||
|
<button class="btn btn-primary" @onclick="() => SelectItem(default(T)!)">
|
||||||
|
<i class="bx bx-md bx-x"></i>
|
||||||
|
</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@{
|
||||||
|
var anyItems = FilteredItems.Any();
|
||||||
|
}
|
||||||
|
|
||||||
|
<div class="dropdown-menu w-100 @(anyItems ? "show" : "")" style="max-height: 200px; overflow-y: auto;">
|
||||||
|
@if (anyItems)
|
||||||
|
{
|
||||||
|
foreach (var item in FilteredItems)
|
||||||
|
{
|
||||||
|
<button class="dropdown-item py-2" type="button" @onclick="(() => SelectItem(item))">@DisplayFunc(item)</button>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public IEnumerable<T> Items { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Func<T, string> DisplayFunc { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Func<T, string> SearchProp { get; set; }
|
||||||
|
|
||||||
|
private string SearchTerm
|
||||||
|
{
|
||||||
|
get => searchTerm;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
FilteredItems = Items.Where(i => SearchProp(i).Contains(SearchTerm, StringComparison.OrdinalIgnoreCase)).ToList();
|
||||||
|
searchTerm = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string searchTerm = "";
|
||||||
|
|
||||||
|
private List<T> FilteredItems = new();
|
||||||
|
|
||||||
|
private void SelectItem(T item)
|
||||||
|
{
|
||||||
|
CurrentValue = item;
|
||||||
|
SearchTerm = "";
|
||||||
|
FilteredItems.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool TryParseValueFromString(string? value, out T result, out string? validationErrorMessage)
|
||||||
|
{
|
||||||
|
// Check if the value is null or empty
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
result = default(T)!;
|
||||||
|
validationErrorMessage = "Value cannot be null or empty";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find an item that matches the search term
|
||||||
|
var item = FilteredItems.FirstOrDefault(i => SearchProp(i).Equals(value, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (item != null)
|
||||||
|
{
|
||||||
|
result = item;
|
||||||
|
validationErrorMessage = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = default(T)!;
|
||||||
|
validationErrorMessage = $"No item found for search term '{value}'";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -11,11 +11,14 @@
|
|||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public TField[] Items { get; set; }
|
public IEnumerable<TField> Items { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public Func<TField, string> DisplayField { get; set; }
|
public Func<TField, string> DisplayField { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public Func<Task>? OnChange { get; set; }
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -53,6 +56,7 @@
|
|||||||
{
|
{
|
||||||
Value = i;
|
Value = i;
|
||||||
ValueChanged.InvokeAsync(i);
|
ValueChanged.InvokeAsync(i);
|
||||||
|
OnChange?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +1,51 @@
|
|||||||
@page "/admin/domains/new"
|
@page "/admin/domains/new"
|
||||||
@using Moonlight.App.Services
|
@using Moonlight.App.Services
|
||||||
@using Moonlight.App.Database.Entities
|
@using Moonlight.App.Database.Entities
|
||||||
@using Blazored.Typeahead
|
@using Moonlight.App.Models.Forms
|
||||||
@using Moonlight.App.Repositories
|
@using Moonlight.App.Repositories
|
||||||
@using Moonlight.App.Repositories.Domains
|
@using Moonlight.App.Repositories.Domains
|
||||||
|
@using Mappy.Net
|
||||||
|
|
||||||
@inject SmartTranslateService SmartTranslateService
|
@inject SmartTranslateService SmartTranslateService
|
||||||
@inject SharedDomainRepository SharedDomainRepository
|
@inject SharedDomainRepository SharedDomainRepository
|
||||||
@inject DomainRepository DomainRepository
|
@inject DomainRepository DomainRepository
|
||||||
@inject UserRepository UserRepository
|
@inject UserRepository UserRepository
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
|
||||||
<OnlyAdmin>
|
<OnlyAdmin>
|
||||||
<div class="row mb-5">
|
<div class="row mb-5">
|
||||||
<div class="card card-body p-10">
|
<div class="card card-body p-10">
|
||||||
<LazyLoader Load="Load">
|
<LazyLoader Load="Load">
|
||||||
<label class="form-label">
|
<SmartForm Model="Model" OnValidSubmit="Add">
|
||||||
<TL>Domain name</TL>
|
|
||||||
</label>
|
|
||||||
<div class="input-group mb-5">
|
|
||||||
<span class="input-group-text">
|
|
||||||
<i class="bx bx-purchase-tag-alt"></i>
|
|
||||||
</span>
|
|
||||||
<input @bind="Name" type="text" class="form-control" placeholder="@(SmartTranslateService.Translate("Server name"))" aria-label="Servername">
|
|
||||||
</div>
|
|
||||||
<div class="mb-5">
|
|
||||||
<label class="form-label">
|
<label class="form-label">
|
||||||
<TL>Shared domain</TL>
|
<TL>Domain name</TL>
|
||||||
</label>
|
</label>
|
||||||
<select @bind="SharedDomainId" class="form-select">
|
<div class="input-group mb-5">
|
||||||
@if (SharedDomains.Any())
|
<span class="input-group-text">
|
||||||
{
|
<i class="bx bx-purchase-tag-alt"></i>
|
||||||
foreach (var sharedDomain in SharedDomains)
|
</span>
|
||||||
{
|
<InputText @bind-Value="Model.Name" class="form-control" placeholder="@(SmartTranslateService.Translate("Domain name"))"></InputText>
|
||||||
<option value="@(sharedDomain.Id)">@(sharedDomain.Name)</option>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
<option value="">
|
|
||||||
<TL>No shared domains available</TL>
|
|
||||||
</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="input-group mb-5">
|
|
||||||
<div class="form-select">
|
|
||||||
<BlazoredTypeahead SearchMethod="SearchUsers"
|
|
||||||
@bind-Value="User">
|
|
||||||
<SelectedTemplate>
|
|
||||||
@(context.Email)
|
|
||||||
</SelectedTemplate>
|
|
||||||
<ResultTemplate>
|
|
||||||
@(context.Email)
|
|
||||||
</ResultTemplate>
|
|
||||||
</BlazoredTypeahead>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="mb-5">
|
||||||
<WButton Text="@(SmartTranslateService.Translate("Add"))"
|
<label class="form-label">
|
||||||
WorkingText="@(SmartTranslateService.Translate("Adding"))"
|
<TL>Shared domain</TL>
|
||||||
CssClasses="btn-success"
|
</label>
|
||||||
OnClick="Add">
|
<SmartSelect @bind-Value="Model.SharedDomain"
|
||||||
</WButton>
|
Items="SharedDomains"
|
||||||
|
DisplayField="@(x => x.Name)">
|
||||||
|
</SmartSelect>
|
||||||
|
</div>
|
||||||
|
<div class="input-group mb-5">
|
||||||
|
<SmartDropdown @bind-Value="Model.Owner"
|
||||||
|
Items="Users"
|
||||||
|
DisplayFunc="@(x => x.Email)"
|
||||||
|
SearchProp="@(x => x.Email)">
|
||||||
|
</SmartDropdown>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-success" type="submit">
|
||||||
|
<TL>Create</TL>
|
||||||
|
</button>
|
||||||
|
</SmartForm>
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -68,53 +53,26 @@
|
|||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
private string Name;
|
private DomainDataModel Model = new();
|
||||||
|
|
||||||
private User? User;
|
|
||||||
private User[] Users;
|
private User[] Users;
|
||||||
|
private SharedDomain[] SharedDomains;
|
||||||
private List<SharedDomain> SharedDomains;
|
|
||||||
|
|
||||||
private SharedDomain? SharedDomain;
|
|
||||||
|
|
||||||
private int SharedDomainId
|
|
||||||
{
|
|
||||||
get => SharedDomain?.Id ?? -1;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
SharedDomain = SharedDomains.FirstOrDefault(x => x.Id == value);
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<IEnumerable<User>> SearchUsers(string input)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(input))
|
|
||||||
{
|
|
||||||
return Task.FromResult(Array.Empty<User>().Cast<User>());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Task.FromResult(Users.Where(x => x.Email.ToLower().StartsWith(input)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task Load(LazyLoader lazyLoader)
|
private Task Load(LazyLoader lazyLoader)
|
||||||
{
|
{
|
||||||
Users = UserRepository.Get().ToArray();
|
Users = UserRepository.Get().ToArray();
|
||||||
SharedDomains = SharedDomainRepository.Get().ToList();
|
SharedDomains = SharedDomainRepository.Get().ToArray();
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task Add()
|
private Task Add()
|
||||||
{
|
{
|
||||||
DomainRepository.Add(new()
|
var domain = Mapper.Map<Domain>(Model);
|
||||||
{
|
|
||||||
Name = Name.ToLower(),
|
DomainRepository.Add(domain);
|
||||||
Owner = User!,
|
|
||||||
SharedDomain = SharedDomain!
|
NavigationManager.NavigateTo("/admin/domains");
|
||||||
});
|
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
@using Moonlight.App.Exceptions
|
@using Moonlight.App.Exceptions
|
||||||
@using Moonlight.App.Services.Interop
|
@using Moonlight.App.Services.Interop
|
||||||
@using Logging.Net
|
@using Logging.Net
|
||||||
@using Blazored.Typeahead
|
@using Moonlight.App.Models.Forms
|
||||||
|
|
||||||
@inject NodeRepository NodeRepository
|
@inject NodeRepository NodeRepository
|
||||||
@inject ImageRepository ImageRepository
|
@inject ImageRepository ImageRepository
|
||||||
@@ -19,226 +19,182 @@
|
|||||||
|
|
||||||
<OnlyAdmin>
|
<OnlyAdmin>
|
||||||
<LazyLoader Load="Load">
|
<LazyLoader Load="Load">
|
||||||
<div class="row mb-5">
|
<SmartForm Model="Model" OnValidSubmit="Create">
|
||||||
<div class="card card-body p-10">
|
<div class="row mb-5">
|
||||||
<label class="form-label">
|
<div class="card card-body p-10">
|
||||||
<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>
|
|
||||||
<input @bind="Name" type="text" class="form-control" placeholder="@(SmartTranslateService.Translate("Server name"))" aria-label="Servername">
|
|
||||||
</div>
|
|
||||||
<label class="form-label">
|
|
||||||
<TL>Server name</TL>
|
|
||||||
</label>
|
|
||||||
<div class="input-group mb-5">
|
|
||||||
<div class="form-select">
|
|
||||||
<BlazoredTypeahead SearchMethod="SearchUsers"
|
|
||||||
@bind-Value="User">
|
|
||||||
<SelectedTemplate>
|
|
||||||
@(context.Email)
|
|
||||||
</SelectedTemplate>
|
|
||||||
<ResultTemplate>
|
|
||||||
@(context.Email)
|
|
||||||
</ResultTemplate>
|
|
||||||
</BlazoredTypeahead>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-5">
|
|
||||||
<div class="card 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>
|
|
||||||
<input @bind="Cpu" type="number" class="form-control">
|
|
||||||
<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>
|
|
||||||
<input @bind="Memory" type="number" class="form-control">
|
|
||||||
<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>
|
|
||||||
<input @bind="Disk" type="number" class="form-control">
|
|
||||||
<span class="input-group-text">
|
|
||||||
MB
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-5">
|
|
||||||
<div class="card card-body p-10">
|
|
||||||
<label class="form-label">
|
|
||||||
<TL>Image</TL>
|
|
||||||
</label>
|
|
||||||
<select @bind="ImageIndex" class="form-select mb-5">
|
|
||||||
@foreach (var image in Images)
|
|
||||||
{
|
|
||||||
<option value="@(Images.IndexOf(image))">@(image.Name)</option>
|
|
||||||
}
|
|
||||||
</select>
|
|
||||||
@if (Image != null)
|
|
||||||
{
|
|
||||||
<label class="form-label">
|
<label class="form-label">
|
||||||
<TL>Override startup</TL>
|
<TL>Server name</TL>
|
||||||
</label>
|
</label>
|
||||||
<div class="input-group mb-5">
|
<div class="input-group mb-5">
|
||||||
<span class="input-group-text">
|
<span class="input-group-text">
|
||||||
<i class="bx bx-terminal"></i>
|
<i class="bx bx-purchase-tag-alt"></i>
|
||||||
</span>
|
</span>
|
||||||
<input @bind="OverrideStartup" type="text" class="form-control" placeholder="@(Image.Startup)">
|
<InputText @bind-Value="Model.Name" type="text" class="form-control" placeholder="@(SmartTranslateService.Translate("Server name"))"></InputText>
|
||||||
</div>
|
</div>
|
||||||
<label class="form-label">
|
<label class="form-label">
|
||||||
<TL>Docker image</TL>
|
<TL>Owner</TL>
|
||||||
</label>
|
</label>
|
||||||
<select @bind="DockerImageIndex" class="form-select">
|
<div class="input-group mb-5">
|
||||||
@foreach (var image in Image.DockerImages)
|
<SmartDropdown
|
||||||
{
|
@bind-Value="Model.Owner"
|
||||||
<option value="@(Image.DockerImages.IndexOf(image))">@(image.Name)</option>
|
Items="Users"
|
||||||
}
|
DisplayFunc="@(x => x.Email)"
|
||||||
</select>
|
SearchProp="@(x => x.Email)">
|
||||||
}
|
</SmartDropdown>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row mb-5">
|
|
||||||
<div class="card card-body">
|
|
||||||
@if (Image != null)
|
|
||||||
{
|
|
||||||
<div class="mt-9 row d-flex">
|
|
||||||
@foreach (var vars in ServerVariables.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>
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="card card-body">
|
|
||||||
<div class="d-flex justify-content-end">
|
|
||||||
<a href="/admin/servers" class="btn btn-danger me-3">
|
|
||||||
<TL>Cancel</TL>
|
|
||||||
</a>
|
|
||||||
<WButton Text="@(SmartTranslateService.Translate("Create"))"
|
|
||||||
WorkingText="@(SmartTranslateService.Translate("Creating"))"
|
|
||||||
CssClasses="btn-success"
|
|
||||||
OnClick="Create">
|
|
||||||
</WButton>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="row mb-5">
|
||||||
|
<div class="card 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" 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" 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" class="form-control"></InputNumber>
|
||||||
|
<span class="input-group-text">
|
||||||
|
MB
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-5">
|
||||||
|
<div class="card card-body p-10">
|
||||||
|
<label class="form-label">
|
||||||
|
<TL>Image</TL>
|
||||||
|
</label>
|
||||||
|
<div class="mb-5">
|
||||||
|
<SmartSelect TField="Image" @bind-Value="Model.Image" Items="Images" DisplayField="@(x => x.Name)" OnChange="OnChange"></SmartSelect>
|
||||||
|
</div>
|
||||||
|
@if (Model.Image != null)
|
||||||
|
{
|
||||||
|
<label class="form-label">
|
||||||
|
<TL>Override startup</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="@(Model.Image.Startup)"></InputText>
|
||||||
|
</div>
|
||||||
|
<label class="form-label">
|
||||||
|
<TL>Docker image</TL>
|
||||||
|
</label>
|
||||||
|
<InputSelect TValue="int" @bind-Value="Model.DockerImageIndex" class="form-control">
|
||||||
|
@foreach (var image in Model.Image.DockerImages)
|
||||||
|
{
|
||||||
|
<option value="@(Model.Image.DockerImages.IndexOf(image))">@(image.Name)</option>
|
||||||
|
}
|
||||||
|
</InputSelect>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mb-5">
|
||||||
|
<div class="card card-body">
|
||||||
|
@if (Model.Image != null)
|
||||||
|
{
|
||||||
|
<div class="mt-9 row d-flex">
|
||||||
|
@foreach (var vars in ServerVariables.Chunk(3))
|
||||||
|
{
|
||||||
|
<div class="row row-cols-3 mb-3">
|
||||||
|
@foreach (var variable in vars)
|
||||||
|
{
|
||||||
|
<div class="col">
|
||||||
|
<div class="card card-body border">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="card card-body">
|
||||||
|
<div class="d-flex justify-content-end">
|
||||||
|
<a href="/admin/servers" class="btn btn-danger me-3">
|
||||||
|
<TL>Cancel</TL>
|
||||||
|
</a>
|
||||||
|
<button class="btn btn-success" type="submit">
|
||||||
|
<TL>Create</TL>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</SmartForm>
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
</OnlyAdmin>
|
</OnlyAdmin>
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
|
private ServerDataModel Model = new();
|
||||||
|
|
||||||
private List<Image> Images;
|
private List<Image> Images;
|
||||||
private Node[] Nodes;
|
private Node[] Nodes;
|
||||||
private User[] Users;
|
private User[] Users;
|
||||||
|
|
||||||
private string Name = "";
|
|
||||||
|
|
||||||
private int Cpu = 100;
|
|
||||||
private int Memory = 4096;
|
|
||||||
private int Disk = 10240;
|
|
||||||
|
|
||||||
private string OverrideStartup = "";
|
|
||||||
private int DockerImageIndex = 0;
|
|
||||||
|
|
||||||
private Image? Image;
|
|
||||||
private User? User;
|
|
||||||
|
|
||||||
private ServerVariable[] ServerVariables = Array.Empty<ServerVariable>();
|
private ServerVariable[] ServerVariables = Array.Empty<ServerVariable>();
|
||||||
|
|
||||||
private int ImageIndex
|
|
||||||
{
|
|
||||||
get => Image == null ? 0 : Images.IndexOf(Image);
|
|
||||||
set
|
|
||||||
{
|
|
||||||
Image = Images[value];
|
|
||||||
|
|
||||||
if (Image == null)
|
|
||||||
ServerVariables = Array.Empty<ServerVariable>();
|
|
||||||
else
|
|
||||||
RebuildVariables();
|
|
||||||
|
|
||||||
|
|
||||||
InvokeAsync(StateHasChanged);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RebuildVariables()
|
private void RebuildVariables()
|
||||||
{
|
{
|
||||||
var list = new List<ServerVariable>();
|
var list = new List<ServerVariable>();
|
||||||
|
|
||||||
foreach (var variable in Image.Variables)
|
if (Model.Image != null)
|
||||||
{
|
{
|
||||||
list.Add(new()
|
foreach (var variable in Model.Image.Variables)
|
||||||
{
|
{
|
||||||
Key = variable.Key,
|
list.Add(new()
|
||||||
Value = variable.DefaultValue
|
{
|
||||||
});
|
Key = variable.Key,
|
||||||
|
Value = variable.DefaultValue
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerVariables = list.ToArray();
|
ServerVariables = list.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task<IEnumerable<User>> SearchUsers(string input)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(input))
|
|
||||||
{
|
|
||||||
return Task.FromResult(Array.Empty<User>().Cast<User>());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Task.FromResult(Users.Where(x => x.Email.ToLower().StartsWith(input)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Load(LazyLoader lazyLoader)
|
private async Task Load(LazyLoader lazyLoader)
|
||||||
{
|
{
|
||||||
await lazyLoader.SetText("Loading images");
|
await lazyLoader.SetText("Loading images");
|
||||||
@@ -256,24 +212,18 @@
|
|||||||
await lazyLoader.SetText("Loading users");
|
await lazyLoader.SetText("Loading users");
|
||||||
|
|
||||||
Users = UserRepository.Get().ToArray();
|
Users = UserRepository.Get().ToArray();
|
||||||
User = Users.FirstOrDefault();
|
|
||||||
|
|
||||||
Image = Images.FirstOrDefault();
|
|
||||||
|
|
||||||
RebuildVariables();
|
RebuildVariables();
|
||||||
|
|
||||||
if (Image != null)
|
|
||||||
DockerImageIndex = Image.DockerImages.Count - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Create()
|
private async Task Create()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await ServerService.Create(Name, Cpu, Memory, Disk, User, Image, null, server =>
|
await ServerService.Create(Model.Name, Model.Cpu, Model.Memory, Model.Disk, Model.Owner, Model.Image, null, server =>
|
||||||
{
|
{
|
||||||
server.OverrideStartup = OverrideStartup;
|
server.OverrideStartup = Model.OverrideStartup;
|
||||||
server.DockerImageIndex = DockerImageIndex;
|
server.DockerImageIndex = Model.DockerImageIndex;
|
||||||
|
|
||||||
foreach (var serverVariable in ServerVariables)
|
foreach (var serverVariable in ServerVariables)
|
||||||
{
|
{
|
||||||
@@ -303,4 +253,10 @@
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task OnChange()
|
||||||
|
{
|
||||||
|
RebuildVariables();
|
||||||
|
await InvokeAsync(StateHasChanged);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
@using Moonlight.App.Models.Forms
|
@using Moonlight.App.Models.Forms
|
||||||
@using Moonlight.App.Services
|
@using Moonlight.App.Services
|
||||||
@using Blazored.Typeahead
|
|
||||||
@using Moonlight.App.Database.Entities
|
@using Moonlight.App.Database.Entities
|
||||||
@using Moonlight.App.Repositories
|
@using Moonlight.App.Repositories
|
||||||
|
|
||||||
@@ -24,15 +23,11 @@
|
|||||||
<TL>Owner</TL>
|
<TL>Owner</TL>
|
||||||
</label>
|
</label>
|
||||||
<div class="input-group mb-5">
|
<div class="input-group mb-5">
|
||||||
<BlazoredTypeahead SearchMethod="SearchUsers"
|
<SmartDropdown @bind-Value="Model.User"
|
||||||
@bind-Value="Model.User">
|
Items="Users"
|
||||||
<SelectedTemplate>
|
DisplayFunc="@(x => x.Email)"
|
||||||
@(context.Email)
|
SearchProp="@(x => x.Email)">
|
||||||
</SelectedTemplate>
|
</SmartDropdown>
|
||||||
<ResultTemplate>
|
|
||||||
@(context.Email)
|
|
||||||
</ResultTemplate>
|
|
||||||
</BlazoredTypeahead>
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button type="submit" class="btn btn-primary float-end">
|
<button type="submit" class="btn btn-primary float-end">
|
||||||
@@ -64,16 +59,4 @@
|
|||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task<IEnumerable<User>> SearchUsers(string input)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(input))
|
|
||||||
{
|
|
||||||
return Task.FromResult(Array.Empty<User>().Cast<User>());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return Task.FromResult(Users.Where(x => x.Email.ToLower().StartsWith(input)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -1,34 +1,39 @@
|
|||||||
@page "/test"
|
@page "/test"
|
||||||
|
@using Moonlight.App.Repositories
|
||||||
|
@using Moonlight.App.Database.Entities
|
||||||
|
@using Moonlight.App.Models.Forms
|
||||||
|
|
||||||
@using Moonlight.Shared.Components.FileManagerPartials
|
@inject UserRepository UserRepository
|
||||||
@using Moonlight.App.Repositories.Servers
|
|
||||||
@using Moonlight.App.Helpers.Files
|
|
||||||
@using Microsoft.EntityFrameworkCore
|
|
||||||
@using Moonlight.App.Helpers
|
|
||||||
@using Moonlight.App.Services
|
|
||||||
@using User = Moonlight.App.Database.Entities.User
|
|
||||||
|
|
||||||
@inject ServerRepository ServerRepository
|
|
||||||
@inject WingsApiHelper WingsApiHelper
|
|
||||||
@inject WingsJwtHelper WingsJwtHelper
|
|
||||||
@inject ConfigService ConfigService
|
|
||||||
|
|
||||||
<LazyLoader Load="Load">
|
<LazyLoader Load="Load">
|
||||||
<FileManager Access="FileAccess">
|
<SmartForm Model="Model" OnValidSubmit="OnValidSubmit">
|
||||||
</FileManager>
|
<div class="mb-3">
|
||||||
|
<SmartDropdown
|
||||||
|
Items="Users"
|
||||||
|
@bind-Value="Model.User"
|
||||||
|
DisplayFunc="@(x => x.Email)"
|
||||||
|
SearchProp="@(x => x.Email)" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-primary" type="submit">Submit</button>
|
||||||
|
</div>
|
||||||
|
</SmartForm>
|
||||||
</LazyLoader>
|
</LazyLoader>
|
||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
[CascadingParameter]
|
private User[] Users;
|
||||||
public User User { get; set; }
|
private TestDataModel Model = new();
|
||||||
|
|
||||||
private FileAccess FileAccess;
|
|
||||||
|
|
||||||
private Task Load(LazyLoader arg)
|
private Task Load(LazyLoader arg)
|
||||||
{
|
{
|
||||||
FileAccess = new FtpFileAccess("vps01.so.host.endelon.link", 21, "example.com", "61P8JZzfjSNyhtZl");
|
Users = UserRepository.Get().ToArray();
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task OnValidSubmit()
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -513,3 +513,15 @@ Error from plesk;Error from plesk
|
|||||||
Host;Host
|
Host;Host
|
||||||
Username;Username
|
Username;Username
|
||||||
SRV records cannot be updated thanks to the cloudflare api client. Please delete the record and create a new one;SRV records cannot be updated thanks to the cloudflare api client. Please delete the record and create a new one
|
SRV records cannot be updated thanks to the cloudflare api client. Please delete the record and create a new one;SRV records cannot be updated thanks to the cloudflare api client. Please delete the record and create a new one
|
||||||
|
The User field is required.;The User field is required.
|
||||||
|
You need to specify a owner;You need to specify a owner
|
||||||
|
You need to specify a image;You need to specify a image
|
||||||
|
Api Url;Api Url
|
||||||
|
Api Key;Api Key
|
||||||
|
Duration;Duration
|
||||||
|
Enter duration of subscription;Enter duration of subscription
|
||||||
|
Copied code to clipboard;Copied code to clipboard
|
||||||
|
Invalid or expired subscription code;Invalid or expired subscription code
|
||||||
|
Current subscription;Current subscription
|
||||||
|
You need to specify a server image;You need to specify a server image
|
||||||
|
CPU;CPU
|
||||||
|
|||||||
Reference in New Issue
Block a user