Merge pull request #156 from Moonlight-Panel/AddServerBackgroundImage
Add dynamic background images for servers
This commit is contained in:
commit
6591bbc927
14 changed files with 1526 additions and 334 deletions
|
@ -20,4 +20,5 @@ public class Image
|
|||
public List<DockerImage> DockerImages { get; set; } = new();
|
||||
public List<ImageVariable> Variables { get; set; } = new();
|
||||
public string TagsJson { get; set; } = "";
|
||||
public string BackgroundImageUrl { get; set; } = "";
|
||||
}
|
1056
Moonlight/App/Database/Migrations/20230609202138_AddBackgroundImageUrlImage.Designer.cs
generated
Normal file
1056
Moonlight/App/Database/Migrations/20230609202138_AddBackgroundImageUrlImage.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 AddBackgroundImageUrlImage : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "BackgroundImageUrl",
|
||||
table: "Images",
|
||||
type: "longtext",
|
||||
nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "BackgroundImageUrl",
|
||||
table: "Images");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -132,6 +132,10 @@ namespace Moonlight.App.Database.Migrations
|
|||
b.Property<int>("Allocations")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("BackgroundImageUrl")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("ConfigFiles")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
|
|
@ -46,6 +46,29 @@ public class ResourcesController : Controller
|
|||
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
[HttpGet("background/{name}")]
|
||||
public async Task<ActionResult> GetBackground([FromRoute] string name)
|
||||
{
|
||||
if (name.Contains(".."))
|
||||
{
|
||||
await SecurityLogService.Log(SecurityLogType.PathTransversal, x =>
|
||||
{
|
||||
x.Add<string>(name);
|
||||
});
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (System.IO.File.Exists(PathBuilder.File("storage", "resources", "public", "background", name)))
|
||||
{
|
||||
var fs = new FileStream(PathBuilder.File("storage", "resources", "public", "background", name), FileMode.Open);
|
||||
|
||||
return File(fs, MimeTypes.GetMimeType(name), name);
|
||||
}
|
||||
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
[HttpGet("bucket/{bucket}/{name}")]
|
||||
public async Task<ActionResult> GetBucket([FromRoute] string bucket, [FromRoute] string name)
|
||||
|
|
|
@ -15,6 +15,11 @@ public class ResourceService
|
|||
{
|
||||
return $"{AppUrl}/api/moonlight/resources/images/{name}";
|
||||
}
|
||||
|
||||
public string BackgroundImage(string name)
|
||||
{
|
||||
return $"{AppUrl}/api/moonlight/resources/background/{name}";
|
||||
}
|
||||
|
||||
public string Avatar(User user)
|
||||
{
|
||||
|
|
39
Moonlight/App/Services/Sessions/DynamicBackgroundService.cs
Normal file
39
Moonlight/App/Services/Sessions/DynamicBackgroundService.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using Logging.Net;
|
||||
using Moonlight.App.Services.Files;
|
||||
|
||||
namespace Moonlight.App.Services.Sessions;
|
||||
|
||||
public class DynamicBackgroundService
|
||||
{
|
||||
public EventHandler OnBackgroundImageChanged { get; set; }
|
||||
public string BackgroundImageUrl { get; private set; }
|
||||
private string DefaultBackgroundImageUrl;
|
||||
|
||||
public DynamicBackgroundService(ResourceService resourceService)
|
||||
{
|
||||
DefaultBackgroundImageUrl = resourceService.BackgroundImage("main.jpg");
|
||||
BackgroundImageUrl = DefaultBackgroundImageUrl;
|
||||
}
|
||||
|
||||
public Task Change(string url)
|
||||
{
|
||||
if(BackgroundImageUrl == url) // Prevent unnecessary updates
|
||||
return Task.CompletedTask;
|
||||
|
||||
BackgroundImageUrl = url;
|
||||
OnBackgroundImageChanged?.Invoke(this, null!);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task Reset()
|
||||
{
|
||||
if(BackgroundImageUrl == DefaultBackgroundImageUrl) // Prevent unnecessary updates
|
||||
return Task.CompletedTask;
|
||||
|
||||
BackgroundImageUrl = DefaultBackgroundImageUrl;
|
||||
OnBackgroundImageChanged?.Invoke(this, null!);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
|
@ -74,6 +74,7 @@
|
|||
<Folder Include="App\ApiClients\CloudPanel\Resources\" />
|
||||
<Folder Include="App\Http\Middleware" />
|
||||
<Folder Include="storage\backups\" />
|
||||
<Folder Include="storage\resources\public\background\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -134,6 +134,7 @@ namespace Moonlight
|
|||
builder.Services.AddScoped<ReCaptchaService>();
|
||||
builder.Services.AddScoped<IpBanService>();
|
||||
builder.Services.AddSingleton<OAuth2Service>();
|
||||
builder.Services.AddScoped<DynamicBackgroundService>();
|
||||
|
||||
builder.Services.AddScoped<SubscriptionService>();
|
||||
builder.Services.AddScoped<SubscriptionAdminService>();
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
@inject ToastService ToastService
|
||||
@inject SmartTranslateService SmartTranslateService
|
||||
@inject IpBanService IpBanService
|
||||
@inject DynamicBackgroundService DynamicBackgroundService
|
||||
|
||||
<GlobalErrorBoundary>
|
||||
@{
|
||||
|
@ -56,7 +57,7 @@
|
|||
<Sidebar></Sidebar>
|
||||
<div class="app-main flex-column flex-row-fluid" id="kt_app_main">
|
||||
<div class="d-flex flex-column flex-column-fluid">
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid">
|
||||
<div id="kt_app_content" class="app-content flex-column-fluid" style="background-position: center; background-size: cover; background-repeat: no-repeat; background-attachment: fixed; background-image: url('@(DynamicBackgroundService.BackgroundImageUrl)')">
|
||||
<div id="kt_app_content_container" class="app-container container-fluid">
|
||||
<div class="mt-10">
|
||||
<SoftErrorBoundary>
|
||||
|
@ -189,6 +190,11 @@
|
|||
{
|
||||
try
|
||||
{
|
||||
DynamicBackgroundService.OnBackgroundImageChanged += async (_, _) =>
|
||||
{
|
||||
await InvokeAsync(StateHasChanged);
|
||||
};
|
||||
|
||||
IsIpBanned = await IpBanService.IsBanned();
|
||||
|
||||
if(IsIpBanned)
|
||||
|
@ -211,7 +217,13 @@
|
|||
|
||||
await SessionService.Register();
|
||||
|
||||
NavigationManager.LocationChanged += (sender, args) => { SessionService.Refresh(); };
|
||||
NavigationManager.LocationChanged += async (_, _) =>
|
||||
{
|
||||
SessionService.Refresh();
|
||||
|
||||
if (!NavigationManager.Uri.Contains("/server/"))
|
||||
await DynamicBackgroundService.Reset();
|
||||
};
|
||||
|
||||
if (User != null)
|
||||
{
|
||||
|
|
|
@ -13,240 +13,250 @@
|
|||
@inject FileDownloadService FileDownloadService
|
||||
|
||||
<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("Export"))"
|
||||
WorkingText="@(SmartTranslateService.Translate("Exporting"))"
|
||||
CssClasses="btn-primary me-3"
|
||||
OnClick="Export">
|
||||
</WButton>
|
||||
<WButton Text="@(SmartTranslateService.Translate("Save"))"
|
||||
WorkingText="@(SmartTranslateService.Translate("Saving"))"
|
||||
CssClasses="btn-success"
|
||||
OnClick="Save">
|
||||
</WButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</LazyLoader>
|
||||
<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 class="mb-10">
|
||||
<label class="form-label">
|
||||
<TL>Background image url</TL>
|
||||
</label>
|
||||
<input
|
||||
@bind="Image.BackgroundImageUrl"
|
||||
type="text"
|
||||
class="form-control"
|
||||
placeholder="@(SmartTranslateService.Translate("Leave empty for the default background image"))">
|
||||
</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("Export"))"
|
||||
WorkingText="@(SmartTranslateService.Translate("Exporting"))"
|
||||
CssClasses="btn-primary me-3"
|
||||
OnClick="Export">
|
||||
</WButton>
|
||||
<WButton Text="@(SmartTranslateService.Translate("Save"))"
|
||||
WorkingText="@(SmartTranslateService.Translate("Saving"))"
|
||||
CssClasses="btn-success"
|
||||
OnClick="Save">
|
||||
</WButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</LazyLoader>
|
||||
</div>
|
||||
</OnlyAdmin>
|
||||
|
||||
@code
|
||||
|
@ -330,7 +340,7 @@
|
|||
{
|
||||
Image!.DockerImages.Remove(image);
|
||||
}
|
||||
|
||||
|
||||
private void AddVariable()
|
||||
{
|
||||
Image!.Variables.Add(ImageVariable);
|
||||
|
@ -361,7 +371,7 @@
|
|||
{
|
||||
Image.TagsJson = JsonConvert.SerializeObject(Tags);
|
||||
Image.InstallScript = await Editor.GetData();
|
||||
|
||||
|
||||
var json = JsonConvert.SerializeObject(Image, Formatting.Indented);
|
||||
await FileDownloadService.DownloadString(Image.Name + ".json", json);
|
||||
}
|
||||
|
|
|
@ -125,111 +125,115 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!--d-flex flex-row mb-5-->
|
||||
<div class="card mb-5">
|
||||
<div class="card-header card-header-stretch">
|
||||
<div class="card-title d-flex align-items-center">
|
||||
<h3 class="fw-bold m-0 text-gray-800">
|
||||
<TL>Create something new</TL>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body pt-3">
|
||||
<div class="flex-row">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="symbol symbol-50px me-3">
|
||||
<i class="bx bx-md bx-server"></i>
|
||||
</div>
|
||||
<div class="d-flex justify-content-start flex-column">
|
||||
<a href="/servers/create" class="text-gray-800 text-hover-primary mb-1 fs-5">
|
||||
<TL>Create a gameserver</TL>
|
||||
</a>
|
||||
<span class="text-gray-400 fw-semibold d-block fs-6">
|
||||
<TL>A new gameserver in just a few minutes</TL>
|
||||
</span>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card mb-5">
|
||||
<div class="card-header card-header-stretch">
|
||||
<div class="card-title d-flex align-items-center">
|
||||
<h3 class="fw-bold m-0 text-gray-800">
|
||||
<TL>Create something new</TL>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator mb-2 mt-2"></div>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="symbol symbol-50px me-3">
|
||||
<i class="bx bx-md bx-globe"></i>
|
||||
</div>
|
||||
<div class="d-flex justify-content-start flex-column">
|
||||
<a href="/webspaces/create" class="text-gray-800 text-hover-primary mb-1 fs-5">
|
||||
<TL>Create a webspace</TL>
|
||||
</a>
|
||||
<span class="text-gray-400 fw-semibold d-block fs-6">
|
||||
<TL>Make your own websites with a webspace</TL>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator mb-2 mt-2"></div>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="symbol symbol-50px me-3">
|
||||
<i class="bx bx-md bx-purchase-tag"></i>
|
||||
</div>
|
||||
<div class="d-flex justify-content-start flex-column">
|
||||
<a href="/domains/create" class="text-gray-800 text-hover-primary mb-1 fs-5">
|
||||
<TL>Create a domain</TL>
|
||||
</a>
|
||||
<span class="text-gray-400 fw-semibold d-block fs-6">
|
||||
<TL>Make your servvices accessible throught your own domain</TL>
|
||||
</span>
|
||||
<div class="card-body pt-3">
|
||||
<div class="flex-row">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="symbol symbol-50px me-3">
|
||||
<i class="bx bx-md bx-server"></i>
|
||||
</div>
|
||||
<div class="d-flex justify-content-start flex-column">
|
||||
<a href="/servers/create" class="text-gray-800 text-hover-primary mb-1 fs-5">
|
||||
<TL>Create a gameserver</TL>
|
||||
</a>
|
||||
<span class="text-gray-400 fw-semibold d-block fs-6">
|
||||
<TL>A new gameserver in just a few minutes</TL>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator mb-2 mt-2"></div>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="symbol symbol-50px me-3">
|
||||
<i class="bx bx-md bx-globe"></i>
|
||||
</div>
|
||||
<div class="d-flex justify-content-start flex-column">
|
||||
<a href="/webspaces/create" class="text-gray-800 text-hover-primary mb-1 fs-5">
|
||||
<TL>Create a webspace</TL>
|
||||
</a>
|
||||
<span class="text-gray-400 fw-semibold d-block fs-6">
|
||||
<TL>Make your own websites with a webspace</TL>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator mb-2 mt-2"></div>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="symbol symbol-50px me-3">
|
||||
<i class="bx bx-md bx-purchase-tag"></i>
|
||||
</div>
|
||||
<div class="d-flex justify-content-start flex-column">
|
||||
<a href="/domains/create" class="text-gray-800 text-hover-primary mb-1 fs-5">
|
||||
<TL>Create a domain</TL>
|
||||
</a>
|
||||
<span class="text-gray-400 fw-semibold d-block fs-6">
|
||||
<TL>Make your services accessible through your own domain</TL>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card mb-5">
|
||||
<div class="card-header card-header-stretch">
|
||||
<div class="card-title d-flex align-items-center">
|
||||
<h3 class="fw-bold m-0 text-gray-800">
|
||||
<TL>Manage your services</TL>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body pt-3">
|
||||
<div class="flex-row">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="symbol symbol-50px me-3">
|
||||
<i class="bx bx-md bx-server"></i>
|
||||
</div>
|
||||
<div class="d-flex justify-content-start flex-column">
|
||||
<a href="/servers" class="text-gray-800 text-hover-primary mb-1 fs-5">
|
||||
<TL>Manage your gameservers</TL>
|
||||
</a>
|
||||
<span class="text-gray-400 fw-semibold d-block fs-6">
|
||||
<TL>Adjust your gameservers</TL>
|
||||
</span>
|
||||
<div class="col">
|
||||
<div class="card mb-5">
|
||||
<div class="card-header card-header-stretch">
|
||||
<div class="card-title d-flex align-items-center">
|
||||
<h3 class="fw-bold m-0 text-gray-800">
|
||||
<TL>Manage your services</TL>
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator mb-2 mt-2"></div>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="symbol symbol-50px me-3">
|
||||
<i class="bx bx-md bx-globe"></i>
|
||||
</div>
|
||||
<div class="d-flex justify-content-start flex-column">
|
||||
<a href="/webspaces" class="text-gray-800 text-hover-primary mb-1 fs-5">
|
||||
<TL>Manage your webspaces</TL>
|
||||
</a>
|
||||
<span class="text-gray-400 fw-semibold d-block fs-6">
|
||||
<TL>Modify the content of your webspaces</TL>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator mb-2 mt-2"></div>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="symbol symbol-50px me-3">
|
||||
<i class="bx bx-md bx-purchase-tag"></i>
|
||||
</div>
|
||||
<div class="d-flex justify-content-start flex-column">
|
||||
<a href="/domains" class="text-gray-800 text-hover-primary mb-1 fs-5">
|
||||
<TL>Manage your domains</TL>
|
||||
</a>
|
||||
<span class="text-gray-400 fw-semibold d-block fs-6">
|
||||
<TL>Add, edit and delete dns records</TL>
|
||||
</span>
|
||||
<div class="card-body pt-3">
|
||||
<div class="flex-row">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="symbol symbol-50px me-3">
|
||||
<i class="bx bx-md bx-server"></i>
|
||||
</div>
|
||||
<div class="d-flex justify-content-start flex-column">
|
||||
<a href="/servers" class="text-gray-800 text-hover-primary mb-1 fs-5">
|
||||
<TL>Manage your gameservers</TL>
|
||||
</a>
|
||||
<span class="text-gray-400 fw-semibold d-block fs-6">
|
||||
<TL>Adjust your gameservers</TL>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator mb-2 mt-2"></div>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="symbol symbol-50px me-3">
|
||||
<i class="bx bx-md bx-globe"></i>
|
||||
</div>
|
||||
<div class="d-flex justify-content-start flex-column">
|
||||
<a href="/webspaces" class="text-gray-800 text-hover-primary mb-1 fs-5">
|
||||
<TL>Manage your webspaces</TL>
|
||||
</a>
|
||||
<span class="text-gray-400 fw-semibold d-block fs-6">
|
||||
<TL>Modify the content of your webspaces</TL>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator mb-2 mt-2"></div>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="symbol symbol-50px me-3">
|
||||
<i class="bx bx-md bx-purchase-tag"></i>
|
||||
</div>
|
||||
<div class="d-flex justify-content-start flex-column">
|
||||
<a href="/domains" class="text-gray-800 text-hover-primary mb-1 fs-5">
|
||||
<TL>Manage your domains</TL>
|
||||
</a>
|
||||
<span class="text-gray-400 fw-semibold d-block fs-6">
|
||||
<TL>Add, edit and delete dns records</TL>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
@using Moonlight.App.Helpers.Wings.Enums
|
||||
@using Moonlight.App.Repositories
|
||||
@using Moonlight.App.Services
|
||||
@using Moonlight.App.Services.Sessions
|
||||
@using Moonlight.Shared.Components.Xterm
|
||||
@using Moonlight.Shared.Components.ServerControl
|
||||
@using Newtonsoft.Json
|
||||
|
@ -20,6 +21,7 @@
|
|||
@inject EventSystem Event
|
||||
@inject ServerService ServerService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject DynamicBackgroundService DynamicBackgroundService
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
|
@ -291,6 +293,11 @@
|
|||
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
if (string.IsNullOrEmpty(Image.BackgroundImageUrl))
|
||||
await DynamicBackgroundService.Reset();
|
||||
else
|
||||
await DynamicBackgroundService.Change(Image.BackgroundImageUrl);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
BIN
Moonlight/defaultstorage/resources/public/background/main.jpg
Normal file
BIN
Moonlight/defaultstorage/resources/public/background/main.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 MiB |
Loading…
Reference in a new issue