Removed old typeahead. Added own solution. Lang file, notes

This commit is contained in:
Marcel Baumgartner
2023-04-10 03:40:08 +02:00
parent 271f56e992
commit 4253f94f59
13 changed files with 394 additions and 328 deletions

View File

@@ -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;

View 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; }
}

View 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; }
}

View 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; }
}

View File

@@ -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>

View File

@@ -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>

View 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;
}
}
}

View File

@@ -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();
} }
} }
} }

View File

@@ -1,19 +1,22 @@
@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">
<SmartForm Model="Model" OnValidSubmit="Add">
<label class="form-label"> <label class="form-label">
<TL>Domain name</TL> <TL>Domain name</TL>
</label> </label>
@@ -21,46 +24,28 @@
<span class="input-group-text"> <span class="input-group-text">
<i class="bx bx-purchase-tag-alt"></i> <i class="bx bx-purchase-tag-alt"></i>
</span> </span>
<input @bind="Name" type="text" class="form-control" placeholder="@(SmartTranslateService.Translate("Server name"))" aria-label="Servername"> <InputText @bind-Value="Model.Name" class="form-control" placeholder="@(SmartTranslateService.Translate("Domain name"))"></InputText>
</div> </div>
<div class="mb-5"> <div class="mb-5">
<label class="form-label"> <label class="form-label">
<TL>Shared domain</TL> <TL>Shared domain</TL>
</label> </label>
<select @bind="SharedDomainId" class="form-select"> <SmartSelect @bind-Value="Model.SharedDomain"
@if (SharedDomains.Any()) Items="SharedDomains"
{ DisplayField="@(x => x.Name)">
foreach (var sharedDomain in SharedDomains) </SmartSelect>
{
<option value="@(sharedDomain.Id)">@(sharedDomain.Name)</option>
}
}
else
{
<option value="">
<TL>No shared domains available</TL>
</option>
}
</select>
</div> </div>
<div class="input-group mb-5"> <div class="input-group mb-5">
<div class="form-select"> <SmartDropdown @bind-Value="Model.Owner"
<BlazoredTypeahead SearchMethod="SearchUsers" Items="Users"
@bind-Value="User"> DisplayFunc="@(x => x.Email)"
<SelectedTemplate> SearchProp="@(x => x.Email)">
@(context.Email) </SmartDropdown>
</SelectedTemplate>
<ResultTemplate>
@(context.Email)
</ResultTemplate>
</BlazoredTypeahead>
</div> </div>
</div> <button class="btn btn-success" type="submit">
<WButton Text="@(SmartTranslateService.Translate("Add"))" <TL>Create</TL>
WorkingText="@(SmartTranslateService.Translate("Adding"))" </button>
CssClasses="btn-success" </SmartForm>
OnClick="Add">
</WButton>
</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;
} }

View File

@@ -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,6 +19,7 @@
<OnlyAdmin> <OnlyAdmin>
<LazyLoader Load="Load"> <LazyLoader Load="Load">
<SmartForm Model="Model" OnValidSubmit="Create">
<div class="row mb-5"> <div class="row mb-5">
<div class="card card-body p-10"> <div class="card card-body p-10">
<label class="form-label"> <label class="form-label">
@@ -28,23 +29,18 @@
<span class="input-group-text"> <span class="input-group-text">
<i class="bx bx-purchase-tag-alt"></i> <i class="bx bx-purchase-tag-alt"></i>
</span> </span>
<input @bind="Name" type="text" class="form-control" placeholder="@(SmartTranslateService.Translate("Server name"))" aria-label="Servername"> <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>Server name</TL> <TL>Owner</TL>
</label> </label>
<div class="input-group mb-5"> <div class="input-group mb-5">
<div class="form-select"> <SmartDropdown
<BlazoredTypeahead SearchMethod="SearchUsers" @bind-Value="Model.Owner"
@bind-Value="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> </div>
</div> </div>
@@ -57,7 +53,7 @@
<span class="input-group-text"> <span class="input-group-text">
<i class="bx bx-chip"></i> <i class="bx bx-chip"></i>
</span> </span>
<input @bind="Cpu" type="number" class="form-control"> <InputNumber @bind-Value="Model.Cpu" class="form-control"></InputNumber>
<span class="input-group-text"> <span class="input-group-text">
<TL>CPU Cores (100% = 1 Core)</TL> <TL>CPU Cores (100% = 1 Core)</TL>
</span> </span>
@@ -69,7 +65,7 @@
<span class="input-group-text"> <span class="input-group-text">
<i class="bx bx-microchip"></i> <i class="bx bx-microchip"></i>
</span> </span>
<input @bind="Memory" type="number" class="form-control"> <InputNumber @bind-Value="Model.Memory" class="form-control"></InputNumber>
<span class="input-group-text"> <span class="input-group-text">
MB MB
</span> </span>
@@ -81,7 +77,7 @@
<span class="input-group-text"> <span class="input-group-text">
<i class="bx bx-hdd"></i> <i class="bx bx-hdd"></i>
</span> </span>
<input @bind="Disk" type="number" class="form-control"> <InputNumber @bind-Value="Model.Disk" class="form-control"></InputNumber>
<span class="input-group-text"> <span class="input-group-text">
MB MB
</span> </span>
@@ -93,13 +89,10 @@
<label class="form-label"> <label class="form-label">
<TL>Image</TL> <TL>Image</TL>
</label> </label>
<select @bind="ImageIndex" class="form-select mb-5"> <div class="mb-5">
@foreach (var image in Images) <SmartSelect TField="Image" @bind-Value="Model.Image" Items="Images" DisplayField="@(x => x.Name)" OnChange="OnChange"></SmartSelect>
{ </div>
<option value="@(Images.IndexOf(image))">@(image.Name)</option> @if (Model.Image != null)
}
</select>
@if (Image != null)
{ {
<label class="form-label"> <label class="form-label">
<TL>Override startup</TL> <TL>Override startup</TL>
@@ -108,33 +101,33 @@
<span class="input-group-text"> <span class="input-group-text">
<i class="bx bx-terminal"></i> <i class="bx bx-terminal"></i>
</span> </span>
<input @bind="OverrideStartup" type="text" class="form-control" placeholder="@(Image.Startup)"> <InputText @bind-Value="Model.OverrideStartup" type="text" class="form-control" placeholder="@(Model.Image.Startup)"></InputText>
</div> </div>
<label class="form-label"> <label class="form-label">
<TL>Docker image</TL> <TL>Docker image</TL>
</label> </label>
<select @bind="DockerImageIndex" class="form-select"> <InputSelect TValue="int" @bind-Value="Model.DockerImageIndex" class="form-control">
@foreach (var image in Image.DockerImages) @foreach (var image in Model.Image.DockerImages)
{ {
<option value="@(Image.DockerImages.IndexOf(image))">@(image.Name)</option> <option value="@(Model.Image.DockerImages.IndexOf(image))">@(image.Name)</option>
} }
</select> </InputSelect>
} }
</div> </div>
</div> </div>
<div class="row mb-5"> <div class="row mb-5">
<div class="card card-body"> <div class="card card-body">
@if (Image != null) @if (Model.Image != null)
{ {
<div class="mt-9 row d-flex"> <div class="mt-9 row d-flex">
@foreach (var vars in ServerVariables.Chunk(4)) @foreach (var vars in ServerVariables.Chunk(3))
{ {
<div class="row mb-3"> <div class="row row-cols-3 mb-3">
@foreach (var variable in vars) @foreach (var variable in vars)
{ {
<div class="col"> <div class="col">
<div class="card card-body"> <div class="card card-body border">
<label class="form-label"> <label class="form-label">
<TL>Name</TL> <TL>Name</TL>
</label> </label>
@@ -163,59 +156,33 @@
<a href="/admin/servers" class="btn btn-danger me-3"> <a href="/admin/servers" class="btn btn-danger me-3">
<TL>Cancel</TL> <TL>Cancel</TL>
</a> </a>
<WButton Text="@(SmartTranslateService.Translate("Create"))" <button class="btn btn-success" type="submit">
WorkingText="@(SmartTranslateService.Translate("Creating"))" <TL>Create</TL>
CssClasses="btn-success" </button>
OnClick="Create">
</WButton>
</div> </div>
</div> </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)
{
foreach (var variable in Model.Image.Variables)
{ {
list.Add(new() list.Add(new()
{ {
@@ -223,22 +190,11 @@
Value = variable.DefaultValue 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);
}
} }

View File

@@ -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)));
}
}
} }

View File

@@ -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;
}
} }

View File

@@ -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