Added new image manager. CRUD implemeted
This commit is contained in:
parent
d5f4278b30
commit
d42fd2095c
15 changed files with 3198 additions and 40 deletions
|
@ -13,8 +13,8 @@ public class Image
|
|||
public string InstallDockerImage { get; set; } = "";
|
||||
public string InstallEntrypoint { get; set; } = "";
|
||||
public string Startup { get; set; } = "";
|
||||
|
||||
public int Allocations { get; set; } = 1;
|
||||
public List<DockerImage> DockerImages { get; set; } = new();
|
||||
public List<ImageVariable> Variables { get; set; } = new();
|
||||
public List<ImageTag> Tags { get; set; } = new();
|
||||
public string TagsJson { get; set; } = "";
|
||||
}
|
1023
Moonlight/App/Database/Migrations/20230314164750_SwitchedToJsonTags.Designer.cs
generated
Normal file
1023
Moonlight/App/Database/Migrations/20230314164750_SwitchedToJsonTags.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,174 @@
|
|||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class SwitchedToJsonTags : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_ImageTags_Images_ImageId",
|
||||
table: "ImageTags");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_ImageTags_ImageId",
|
||||
table: "ImageTags");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "ImageId",
|
||||
table: "ImageTags");
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "TagsJson",
|
||||
table: "Images",
|
||||
type: "longtext",
|
||||
nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "InternalAaPanelId",
|
||||
table: "Databases",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Name",
|
||||
table: "Databases",
|
||||
type: "longtext",
|
||||
nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "AaPanels",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
Url = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
Key = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
BaseDomain = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_AaPanels", x => x.Id);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Websites",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<int>(type: "int", nullable: false)
|
||||
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
|
||||
InternalAaPanelId = table.Column<int>(type: "int", nullable: false),
|
||||
AaPanelId = table.Column<int>(type: "int", nullable: false),
|
||||
OwnerId = table.Column<int>(type: "int", nullable: false),
|
||||
DomainName = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
PhpVersion = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
FtpUsername = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4"),
|
||||
FtpPassword = table.Column<string>(type: "longtext", nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4")
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Websites", x => x.Id);
|
||||
table.ForeignKey(
|
||||
name: "FK_Websites_AaPanels_AaPanelId",
|
||||
column: x => x.AaPanelId,
|
||||
principalTable: "AaPanels",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
table.ForeignKey(
|
||||
name: "FK_Websites_Users_OwnerId",
|
||||
column: x => x.OwnerId,
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
})
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Databases_AaPanelId",
|
||||
table: "Databases",
|
||||
column: "AaPanelId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Websites_AaPanelId",
|
||||
table: "Websites",
|
||||
column: "AaPanelId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Websites_OwnerId",
|
||||
table: "Websites",
|
||||
column: "OwnerId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_Databases_AaPanels_AaPanelId",
|
||||
table: "Databases",
|
||||
column: "AaPanelId",
|
||||
principalTable: "AaPanels",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_Databases_AaPanels_AaPanelId",
|
||||
table: "Databases");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "Websites");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "AaPanels");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_Databases_AaPanelId",
|
||||
table: "Databases");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "TagsJson",
|
||||
table: "Images");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "InternalAaPanelId",
|
||||
table: "Databases");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Name",
|
||||
table: "Databases");
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "ImageId",
|
||||
table: "ImageTags",
|
||||
type: "int",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ImageTags_ImageId",
|
||||
table: "ImageTags",
|
||||
column: "ImageId");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_ImageTags_Images_ImageId",
|
||||
table: "ImageTags",
|
||||
column: "ImageId",
|
||||
principalTable: "Images",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
}
|
||||
}
|
1026
Moonlight/App/Database/Migrations/20230314190100_AddedAllocationsToImage.Designer.cs
generated
Normal file
1026
Moonlight/App/Database/Migrations/20230314190100_AddedAllocationsToImage.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,29 @@
|
|||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Moonlight.App.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddedAllocationsToImage : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "Allocations",
|
||||
table: "Images",
|
||||
type: "int",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Allocations",
|
||||
table: "Images");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,6 +19,29 @@ namespace Moonlight.App.Database.Migrations
|
|||
.HasAnnotation("ProductVersion", "7.0.3")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.AaPanel", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("BaseDomain")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Key")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Url")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("AaPanels");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
|
@ -28,11 +51,20 @@ namespace Moonlight.App.Database.Migrations
|
|||
b.Property<int>("AaPanelId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("InternalAaPanelId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("OwnerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AaPanelId");
|
||||
|
||||
b.HasIndex("OwnerId");
|
||||
|
||||
b.ToTable("Databases");
|
||||
|
@ -92,6 +124,9 @@ namespace Moonlight.App.Database.Migrations
|
|||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("Allocations")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ConfigFiles")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
@ -128,6 +163,10 @@ namespace Moonlight.App.Database.Migrations
|
|||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("TagsJson")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<Guid>("Uuid")
|
||||
.HasColumnType("char(36)");
|
||||
|
||||
|
@ -142,17 +181,12 @@ namespace Moonlight.App.Database.Migrations
|
|||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("ImageId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ImageId");
|
||||
|
||||
b.ToTable("ImageTags");
|
||||
});
|
||||
|
||||
|
@ -726,14 +760,62 @@ namespace Moonlight.App.Database.Migrations
|
|||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Website", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("AaPanelId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("DomainName")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("FtpPassword")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("FtpUsername")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int>("InternalAaPanelId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("OwnerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("PhpVersion")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AaPanelId");
|
||||
|
||||
b.HasIndex("OwnerId");
|
||||
|
||||
b.ToTable("Websites");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Database", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.AaPanel", "AaPanel")
|
||||
.WithMany()
|
||||
.HasForeignKey("AaPanelId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||
.WithMany()
|
||||
.HasForeignKey("OwnerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("AaPanel");
|
||||
|
||||
b.Navigation("Owner");
|
||||
});
|
||||
|
||||
|
@ -763,13 +845,6 @@ namespace Moonlight.App.Database.Migrations
|
|||
b.Navigation("SharedDomain");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageTag", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.Image", null)
|
||||
.WithMany("Tags")
|
||||
.HasForeignKey("ImageId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.ImageVariable", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.Image", null)
|
||||
|
@ -898,12 +973,29 @@ namespace Moonlight.App.Database.Migrations
|
|||
b.Navigation("Subscription");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Website", b =>
|
||||
{
|
||||
b.HasOne("Moonlight.App.Database.Entities.AaPanel", "AaPanel")
|
||||
.WithMany()
|
||||
.HasForeignKey("AaPanelId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Moonlight.App.Database.Entities.User", "Owner")
|
||||
.WithMany()
|
||||
.HasForeignKey("OwnerId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("AaPanel");
|
||||
|
||||
b.Navigation("Owner");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Moonlight.App.Database.Entities.Image", b =>
|
||||
{
|
||||
b.Navigation("DockerImages");
|
||||
|
||||
b.Navigation("Tags");
|
||||
|
||||
b.Navigation("Variables");
|
||||
});
|
||||
|
||||
|
|
|
@ -152,7 +152,7 @@ namespace Moonlight
|
|||
var supportServerService = app.Services.GetRequiredService<SupportServerService>();
|
||||
|
||||
// Discord bot service
|
||||
var discordBotService = app.Services.GetRequiredService<DiscordBotService>();
|
||||
//var discordBotService = app.Services.GetRequiredService<DiscordBotService>();
|
||||
|
||||
app.Run();
|
||||
}
|
||||
|
|
|
@ -8,19 +8,22 @@
|
|||
<MonacoEditor CssClass="h-100" @ref="Editor" Id="vseditor" ConstructionOptions="(x) => EditorOptions"/>
|
||||
</div>
|
||||
|
||||
<div class="card-footer pt-0">
|
||||
<div class="btn-group">
|
||||
<WButton
|
||||
Text="@(TranslationService.Translate("Save"))"
|
||||
WorkingText="@(TranslationService.Translate("Saving"))"
|
||||
OnClick="Submit"></WButton>
|
||||
<WButton
|
||||
CssClasses="btn-danger"
|
||||
Text="@(TranslationService.Translate("Cancel"))"
|
||||
WorkingText="@(TranslationService.Translate("Canceling"))"
|
||||
OnClick="Cancel"></WButton>
|
||||
@if (!HideControls)
|
||||
{
|
||||
<div class="card-footer pt-0">
|
||||
<div class="btn-group">
|
||||
<WButton
|
||||
Text="@(TranslationService.Translate("Save"))"
|
||||
WorkingText="@(TranslationService.Translate("Saving"))"
|
||||
OnClick="Submit"></WButton>
|
||||
<WButton
|
||||
CssClasses="btn-danger"
|
||||
Text="@(TranslationService.Translate("Cancel"))"
|
||||
WorkingText="@(TranslationService.Translate("Canceling"))"
|
||||
OnClick="Cancel"></WButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@code
|
||||
{
|
||||
|
@ -29,6 +32,9 @@
|
|||
|
||||
[Parameter]
|
||||
public string Language { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public bool HideControls { get; set; } = false;
|
||||
|
||||
// Events
|
||||
[Parameter]
|
||||
|
@ -95,4 +101,9 @@
|
|||
{
|
||||
await InvokeAsync(() => OnCancel?.Invoke());
|
||||
}
|
||||
|
||||
public async Task<string> GetData()
|
||||
{
|
||||
return await Editor.GetValue();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -146,7 +146,7 @@ else
|
|||
</div>
|
||||
|
||||
<div class="menu-item">
|
||||
<a class="menu-link" href="/admin/images">
|
||||
<a class="menu-link" href="/admin/servers/images">
|
||||
<span class="menu-bullet">
|
||||
<span class="bullet bullet-dot"></span>
|
||||
</span>
|
||||
|
|
|
@ -141,8 +141,10 @@
|
|||
</div>
|
||||
<div class="row">
|
||||
<div class="card card-body">
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-primary" href="/admin/servers">Back</a>
|
||||
<div class="d-flex justify-content-end">
|
||||
<a href="/admin/servers/images" class="btn btn-danger me-3">
|
||||
<TL>Cancel</TL>
|
||||
</a>
|
||||
<WButton Text="@(SmartTranslateService.Translate("Save"))"
|
||||
WorkingText="@(SmartTranslateService.Translate("Saving"))"
|
||||
CssClasses="btn-success"
|
||||
|
|
353
Moonlight/Shared/Views/Admin/Servers/Images/Edit.razor
Normal file
353
Moonlight/Shared/Views/Admin/Servers/Images/Edit.razor
Normal file
|
@ -0,0 +1,353 @@
|
|||
@page "/admin/servers/images/edit/{Id:int}"
|
||||
@using Moonlight.App.Repositories
|
||||
@using Moonlight.Shared.Components.FileManagerPartials
|
||||
@using Moonlight.App.Database.Entities
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using Moonlight.App.Services
|
||||
@using Moonlight.App.Services.Interop
|
||||
@using Newtonsoft.Json
|
||||
|
||||
@inject ImageRepository ImageRepository
|
||||
@inject SmartTranslateService SmartTranslateService
|
||||
@inject ToastService ToastService
|
||||
|
||||
<OnlyAdmin>
|
||||
<div class="row">
|
||||
<LazyLoader @ref="LazyLoader" Load="Load">
|
||||
@if (Image == null)
|
||||
{
|
||||
<div class="alert alert-danger">
|
||||
<TL>No image with this id found</TL>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="card card-body">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Name</TL>
|
||||
</label>
|
||||
<input @bind="Image.Name" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Description</TL>
|
||||
</label>
|
||||
<textarea @bind="Image.Description" type="text" class="form-control"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="card card-body">
|
||||
<label class="form-label">
|
||||
<TL>Tags</TL>
|
||||
</label>
|
||||
<div class="input-group mb-5">
|
||||
<input @bind="AddTagName" type="text" class="form-control" placeholder="@(SmartTranslateService.Translate("Enter tag name"))">
|
||||
<button @onclick="AddTag" class="btn btn-primary">
|
||||
<TL>Add</TL>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
@if (Tags.Any())
|
||||
{
|
||||
<div class="row">
|
||||
@foreach (var tag in Tags)
|
||||
{
|
||||
<button @onclick="() => RemoveTag(tag)" class="col m-3 btn btn-outline-primary mw-25">
|
||||
@(tag)
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-primary">
|
||||
<TL>No tags found</TL>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="card card-body">
|
||||
<label class="form-label">
|
||||
<TL>Docker images</TL>
|
||||
</label>
|
||||
<div class="input-group mb-5">
|
||||
<input @bind="NewDockerImage.Name" type="text" class="form-control" placeholder="@(SmartTranslateService.Translate("Enter docker image name"))">
|
||||
<button @onclick="AddDockerImage" class="btn btn-primary">
|
||||
<TL>Add</TL>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
@if (Image.DockerImages.Any())
|
||||
{
|
||||
<div class="row">
|
||||
@foreach (var imageDocker in Image.DockerImages)
|
||||
{
|
||||
<button @onclick="() => RemoveDockerImage(imageDocker)" class="col m-3 btn btn-outline-primary mw-25">
|
||||
@(imageDocker.Name)
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-primary">
|
||||
<TL>No docker images found</TL>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="card card-body">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Default image</TL>
|
||||
</label>
|
||||
<select @bind="DefaultImageIndex" class="form-select">
|
||||
@foreach (var image in Image.DockerImages)
|
||||
{
|
||||
<option value="@(image.Id)">@(image.Name)</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Allocations</TL>
|
||||
</label>
|
||||
<input @bind="Image.Allocations" type="number" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mx-0">
|
||||
<div class="card card-body">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Startup command</TL>
|
||||
</label>
|
||||
<input @bind="Image.Startup" type="text" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Install container</TL>
|
||||
</label>
|
||||
<input @bind="Image.InstallDockerImage" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Install entry</TL>
|
||||
</label>
|
||||
<input @bind="Image.InstallEntrypoint" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card card-flush">
|
||||
<FileEditor @ref="Editor" Language="shell" InitialData="@(Image.InstallScript)" HideControls="true"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-8">
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="card card-body">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Configuration files</TL>
|
||||
</label>
|
||||
<textarea @bind="Image.ConfigFiles" class="form-control"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="card card-body">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Startup detection</TL>
|
||||
</label>
|
||||
<input @bind="Image.StartupDetection" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Stop command</TL>
|
||||
</label>
|
||||
<input @bind="Image.StopCommand" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-6">
|
||||
<div class="card card-body">
|
||||
<div class="input-group mb-5">
|
||||
<input type="text" @bind="ImageVariable.Key" placeholder="@(SmartTranslateService.Translate("Key"))" class="form-control">
|
||||
<input type="text" @bind="ImageVariable.DefaultValue" placeholder="@(SmartTranslateService.Translate("Default value"))" class="form-control">
|
||||
<button @onclick="AddVariable" class="btn btn-primary">
|
||||
<TL>Add</TL>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@if (Image!.Variables.Any())
|
||||
{
|
||||
<div class="row">
|
||||
@foreach (var variable in Image!.Variables)
|
||||
{
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" @bind="variable.Key" placeholder="@(SmartTranslateService.Translate("Key"))" class="form-control">
|
||||
<input type="text" @bind="variable.DefaultValue" placeholder="@(SmartTranslateService.Translate("Default value"))" class="form-control">
|
||||
<button @onclick="() => RemoveVariable(variable)" class="btn btn-danger">
|
||||
<TL>Remove</TL>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-primary">
|
||||
<TL>No variables found</TL>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="card card-body">
|
||||
<div class="d-flex justify-content-end">
|
||||
<a href="/admin/servers/images" class="btn btn-danger me-3">
|
||||
<TL>Cancel</TL>
|
||||
</a>
|
||||
<WButton Text="@(SmartTranslateService.Translate("Save"))"
|
||||
WorkingText="@(SmartTranslateService.Translate("Saving"))"
|
||||
CssClasses="btn-success"
|
||||
OnClick="Save">
|
||||
</WButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</LazyLoader>
|
||||
</div>
|
||||
</OnlyAdmin>
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter]
|
||||
public int Id { get; set; }
|
||||
|
||||
private Image? Image;
|
||||
|
||||
private List<string> Tags;
|
||||
private string AddTagName = "";
|
||||
|
||||
private DockerImage NewDockerImage = new();
|
||||
private ImageVariable ImageVariable = new();
|
||||
|
||||
private FileEditor Editor;
|
||||
|
||||
private int DefaultImageIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
var i = Image.DockerImages.FirstOrDefault(x => x.Default);
|
||||
return i?.Id ?? -1;
|
||||
}
|
||||
set
|
||||
{
|
||||
foreach (var image in Image!.DockerImages)
|
||||
{
|
||||
image.Default = false;
|
||||
}
|
||||
|
||||
var i = Image.DockerImages.FirstOrDefault(x => x.Id == value);
|
||||
|
||||
if (i != null)
|
||||
i.Default = true;
|
||||
}
|
||||
}
|
||||
|
||||
private LazyLoader LazyLoader;
|
||||
|
||||
private Task Load(LazyLoader arg)
|
||||
{
|
||||
Image = ImageRepository
|
||||
.Get()
|
||||
.Include(x => x.Variables)
|
||||
.Include(x => x.DockerImages)
|
||||
.FirstOrDefault(x => x.Id == Id);
|
||||
|
||||
if (Image != null)
|
||||
{
|
||||
Tags = new();
|
||||
|
||||
foreach (var tag in JsonConvert.DeserializeObject<string[]>(Image.TagsJson) ?? Array.Empty<string>())
|
||||
{
|
||||
Tags.Add(tag);
|
||||
}
|
||||
|
||||
// Editor
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void AddTag()
|
||||
{
|
||||
Tags.Add(AddTagName);
|
||||
}
|
||||
|
||||
private void RemoveTag(string tag)
|
||||
{
|
||||
Tags.Remove(tag);
|
||||
}
|
||||
|
||||
private void AddDockerImage()
|
||||
{
|
||||
Image!.DockerImages.Add(NewDockerImage);
|
||||
NewDockerImage = new();
|
||||
}
|
||||
|
||||
private void RemoveDockerImage(DockerImage image)
|
||||
{
|
||||
Image!.DockerImages.Remove(image);
|
||||
}
|
||||
|
||||
private void AddVariable()
|
||||
{
|
||||
Image!.Variables.Add(ImageVariable);
|
||||
ImageVariable = new();
|
||||
}
|
||||
|
||||
private void RemoveVariable(ImageVariable variable)
|
||||
{
|
||||
Image!.Variables.Remove(variable);
|
||||
}
|
||||
|
||||
private async Task Save()
|
||||
{
|
||||
if (Image == null)
|
||||
return;
|
||||
|
||||
Image.TagsJson = JsonConvert.SerializeObject(Tags);
|
||||
Image.InstallScript = await Editor.GetData();
|
||||
|
||||
ImageRepository.Update(Image);
|
||||
|
||||
await ToastService.Success(SmartTranslateService.Translate("Successfully saved image"));
|
||||
|
||||
await LazyLoader.Reload();
|
||||
}
|
||||
}
|
91
Moonlight/Shared/Views/Admin/Servers/Images/Index.razor
Normal file
91
Moonlight/Shared/Views/Admin/Servers/Images/Index.razor
Normal file
|
@ -0,0 +1,91 @@
|
|||
@page "/admin/servers/images"
|
||||
|
||||
@using BlazorTable
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using Moonlight.App.Database.Entities
|
||||
@using Moonlight.App.Repositories
|
||||
@using Moonlight.App.Services
|
||||
|
||||
@inject ImageRepository ImageRepository
|
||||
@inject SmartTranslateService SmartTranslateService
|
||||
|
||||
<OnlyAdmin>
|
||||
<div class="row">
|
||||
<LazyLoader @ref="LazyLoader" Load="Load">
|
||||
<div class="card">
|
||||
<div class="card-header border-0 pt-5">
|
||||
<h3 class="card-title align-items-start flex-column">
|
||||
<span class="card-label fw-bold fs-3 mb-1">
|
||||
<TL>Images</TL>
|
||||
</span>
|
||||
</h3>
|
||||
<div class="card-toolbar">
|
||||
<a href="/admin/servers/images/new" class="btn btn-sm btn-light-success">
|
||||
<i class="bx bx-layer-plus"></i>
|
||||
<TL>New image</TL>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body pt-0">
|
||||
@if (Images.Any())
|
||||
{
|
||||
<div class="table-responsive">
|
||||
<Table TableItem="Image" Items="Images" PageSize="25" TableClass="table table-row-bordered table-row-gray-100 align-middle gs-0 gy-3" TableHeadClass="fw-bold text-muted">
|
||||
<Column TableItem="Image" Title="@(SmartTranslateService.Translate("Id"))" Field="@(x => x.Id)" Sortable="true" Filterable="true"/>
|
||||
<Column TableItem="Image" Title="@(SmartTranslateService.Translate("Name"))" Field="@(x => x.Name)" Sortable="true" Filterable="true"/>
|
||||
<Column TableItem="Image" Title="@(SmartTranslateService.Translate("Description"))" Field="@(x => x.Description)" Sortable="true" Filterable="true"/>
|
||||
<Column TableItem="Image" Title="@(SmartTranslateService.Translate("Uuid"))" Field="@(x => x.Uuid)" Sortable="true" Filterable="true"/>
|
||||
<Column TableItem="Image" Title="" Field="@(x => x.Id)" Sortable="false" Filterable="false">
|
||||
<Template>
|
||||
<a href="/admin/servers/images/edit/@(context.Id)">
|
||||
@(SmartTranslateService.Translate("Edit"))
|
||||
</a>
|
||||
</Template>
|
||||
</Column>
|
||||
<Column TableItem="Image" Title="" Field="@(x => x.Id)" Sortable="false" Filterable="false">
|
||||
<Template>
|
||||
<WButton Text="@(SmartTranslateService.Translate("Delete"))"
|
||||
WorkingText="@(SmartTranslateService.Translate("Deleting"))"
|
||||
CssClasses="btn-danger"
|
||||
OnClick="() => Delete(context)">
|
||||
</WButton>
|
||||
</Template>
|
||||
</Column>
|
||||
<Pager ShowPageNumber="true" ShowTotalCount="true"/>
|
||||
</Table>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-info">
|
||||
<TL>No images found</TL>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</LazyLoader>
|
||||
</div>
|
||||
</OnlyAdmin>
|
||||
|
||||
@code
|
||||
{
|
||||
private Image[] Images;
|
||||
private LazyLoader LazyLoader;
|
||||
|
||||
private Task Load(LazyLoader arg)
|
||||
{
|
||||
Images = ImageRepository
|
||||
.Get()
|
||||
.Include(x => x.DockerImages)
|
||||
.Include(x => x.Variables)
|
||||
.ToArray();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private async Task Delete(Image image)
|
||||
{
|
||||
ImageRepository.Delete(image);
|
||||
await LazyLoader.Reload();
|
||||
}
|
||||
}
|
340
Moonlight/Shared/Views/Admin/Servers/Images/New.razor
Normal file
340
Moonlight/Shared/Views/Admin/Servers/Images/New.razor
Normal file
|
@ -0,0 +1,340 @@
|
|||
@page "/admin/servers/images/new"
|
||||
@using Moonlight.App.Repositories
|
||||
@using Moonlight.Shared.Components.FileManagerPartials
|
||||
@using Moonlight.App.Database.Entities
|
||||
@using Moonlight.App.Services
|
||||
@using Moonlight.App.Services.Interop
|
||||
@using Newtonsoft.Json
|
||||
|
||||
@inject ImageRepository ImageRepository
|
||||
@inject SmartTranslateService SmartTranslateService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ToastService ToastService
|
||||
|
||||
<OnlyAdmin>
|
||||
<div class="row">
|
||||
<LazyLoader @ref="LazyLoader" Load="Load">
|
||||
<div class="row">
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="card card-body">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Name</TL>
|
||||
</label>
|
||||
<input @bind="Image.Name" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Description</TL>
|
||||
</label>
|
||||
<textarea @bind="Image.Description" type="text" class="form-control"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="card card-body">
|
||||
<label class="form-label">
|
||||
<TL>Tags</TL>
|
||||
</label>
|
||||
<div class="input-group mb-5">
|
||||
<input @bind="AddTagName" type="text" class="form-control" placeholder="@(SmartTranslateService.Translate("Enter tag name"))">
|
||||
<button @onclick="AddTag" class="btn btn-primary">
|
||||
<TL>Add</TL>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
@if (Tags.Any())
|
||||
{
|
||||
<div class="row">
|
||||
@foreach (var tag in Tags)
|
||||
{
|
||||
<button @onclick="() => RemoveTag(tag)" class="col m-3 btn btn-outline-primary mw-25">
|
||||
@(tag)
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-primary">
|
||||
<TL>No tags found</TL>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="card card-body">
|
||||
<label class="form-label">
|
||||
<TL>Docker images</TL>
|
||||
</label>
|
||||
<div class="input-group mb-5">
|
||||
<input @bind="NewDockerImage.Name" type="text" class="form-control" placeholder="@(SmartTranslateService.Translate("Enter docker image name"))">
|
||||
<button @onclick="AddDockerImage" class="btn btn-primary">
|
||||
<TL>Add</TL>
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
@if (Image.DockerImages.Any())
|
||||
{
|
||||
<div class="row">
|
||||
@foreach (var imageDocker in Image.DockerImages)
|
||||
{
|
||||
<button @onclick="() => RemoveDockerImage(imageDocker)" class="col m-3 btn btn-outline-primary mw-25">
|
||||
@(imageDocker.Name)
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-primary">
|
||||
<TL>No docker images found</TL>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="card card-body">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Default image</TL>
|
||||
</label>
|
||||
<select @bind="DefaultImageIndex" class="form-select">
|
||||
@foreach (var image in Image.DockerImages)
|
||||
{
|
||||
<option value="@(image.Id)">@(image.Name)</option>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Allocations</TL>
|
||||
</label>
|
||||
<input @bind="Image.Allocations" type="number" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mx-0">
|
||||
<div class="card card-body">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Startup command</TL>
|
||||
</label>
|
||||
<input @bind="Image.Startup" type="text" class="form-control">
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Install container</TL>
|
||||
</label>
|
||||
<input @bind="Image.InstallDockerImage" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Install entry</TL>
|
||||
</label>
|
||||
<input @bind="Image.InstallEntrypoint" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card card-flush">
|
||||
<FileEditor @ref="Editor" Language="shell" InitialData="@(Image.InstallScript)" HideControls="true"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-8">
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="card card-body">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Configuration files</TL>
|
||||
</label>
|
||||
<textarea @bind="Image.ConfigFiles" class="form-control"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-6 mb-5 mb-xl-10">
|
||||
<div class="card card-body">
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Startup detection</TL>
|
||||
</label>
|
||||
<input @bind="Image.StartupDetection" type="text" class="form-control">
|
||||
</div>
|
||||
<div class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Stop command</TL>
|
||||
</label>
|
||||
<input @bind="Image.StopCommand" type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row my-6">
|
||||
<div class="card card-body">
|
||||
<div class="input-group mb-5">
|
||||
<input type="text" @bind="ImageVariable.Key" placeholder="@(SmartTranslateService.Translate("Key"))" class="form-control">
|
||||
<input type="text" @bind="ImageVariable.DefaultValue" placeholder="@(SmartTranslateService.Translate("Default value"))" class="form-control">
|
||||
<button @onclick="AddVariable" class="btn btn-primary">
|
||||
<TL>Add</TL>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@if (Image!.Variables.Any())
|
||||
{
|
||||
<div class="row">
|
||||
@foreach (var variable in Image!.Variables)
|
||||
{
|
||||
<div class="input-group mb-3">
|
||||
<input type="text" @bind="variable.Key" placeholder="@(SmartTranslateService.Translate("Key"))" class="form-control">
|
||||
<input type="text" @bind="variable.DefaultValue" placeholder="@(SmartTranslateService.Translate("Default value"))" class="form-control">
|
||||
<button @onclick="() => RemoveVariable(variable)" class="btn btn-danger">
|
||||
<TL>Remove</TL>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="alert alert-primary">
|
||||
<TL>No variables found</TL>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="card card-body">
|
||||
<div class="d-flex justify-content-end">
|
||||
<a href="/admin/servers/images" class="btn btn-danger me-3">
|
||||
<TL>Cancel</TL>
|
||||
</a>
|
||||
<WButton Text="@(SmartTranslateService.Translate("Save"))"
|
||||
WorkingText="@(SmartTranslateService.Translate("Saving"))"
|
||||
CssClasses="btn-success"
|
||||
OnClick="Save">
|
||||
</WButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</LazyLoader>
|
||||
</div>
|
||||
</OnlyAdmin>
|
||||
|
||||
@code
|
||||
{
|
||||
private Image Image = new()
|
||||
{
|
||||
Variables = new(),
|
||||
DockerImages = new(),
|
||||
InstallScript = "# install script here",
|
||||
Name = "Name",
|
||||
TagsJson = "[]",
|
||||
Description = "Description",
|
||||
Startup = "",
|
||||
Uuid = Guid.NewGuid(),
|
||||
ConfigFiles = "{}",
|
||||
InstallEntrypoint = "ash",
|
||||
StartupDetection = "Done",
|
||||
StopCommand = "^C",
|
||||
InstallDockerImage = "ghcr.io/pterodactyl/installers:alpine"
|
||||
};
|
||||
|
||||
private List<string> Tags;
|
||||
private string AddTagName = "";
|
||||
|
||||
private DockerImage NewDockerImage = new();
|
||||
private ImageVariable ImageVariable = new();
|
||||
|
||||
private FileEditor Editor;
|
||||
|
||||
private int DefaultImageIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
var i = Image.DockerImages.FirstOrDefault(x => x.Default);
|
||||
return i?.Id ?? -1;
|
||||
}
|
||||
set
|
||||
{
|
||||
foreach (var image in Image!.DockerImages)
|
||||
{
|
||||
image.Default = false;
|
||||
}
|
||||
|
||||
var i = Image.DockerImages.FirstOrDefault(x => x.Id == value);
|
||||
|
||||
if (i != null)
|
||||
i.Default = true;
|
||||
}
|
||||
}
|
||||
|
||||
private LazyLoader LazyLoader;
|
||||
|
||||
private Task Load(LazyLoader arg)
|
||||
{
|
||||
Tags = new();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void AddTag()
|
||||
{
|
||||
Tags.Add(AddTagName);
|
||||
}
|
||||
|
||||
private void RemoveTag(string tag)
|
||||
{
|
||||
Tags.Remove(tag);
|
||||
}
|
||||
|
||||
private void AddDockerImage()
|
||||
{
|
||||
Image!.DockerImages.Add(NewDockerImage);
|
||||
NewDockerImage = new();
|
||||
}
|
||||
|
||||
private void RemoveDockerImage(DockerImage image)
|
||||
{
|
||||
Image!.DockerImages.Remove(image);
|
||||
}
|
||||
|
||||
private void AddVariable()
|
||||
{
|
||||
Image!.Variables.Add(ImageVariable);
|
||||
ImageVariable = new();
|
||||
}
|
||||
|
||||
private void RemoveVariable(ImageVariable variable)
|
||||
{
|
||||
Image!.Variables.Remove(variable);
|
||||
}
|
||||
|
||||
private async Task Save()
|
||||
{
|
||||
if (Image == null)
|
||||
return;
|
||||
|
||||
Image.TagsJson = JsonConvert.SerializeObject(Tags);
|
||||
Image.InstallScript = await Editor.GetData();
|
||||
|
||||
ImageRepository.Add(Image);
|
||||
|
||||
await ToastService.Success(SmartTranslateService.Translate("Successfully added image"));
|
||||
|
||||
NavigationManager.NavigateTo("/admin/servers/images");
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
@using Moonlight.App.Services.Sessions
|
||||
@using Moonlight.Shared.Components.Xterm
|
||||
@using Moonlight.Shared.Components.ServerControl
|
||||
@using Newtonsoft.Json
|
||||
|
||||
@inject ImageRepository ImageRepository
|
||||
@inject ServerRepository ServerRepository
|
||||
|
@ -190,18 +191,11 @@
|
|||
{
|
||||
await lazyLoader.SetText("Requesting tags");
|
||||
|
||||
var tags = new List<string>();
|
||||
var image = ImageRepository
|
||||
.Get()
|
||||
.Include(x => x.Tags)
|
||||
.First(x => x.Id == CurrentServer.Image.Id);
|
||||
|
||||
foreach (var tag in image.Tags)
|
||||
{
|
||||
tags.Add(tag.Name);
|
||||
}
|
||||
|
||||
Tags = tags.ToArray();
|
||||
Tags = JsonConvert.DeserializeObject<string[]>(image.TagsJson) ?? Array.Empty<string>();
|
||||
Image = image;
|
||||
|
||||
await lazyLoader.SetText("Connecting to console");
|
||||
|
|
|
@ -330,3 +330,26 @@ Wrong here?;Wrong here?
|
|||
A user with this email can not be found;A user with this email can not be found
|
||||
Passwort reset successfull. Check your mail;Passwort reset successfull. Check your mail
|
||||
Discord bot;Discord bot
|
||||
New image;New image
|
||||
Description;Description
|
||||
Uuid;Uuid
|
||||
Enter tag name;Enter tag name
|
||||
Remove;Remove
|
||||
No tags found;No tags found
|
||||
Enter docker image name;Enter docker image name
|
||||
Tags;Tags
|
||||
Docker images;Docker images
|
||||
Default image;Default image
|
||||
Startup command;Startup command
|
||||
Install container;Install container
|
||||
Install entry;Install entry
|
||||
Configuration files;Configuration files
|
||||
Startup detection;Startup detection
|
||||
Stop command;Stop command
|
||||
Successfully saved image;Successfully saved image
|
||||
No docker images found;No docker images found
|
||||
Key;Key
|
||||
Default value;Default value
|
||||
Allocations;Allocations
|
||||
No variables found;No variables found
|
||||
Successfully added image;Successfully added image
|
||||
|
|
Loading…
Reference in a new issue