Improved image editor and added more options

This commit is contained in:
Marcel Baumgartner 2024-01-29 17:17:42 +01:00
parent 4e5124cc1b
commit aaee81e9c4
13 changed files with 1282 additions and 18 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Moonlight.Core.Database.Migrations
{
/// <inheritdoc />
public partial class AddedAllowUserToChangeDockerImage : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "AllowUserToChangeDockerImage",
table: "ServerImages",
type: "INTEGER",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "AllowUserToChangeDockerImage",
table: "ServerImages");
}
}
}

View file

@ -275,6 +275,9 @@ namespace Moonlight.Core.Database.Migrations
b.Property<int>("AllocationsNeeded") b.Property<int>("AllocationsNeeded")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<bool>("AllowUserToChangeDockerImage")
.HasColumnType("INTEGER");
b.Property<string>("Author") b.Property<string>("Author")
.IsRequired() .IsRequired()
.HasColumnType("TEXT"); .HasColumnType("TEXT");

View file

@ -22,5 +22,6 @@ public class ServerImage
public List<ServerImageVariable> Variables { get; set; } = new(); public List<ServerImageVariable> Variables { get; set; } = new();
public int DefaultDockerImageIndex { get; set; } = 0; public int DefaultDockerImageIndex { get; set; } = 0;
public bool AllowUserToChangeDockerImage { get; set; }
public List<ServerDockerImage> DockerImages { get; set; } public List<ServerDockerImage> DockerImages { get; set; }
} }

View file

@ -0,0 +1,27 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace Moonlight.Features.Servers.Models.Forms.Admin.Images;
public class CreateImageVariable
{
[Required(ErrorMessage = "You need to specify a key")]
[Description("This is the environment variable name")]
public string Key { get; set; }
[Description("This is the default value which will be set when a server is created")]
public string DefaultValue { get; set; } = "";
[Required(ErrorMessage = "You need to specify a display name")]
[Description("This is the display name of the variable which will be shown to the user if enabled to edit/view the variable")]
public string DisplayName { get; set; }
[Description("This text should describe what the variable does for the user if allowed to view and/or change")]
public string Description { get; set; } = "";
[Description("Allow the user to edit the variable. Wont work if view is disabled")]
public bool AllowUserToEdit { get; set; } = false;
[Description("Allow the user to view the variable but not edit it unless specified otherwise")]
public bool AllowUserToView { get; set; } = false;
}

View file

@ -0,0 +1,27 @@
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace Moonlight.Features.Servers.Models.Forms.Admin.Images;
public class UpdateImageVariable
{
[Required(ErrorMessage = "You need to specify a key")]
[Description("This is the environment variable name")]
public string Key { get; set; }
[Description("This is the default value which will be set when a server is created")]
public string DefaultValue { get; set; } = "";
[Required(ErrorMessage = "You need to specify a display name")]
[Description("This is the display name of the variable which will be shown to the user if enabled to edit/view the variable")]
public string DisplayName { get; set; }
[Description("This text should describe what the variable does for the user if allowed to view and/or change")]
public string Description { get; set; } = "";
[Description("Allow the user to edit the variable. Wont work if view is disabled")]
public bool AllowUserToEdit { get; set; } = false;
[Description("Allow the user to view the variable but not edit it unless specified otherwise")]
public bool AllowUserToView { get; set; } = false;
}

View file

@ -2,9 +2,12 @@
@using Moonlight.Features.Servers.Entities @using Moonlight.Features.Servers.Entities
@using Moonlight.Core.Repositories @using Moonlight.Core.Repositories
@using Moonlight.Core.Services.Interop
@using Moonlight.Features.Servers.UI.Components @using Moonlight.Features.Servers.UI.Components
@using Moonlight.Core.Exceptions
@inject Repository<ServerImage> ImageRepository @inject Repository<ServerImage> ImageRepository
@inject ToastService ToastService
<LazyLoader ShowAsCard="true" Load="Load"> <LazyLoader ShowAsCard="true" Load="Load">
@if (Image == null) @if (Image == null)
@ -14,6 +17,14 @@
else else
{ {
<AdminImageViewNavigation Index="2" ImageId="@Id" /> <AdminImageViewNavigation Index="2" ImageId="@Id" />
<ParseConfigEditor @ref="ParseConfigEditor" InitialContent="@Image.ParseConfigurations" />
<div class="card card-body mt-5">
<div class="d-flex justify-content-end">
<WButton Text="Save" CssClasses="btn btn-success" OnClick="OnSave" />
</div>
</div>
} }
</LazyLoader> </LazyLoader>
@ -24,6 +35,8 @@
private ServerImage? Image; private ServerImage? Image;
private ParseConfigEditor ParseConfigEditor;
private Task Load(LazyLoader arg) private Task Load(LazyLoader arg)
{ {
Image = ImageRepository Image = ImageRepository
@ -32,4 +45,19 @@
return Task.CompletedTask; return Task.CompletedTask;
} }
private async Task OnSave()
{
try
{
Image!.ParseConfigurations = await ParseConfigEditor.ValidateAndGet();
ImageRepository.Update(Image);
await ToastService.Success("Successfully updated image");
}
catch (DisplayException e)
{
await ToastService.Danger(e.Message);
}
}
} }

View file

@ -29,7 +29,7 @@
</div> </div>
<div class="card-footer"> <div class="card-footer">
<div class="d-flex justify-content-end"> <div class="d-flex justify-content-end">
<button type="submit" class="btn btn-success">Create</button> <button type="submit" class="btn btn-success">Save</button>
</div> </div>
</div> </div>
</SmartForm> </SmartForm>

View file

@ -6,18 +6,45 @@
@using Moonlight.Features.Servers.UI.Components @using Moonlight.Features.Servers.UI.Components
@using BlazorTable @using BlazorTable
@using Microsoft.EntityFrameworkCore @using Microsoft.EntityFrameworkCore
@using Moonlight.Core.Services.Interop
@using Microsoft.AspNetCore.Components.Forms
@inject Repository<ServerImage> ImageRepository @inject Repository<ServerImage> ImageRepository
@inject ToastService ToastService
<LazyLoader ShowAsCard="true" Load="Load"> <LazyLoader ShowAsCard="true" Load="Load">
@if (Image == null) @if (Image == null)
{ {
<NotFoundAlert /> <NotFoundAlert/>
} }
else else
{ {
<AdminImageViewNavigation Index="4" ImageId="@Id" /> <AdminImageViewNavigation Index="4" ImageId="@Id"/>
<div class="card mb-5">
<div class="card-body">
<div class="row ">
<div class="col-md-6 col-12">
<label class="form-label">Default docker image</label>
<SmartSelect TField="ServerDockerImage"
@bind-Value="SelectedDockerImage"
Items="Image.DockerImages"
DisplayField="@(x => x.Name)"
CanBeNull="true"/>
</div>
<div class="col-md-6 col-12">
<label class="form-label">Allow user to change the docker image</label>
<div class="form-check">
<InputCheckbox @bind-Value="Image.AllowUserToChangeDockerImage" class="form-check-input"/>
</div>
</div>
</div>
</div>
<div class="card-footer d-flex justify-content-end">
<WButton Text="Save" CssClasses="btn btn-success" OnClick="OnSave"/>
</div>
</div>
<AutoListCrud TItem="ServerDockerImage" <AutoListCrud TItem="ServerDockerImage"
TRootItem="ServerImage" TRootItem="ServerImage"
TCreateForm="CreateDockerImage" TCreateForm="CreateDockerImage"
@ -26,10 +53,10 @@
RootItem="Image" RootItem="Image"
Title="Manage docker images"> Title="Manage docker images">
<View> <View>
<Column TableItem="ServerDockerImage" Field="@(x => x.Id)" Title="Id" /> <Column TableItem="ServerDockerImage" Field="@(x => x.Id)" Title="Id"/>
<Column TableItem="ServerDockerImage" Field="@(x => x.DisplayName)" Title="Display name" /> <Column TableItem="ServerDockerImage" Field="@(x => x.DisplayName)" Title="Display name"/>
<Column TableItem="ServerDockerImage" Field="@(x => x.Name)" Title="Name" /> <Column TableItem="ServerDockerImage" Field="@(x => x.Name)" Title="Name"/>
<Column TableItem="ServerDockerImage" Field="@(x => x.AutoPull)" Title=""> <Column TableItem="ServerDockerImage" Field="@(x => x.AutoPull)" Title="Auto pull">
<Template> <Template>
@if (context.AutoPull) @if (context.AutoPull)
{ {
@ -48,18 +75,54 @@
@code @code
{ {
[Parameter] [Parameter] public int Id { get; set; }
public int Id { get; set; }
private ServerImage? Image; private ServerImage? Image;
private ServerDockerImage? SelectedDockerImage
{
get
{
if (Image == null)
return null;
if (Image.DefaultDockerImageIndex >= Image.DockerImages.Count)
return null;
if (Image.DefaultDockerImageIndex == -1)
return null;
return Image.DockerImages[Image.DefaultDockerImageIndex];
}
set
{
if (Image == null)
return;
if (value == null)
{
Image.DefaultDockerImageIndex = -1;
return;
}
Image.DefaultDockerImageIndex = Image.DockerImages.IndexOf(value);
}
}
private Task Load(LazyLoader arg) private Task Load(LazyLoader arg)
{ {
Image = ImageRepository Image = ImageRepository
.Get() .Get()
.Include(x => x.DockerImages) .Include(x => x.DockerImages)
.FirstOrDefault(x => x.Id == Id); .FirstOrDefault(x => x.Id == Id);
return Task.CompletedTask; return Task.CompletedTask;
} }
private async Task OnSave()
{
ImageRepository.Update(Image!);
await ToastService.Success("Successfully updated image");
}
} }

View file

@ -29,7 +29,7 @@
</div> </div>
<div class="card-footer"> <div class="card-footer">
<div class="d-flex justify-content-end"> <div class="d-flex justify-content-end">
<button type="submit" class="btn btn-success">Create</button> <button type="submit" class="btn btn-success">Save</button>
</div> </div>
</div> </div>
</SmartForm> </SmartForm>

View file

@ -29,7 +29,7 @@
</div> </div>
<div class="card-footer"> <div class="card-footer">
<div class="d-flex justify-content-end"> <div class="d-flex justify-content-end">
<button type="submit" class="btn btn-success">Create</button> <button type="submit" class="btn btn-success">Save</button>
</div> </div>
</div> </div>
</SmartForm> </SmartForm>

View file

@ -3,24 +3,65 @@
@using Moonlight.Features.Servers.Entities @using Moonlight.Features.Servers.Entities
@using Moonlight.Core.Repositories @using Moonlight.Core.Repositories
@using Moonlight.Features.Servers.UI.Components @using Moonlight.Features.Servers.UI.Components
@using Microsoft.EntityFrameworkCore
@using BlazorTable
@using Moonlight.Features.Servers.Models.Forms.Admin.Images
@inject Repository<ServerImage> ImageRepository @inject Repository<ServerImage> ImageRepository
<LazyLoader ShowAsCard="true" Load="Load"> <LazyLoader ShowAsCard="true" Load="Load">
@if (Image == null) @if (Image == null)
{ {
<NotFoundAlert /> <NotFoundAlert/>
} }
else else
{ {
<AdminImageViewNavigation Index="5" ImageId="@Id" /> <AdminImageViewNavigation Index="5" ImageId="@Id"/>
<AutoListCrud TItem="ServerImageVariable"
TRootItem="ServerImage"
TCreateForm="CreateImageVariable"
TUpdateForm="UpdateImageVariable"
Field="@(x => x.Variables)"
RootItem="Image"
Title="Manage image variables">
<View>
<Column TableItem="ServerImageVariable" Field="@(x => x.Id)" Title="Id"/>
<Column TableItem="ServerImageVariable" Field="@(x => x.DisplayName)" Title="Display name"/>
<Column TableItem="ServerImageVariable" Field="@(x => x.Key)" Title="Key"/>
<Column TableItem="ServerImageVariable" Field="@(x => x.DefaultValue)" Title="Default value"/>
<Column TableItem="ServerImageVariable" Field="@(x => x.AllowUserToView)" Title="View">
<Template>
@if (context.AllowUserToView)
{
<i class="bx bx-sm bx-check text-success"></i>
}
else
{
<i class="bx bx-sm bx-x text-danger"></i>
}
</Template>
</Column>
<Column TableItem="ServerImageVariable" Field="@(x => x.AllowUserToEdit)" Title="Edit">
<Template>
@if (context.AllowUserToEdit)
{
<i class="bx bx-sm bx-check text-success"></i>
}
else
{
<i class="bx bx-sm bx-x text-danger"></i>
}
</Template>
</Column>
</View>
</AutoListCrud>
} }
</LazyLoader> </LazyLoader>
@code @code
{ {
[Parameter] [Parameter] public int Id { get; set; }
public int Id { get; set; }
private ServerImage? Image; private ServerImage? Image;
@ -28,8 +69,9 @@
{ {
Image = ImageRepository Image = ImageRepository
.Get() .Get()
.Include(x => x.Variables)
.FirstOrDefault(x => x.Id == Id); .FirstOrDefault(x => x.Id == Id);
return Task.CompletedTask; return Task.CompletedTask;
} }
} }

View file

@ -38,6 +38,7 @@
<Folder Include="Features\Servers\Http\Resources\" /> <Folder Include="Features\Servers\Http\Resources\" />
<Folder Include="Features\StoreSystem\Helpers\" /> <Folder Include="Features\StoreSystem\Helpers\" />
<Folder Include="Features\Ticketing\Models\Abstractions\" /> <Folder Include="Features\Ticketing\Models\Abstractions\" />
<Folder Include="storage\plugins\" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>