Refactored frontend to work with the latest mooncore changes

This commit is contained in:
2025-07-16 20:46:45 +02:00
parent 383d4bb24b
commit 61253919cf
93 changed files with 3347 additions and 1661 deletions

View File

@@ -9,13 +9,23 @@
<ItemGroup>
<ProjectReference Include="..\MoonlightServers.ApiServer\MoonlightServers.ApiServer.csproj"/>
<ProjectReference Include="..\MoonlightServers.Frontend.Runtime\MoonlightServers.Frontend.Runtime.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.7" />
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.8"/>
<PackageReference Include="MoonCore.PluginFramework.Generator" Version="1.0.2"/>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.7" PrivateAssets="all"/>
</ItemGroup>
<ItemGroup>
<Content Update="Properties\launchSettings.json">
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
</Project>

View File

@@ -13,7 +13,7 @@ using MoonlightServers.Shared.Http.Responses.Admin.NodeAllocations;
namespace MoonlightServers.ApiServer.Http.Controllers.Admin.Nodes;
[ApiController]
[Route("api/admin/servers/nodes")]
[Route("api/admin/servers/nodes/{nodeId:int}/allocations")]
public class NodeAllocationsController : Controller
{
private readonly DatabaseRepository<Node> NodeRepository;
@@ -28,7 +28,7 @@ public class NodeAllocationsController : Controller
AllocationRepository = allocationRepository;
}
[HttpGet("{nodeId:int}/allocations")]
[HttpGet("")]
[Authorize(Policy = "permissions:admin.servers.nodes.get")]
public async Task<IPagedData<NodeAllocationResponse>> Get(
[FromRoute] int nodeId,
@@ -59,7 +59,7 @@ public class NodeAllocationsController : Controller
};
}
[HttpGet("{nodeId:int}/allocations/{id:int}")]
[HttpGet("{id:int}")]
[Authorize(Policy = "permissions:admin.servers.nodes.get")]
public async Task<NodeAllocationResponse> GetSingle([FromRoute] int nodeId, [FromRoute] int id)
{
@@ -74,7 +74,7 @@ public class NodeAllocationsController : Controller
return AllocationMapper.ToNodeAllocation(allocation);
}
[HttpPost("{nodeId:int}/allocations")]
[HttpPost("")]
[Authorize(Policy = "permissions:admin.servers.nodes.create")]
public async Task<NodeAllocationResponse> Create(
[FromRoute] int nodeId,
@@ -95,7 +95,7 @@ public class NodeAllocationsController : Controller
return AllocationMapper.ToNodeAllocation(finalAllocation);
}
[HttpPatch("{nodeId:int}/allocations/{id:int}")]
[HttpPatch("{id:int}")]
public async Task<NodeAllocationResponse> Update(
[FromRoute] int nodeId,
[FromRoute] int id,
@@ -116,7 +116,7 @@ public class NodeAllocationsController : Controller
return AllocationMapper.ToNodeAllocation(allocation);
}
[HttpDelete("{nodeId:int}/allocations/{id:int}")]
[HttpDelete("{id:int}")]
public async Task Delete([FromRoute] int nodeId, [FromRoute] int id)
{
var allocation = await AllocationRepository
@@ -130,7 +130,7 @@ public class NodeAllocationsController : Controller
await AllocationRepository.Remove(allocation);
}
[HttpPost("{nodeId:int}/allocations/range")]
[HttpPost("range")]
public async Task CreateRange([FromRoute] int nodeId, [FromBody] CreateNodeAllocationRangeRequest rangeRequest)
{
var node = await NodeRepository
@@ -168,7 +168,7 @@ public class NodeAllocationsController : Controller
await AllocationRepository.RunTransaction(async set => { await set.AddRangeAsync(allocations); });
}
[HttpDelete("{nodeId:int}/allocations/all")]
[HttpDelete("all")]
public async Task DeleteAll([FromRoute] int nodeId)
{
var allocations = AllocationRepository
@@ -179,7 +179,7 @@ public class NodeAllocationsController : Controller
await AllocationRepository.RunTransaction(set => { set.RemoveRange(allocations); });
}
[HttpGet("{nodeId:int}/allocations/free")]
[HttpGet("free")]
[Authorize(Policy = "permissions:admin.servers.nodes.get")]
public async Task<IPagedData<NodeAllocationResponse>> GetFree(
[FromRoute] int nodeId,

View File

@@ -96,7 +96,7 @@ public class NodesController : Controller
if (node == null)
throw new HttpApiException("No node with this id found", 404);
node = NodeMapper.Merge(request, node);
NodeMapper.Merge(request, node);
await NodeRepository.Update(node);
return NodeMapper.ToAdminNodeResponse(node);

View File

@@ -229,7 +229,7 @@ public class ServersController : Controller
if (server == null)
throw new HttpApiException("No server with that id found", 404);
server = ServerMapper.Merge(request, server);
ServerMapper.Merge(request, server);
var allocations = new List<Allocation>();

View File

@@ -135,7 +135,7 @@ public class StarDockerImagesController : Controller
if (dockerImage == null)
throw new HttpApiException("No star docker image with this id found", 404);
dockerImage = DockerImageMapper.Merge(request, dockerImage);
DockerImageMapper.Merge(request, dockerImage);
await DockerImageRepository.Update(dockerImage);
return DockerImageMapper.ToAdminResponse(dockerImage);

View File

@@ -133,7 +133,7 @@ public class StarVariablesController : Controller
if (starVariable == null)
throw new HttpApiException("No variable with this id found", 404);
starVariable = StarVariableMapper.Merge(request, starVariable);
StarVariableMapper.Merge(request, starVariable);
await VariableRepository.Update(starVariable);
return StarVariableMapper.ToAdminResponse(starVariable);

View File

@@ -106,7 +106,7 @@ public class StarsController : Controller
if (star == null)
throw new HttpApiException("No star with that id found", 404);
star = StarMapper.Merge(request, star);
StarMapper.Merge(request, star);
await StarRepository.Update(star);
return StarMapper.ToAdminResponse(star);

View File

@@ -15,7 +15,7 @@ namespace MoonlightServers.ApiServer.Http.Controllers.Client;
[Authorize]
[ApiController]
[Route("api/client/servers")]
[Route("api/client/servers/{serverId:int}/files")]
public class FilesController : Controller
{
private readonly DatabaseRepository<Server> ServerRepository;
@@ -36,7 +36,7 @@ public class FilesController : Controller
AuthorizeService = authorizeService;
}
[HttpGet("{serverId:int}/files/list")]
[HttpGet("list")]
public async Task<ServerFilesEntryResponse[]> List([FromRoute] int serverId, [FromQuery] string path)
{
var server = await GetServerById(serverId, ServerPermissionType.Read);
@@ -47,13 +47,13 @@ public class FilesController : Controller
{
Name = x.Name,
Size = x.Size,
IsFile = x.IsFile,
IsFolder = x.IsFolder,
CreatedAt = x.CreatedAt,
UpdatedAt = x.UpdatedAt
}).ToArray();
}
[HttpPost("{serverId:int}/files/move")]
[HttpPost("move")]
public async Task Move([FromRoute] int serverId, [FromQuery] string oldPath, [FromQuery] string newPath)
{
var server = await GetServerById(serverId, ServerPermissionType.ReadWrite);
@@ -61,7 +61,7 @@ public class FilesController : Controller
await ServerFileSystemService.Move(server, oldPath, newPath);
}
[HttpDelete("{serverId:int}/files/delete")]
[HttpDelete("delete")]
public async Task Delete([FromRoute] int serverId, [FromQuery] string path)
{
var server = await GetServerById(serverId, ServerPermissionType.ReadWrite);
@@ -69,7 +69,7 @@ public class FilesController : Controller
await ServerFileSystemService.Delete(server, path);
}
[HttpPost("{serverId:int}/files/mkdir")]
[HttpPost("mkdir")]
public async Task Mkdir([FromRoute] int serverId, [FromQuery] string path)
{
var server = await GetServerById(serverId, ServerPermissionType.ReadWrite);
@@ -77,7 +77,15 @@ public class FilesController : Controller
await ServerFileSystemService.Mkdir(server, path);
}
[HttpGet("{serverId:int}/files/upload")]
[HttpPost("touch")]
public async Task Touch([FromRoute] int serverId, [FromQuery] string path)
{
var server = await GetServerById(serverId, ServerPermissionType.ReadWrite);
await ServerFileSystemService.Mkdir(server, path);
}
[HttpGet("upload")]
public async Task<ServerFilesUploadResponse> Upload([FromRoute] int serverId)
{
var server = await GetServerById(serverId, ServerPermissionType.ReadWrite);
@@ -104,7 +112,7 @@ public class FilesController : Controller
};
}
[HttpGet("{serverId:int}/files/download")]
[HttpGet("download")]
public async Task<ServerFilesDownloadResponse> Download([FromRoute] int serverId, [FromQuery] string path)
{
var server = await GetServerById(serverId, ServerPermissionType.Read);
@@ -132,7 +140,7 @@ public class FilesController : Controller
};
}
[HttpPost("{serverId:int}/files/compress")]
[HttpPost("compress")]
public async Task Compress([FromRoute] int serverId, [FromBody] ServerFilesCompressRequest request)
{
var server = await GetServerById(serverId, ServerPermissionType.ReadWrite);
@@ -143,7 +151,7 @@ public class FilesController : Controller
await ServerFileSystemService.Compress(server, type, request.Items, request.Destination);
}
[HttpPost("{serverId:int}/files/decompress")]
[HttpPost("decompress")]
public async Task Decompress([FromRoute] int serverId, [FromBody] ServerFilesDecompressRequest request)
{
var server = await GetServerById(serverId, ServerPermissionType.ReadWrite);

View File

@@ -10,5 +10,5 @@ public static partial class AllocationMapper
{
public static partial NodeAllocationResponse ToNodeAllocation(Allocation allocation);
public static partial Allocation ToAllocation(CreateNodeAllocationRequest request);
public static partial Allocation Merge(UpdateNodeAllocationRequest request, Allocation allocation);
public static partial void Merge(UpdateNodeAllocationRequest request, Allocation allocation);
}

View File

@@ -10,5 +10,5 @@ public static partial class DockerImageMapper
{
public static partial StarDockerImageDetailResponse ToAdminResponse(StarDockerImage dockerImage);
public static partial StarDockerImage ToDockerImage(CreateStarDockerImageRequest request);
public static partial StarDockerImage Merge(UpdateStarDockerImageRequest request, StarDockerImage variable);
public static partial void Merge(UpdateStarDockerImageRequest request, StarDockerImage variable);
}

View File

@@ -10,5 +10,5 @@ public static partial class NodeMapper
{
public static partial NodeResponse ToAdminNodeResponse(Node node);
public static partial Node ToNode(CreateNodeRequest request);
public static partial Node Merge(UpdateNodeRequest request, Node node);
public static partial void Merge(UpdateNodeRequest request, Node node);
}

View File

@@ -21,5 +21,5 @@ public static partial class ServerMapper
private static partial ServerResponse ToAdminServerResponse_Internal(Server server);
public static partial Server ToServer(CreateServerRequest request);
public static partial Server Merge(UpdateServerRequest request, Server server);
public static partial void Merge(UpdateServerRequest request, Server server);
}

View File

@@ -11,5 +11,5 @@ public static partial class StarMapper
{
public static partial StarDetailResponse ToAdminResponse(Star star);
public static partial Star ToStar(CreateStarRequest request);
public static partial Star Merge(UpdateStarRequest request, Star star);
public static partial void Merge(UpdateStarRequest request, Star star);
}

View File

@@ -10,5 +10,5 @@ public static partial class StarVariableMapper
{
public static partial StarVariableDetailResponse ToAdminResponse(StarVariable variable);
public static partial StarVariable ToStarVariable(CreateStarVariableRequest request);
public static partial StarVariable Merge(UpdateStarVariableRequest request, StarVariable variable);
public static partial void Merge(UpdateStarVariableRequest request, StarVariable variable);
}

View File

@@ -47,4 +47,8 @@
<None Remove="storage\**\*"/>
</ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="Properties\launchSettings.json" />
</ItemGroup>
</Project>

View File

@@ -60,6 +60,15 @@ public class ServerFileSystemService
);
}
public async Task Touch(Server server, string path)
{
using var apiClient = await GetApiClient(server);
await apiClient.Post(
$"api/servers/{server.Id}/files/touch?path={path}"
);
}
public async Task Compress(Server server, CompressType type, string[] items, string destination)
{
using var apiClient = await GetApiClient(server);

View File

@@ -35,11 +35,11 @@ public class PluginStartup : IPluginStartup
{
Scripts =
[
"js/XtermBlazor.min.js",
"js/addon-fit.js",
"js/moonlightServers.js"
"/_content/MoonlightServers.Frontend/js/XtermBlazor.min.js",
"/_content/MoonlightServers.Frontend/js/addon-fit.js",
"/_content/MoonlightServers.Frontend/js/moonlightServers.js"
],
Styles = ["css/XtermBlazor.min.css"]
Styles = ["/_content/MoonlightServers.Frontend/css/XtermBlazor.min.css"]
});
}

View File

@@ -35,7 +35,7 @@ public class ServerFileSystem
.Select(x => new ServerFileSystemResponse()
{
Name = x.Name,
IsFile = x.IsFile,
IsFolder = x.IsDirectory,
Size = x.Size,
UpdatedAt = x.LastChanged,
CreatedAt = x.CreatedAt
@@ -73,6 +73,24 @@ public class ServerFileSystem
return Task.CompletedTask;
}
public Task Touch(string inputPath)
{
var path = Normalize(inputPath);
var parentDirectory = Path.GetDirectoryName(path);
if (!string.IsNullOrEmpty(parentDirectory) && parentDirectory != "/")
FileSystem.MkdirAll(parentDirectory, FilePermissions.ACCESSPERMS);
FileSystem.OpenFileWrite(
path,
_ => { },
OpenFlags.O_CREAT
); // We use these custom flags to ensure we aren't overwriting the file
return Task.CompletedTask;
}
public Task CreateChunk(string inputPath, long totalSize, long positionToSkip, Stream chunkStream)
{
var path = Normalize(inputPath);
@@ -259,10 +277,7 @@ public class ServerFileSystem
outputStream.PutNextEntry(entry);
FileSystem.OpenFileRead(path, stream =>
{
stream.CopyTo(outputStream);
});
FileSystem.OpenFileRead(path, stream => { stream.CopyTo(outputStream); });
outputStream.CloseEntry();
}
@@ -274,10 +289,10 @@ public class ServerFileSystem
{
var entry = inputStream.GetNextEntry();
if(entry == null)
if (entry == null)
break;
if(entry.IsDirectory)
if (entry.IsDirectory)
continue;
var fileDestination = Path.Combine(destination, entry.Name);
@@ -304,10 +319,10 @@ public class ServerFileSystem
{
var entry = inputStream.GetNextEntry();
if(entry == null)
if (entry == null)
break;
if(entry.IsDirectory)
if (entry.IsDirectory)
continue;
var fileDestination = Path.Combine(destination, entry.Name);

View File

@@ -11,7 +11,7 @@ namespace MoonlightServers.Daemon.Http.Controllers.Servers;
[Authorize]
[ApiController]
[Route("api/servers")]
[Route("api/servers/{id:int}/files")]
public class ServerFileSystemController : Controller
{
private readonly ServerService ServerService;
@@ -21,7 +21,7 @@ public class ServerFileSystemController : Controller
ServerService = serverService;
}
[HttpGet("{id:int}/files/list")]
[HttpGet("list")]
public async Task<ServerFileSystemResponse[]> List([FromRoute] int id, [FromQuery] string path = "")
{
var fileSystem = await GetFileSystemById(id);
@@ -29,7 +29,7 @@ public class ServerFileSystemController : Controller
return await fileSystem.List(path);
}
[HttpPost("{id:int}/files/move")]
[HttpPost("move")]
public async Task Move([FromRoute] int id, [FromQuery] string oldPath, [FromQuery] string newPath)
{
var fileSystem = await GetFileSystemById(id);
@@ -37,7 +37,7 @@ public class ServerFileSystemController : Controller
await fileSystem.Move(oldPath, newPath);
}
[HttpDelete("{id:int}/files/delete")]
[HttpDelete("delete")]
public async Task Delete([FromRoute] int id, [FromQuery] string path)
{
var fileSystem = await GetFileSystemById(id);
@@ -45,7 +45,7 @@ public class ServerFileSystemController : Controller
await fileSystem.Delete(path);
}
[HttpPost("{id:int}/files/mkdir")]
[HttpPost("mkdir")]
public async Task Mkdir([FromRoute] int id, [FromQuery] string path)
{
var fileSystem = await GetFileSystemById(id);
@@ -53,7 +53,15 @@ public class ServerFileSystemController : Controller
await fileSystem.Mkdir(path);
}
[HttpPost("{id:int}/files/compress")]
[HttpPost("touch")]
public async Task Touch([FromRoute] int id, [FromQuery] string path)
{
var fileSystem = await GetFileSystemById(id);
await fileSystem.Touch(path);
}
[HttpPost("compress")]
public async Task Compress([FromRoute] int id, [FromBody] ServerFilesCompressRequest request)
{
var fileSystem = await GetFileSystemById(id);
@@ -65,7 +73,7 @@ public class ServerFileSystemController : Controller
);
}
[HttpPost("{id:int}/files/decompress")]
[HttpPost("decompress")]
public async Task Decompress([FromRoute] int id, [FromBody] ServerFilesDecompressRequest request)
{
var fileSystem = await GetFileSystemById(id);

View File

@@ -3,7 +3,7 @@ namespace MoonlightServers.DaemonShared.DaemonSide.Http.Responses.Servers;
public class ServerFileSystemResponse
{
public string Name { get; set; }
public bool IsFile { get; set; }
public bool IsFolder { get; set; }
public long Size { get; set; }
public DateTime CreatedAt { get; set; }

View File

@@ -7,9 +7,10 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.5"/>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.5" PrivateAssets="all"/>
<PackageReference Include="MoonCore.PluginFramework" Version="1.0.8" />
<PackageReference Include="MoonCore.PluginFramework.Generator" Version="1.0.2" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.7" PrivateAssets="all"/>
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,30 @@
// extract-classes.js
const fs = require('fs');
module.exports = (opts = {}) => {
const classSet = new Set();
return {
postcssPlugin: 'extract-tailwind-classes',
Rule(rule) {
const selectorParser = require('postcss-selector-parser');
selectorParser(selectors => {
selectors.walkClasses(node => {
classSet.add(node.value);
});
}).processSync(rule.selector);
},
OnceExit() {
const classArray = Array.from(classSet).sort();
if (!fs.existsSync("../../MoonlightServers.Frontend/Styles/mappings")){
fs.mkdirSync("../../MoonlightServers.Frontend/Styles/mappings");
}
fs.writeFileSync('../../MoonlightServers.Frontend/mappings/classes.map', classArray.join('\n'));
console.log(`✅ Extracted ${classArray.length} Tailwind classes to tailwind-classes.txt`);
}
};
};
module.exports.postcss = true;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
{
"name": "styles",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"tailwind": "npx postcss styles.css -o ../wwwroot/css/style.min.css --watch",
"tailwind-build": "npx postcss styles.css -o ../wwwroot/css/style.min.css",
"mappings": "EXTRACT_CLASSES=true npx postcss styles.css -o ../wwwroot/css/style.min.css "
},
"author": "",
"license": "ISC",
"dependencies": {
"@tailwindcss/postcss": "^4.1.11",
"flyonui": "^2.2.0",
"tailwindcss": "^4.1.11",
"postcss": "^8.5.6",
"postcss-cli": "^11.0.1",
"postcss-selector-parser": "^7.1.0"
},
"devDependencies": {
}
}

View File

@@ -0,0 +1,11 @@
const tailwindcss = require('@tailwindcss/postcss');
const extractClasses = require('./extract-classes');
module.exports = {
plugins: [
tailwindcss
],
};
if(process.env.EXTRACT_CLASSES === "true")
module.exports.plugins.push(extractClasses);

View File

@@ -0,0 +1,113 @@
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=fallback') layer(base);
@import url('https://fonts.googleapis.com/css2?family=Source+Code+Pro:ital,wght@0,200..900;1,200..900&display=swap') layer(base);
@import url("https://cdn.jsdelivr.net/npm/lucide-static/font/lucide.css") layer(base);
@import "tailwindcss";
@import "./node_modules/flyonui/variants.css";
@import "./theme.css";
@theme {
--font-inter: "Inter", var(--font-sans);
--font-scp: "Source Code Pro", var(--font-mono);
--color-background: var(--mooncore-color-background);
--color-base-150: var(--mooncore-color-base-150);
--color-base-250: var(--mooncore-color-base-250);
}
@plugin "flyonui" {
themes: mooncore --default;
}
@source "./node_modules/flyonui/dist/index.js";
@source "../**/*.razor";
@source "../**/*.cs";
@source "../**/*.html";
@source "./mappings/*.map";
@source "../../MoonlightServers.Frontend/**/*.cs";
@source "../../MoonlightServers.Frontend/**/*.html";
@source "../../MoonlightServers.Frontend/**/*.razor";
@source "../../MoonlightServers.Frontend/Styles/**/*.map";
@source "../../MoonlightServers.ApiServer/**/*.razor";
#blazor-error-ui {
display: none;
}
#blazor-loader-label:after {
content: var(--blazor-load-percentage-text, "Loading");
}
#blazor-loader-progress {
width: var(--blazor-load-percentage, 0%);
}
@plugin "flyonui/theme" {
name: "mooncore";
default: true;
prefersdark: true;
color-scheme: "dark";
--color-base-100: var(--mooncore-color-base-100);
--color-base-200: var(--mooncore-color-base-200);
--color-base-300: var(--mooncore-color-base-300);
--color-base-content: var(--mooncore-color-base-content);
--color-primary: var(--mooncore-color-primary);
--color-primary-content: var(--mooncore-color-primary-content);
--color-secondary: var(--mooncore-color-secondary);
--color-secondary-content: var(--mooncore-color-secondary-content);
--color-accent: var(--mooncore-color-accent);
--color-accent-content: var(--mooncore-color-accent-content);
--color-neutral: var(--mooncore-color-neutral);
--color-neutral-content: var(--mooncore-color-neutral-content);
--color-info: var(--mooncore-color-info);
--color-info-content: var(--mooncore-color-info-content);
--color-success: var(--mooncore-color-success);
--color-success-content: var(--mooncore-color-success-content);
--color-warning: var(--mooncore-color-warning);
--color-warning-content: var(--mooncore-color-warning-content);
--color-error: var(--mooncore-color-error);
--color-error-content: var(--mooncore-color-error-content);
--radius-selector: var(--mooncore-radius-selector);
--radius-field: var(--mooncore-radius-field);
--radius-box: var(--mooncore-radius-box);
--size-selector: var(--mooncore-size-selector);
--size-field: var(--mooncore-size-field);
--border: var(--mooncore-border);
--depth: var(--mooncore-depth);
--noise: var(--mooncore-noise);
}
@layer utilities {
.btn {
@apply text-sm font-medium inline-flex items-center justify-center;
}
.checkbox {
@apply border-base-content/30 bg-base-100;
}
.input {
@apply !border-base-content/20 border-2 ring-0! outline-0! focus:border-primary! focus-within:border-primary! bg-base-200/50;
}
.advance-select-toggle {
@apply !border-base-content/20 border-2 ring-0! outline-0! focus:border-primary! focus-within:border-primary! bg-base-200/50;
}
.table {
:where(th, td) {
@apply py-1.5;
}
}
.dropdown-item {
@apply px-2.5 py-1.5 text-sm;
}
.dropdown-menu {
@apply bg-base-150;
}
}

View File

@@ -0,0 +1,33 @@
@theme {
--mooncore-color-background: #0c0f18;
--mooncore-color-base-100: #1e2b47;
--mooncore-color-base-150: #1a2640;
--mooncore-color-base-200: #101a2e;
--mooncore-color-base-250: #0f1729;
--mooncore-color-base-300: #0c1221;
--mooncore-color-base-content: #dde5f5;
--mooncore-color-primary: oklch(.511 .262 276.966);
--mooncore-color-primary-content: #dde5f5;
--mooncore-color-secondary: oklch(37% 0.034 259.733);
--mooncore-color-secondary-content: #dde5f5;
--mooncore-color-accent: oklch(.627 .265 303.9);
--mooncore-color-accent-content: #dde5f5;
--mooncore-color-neutral: #dde5f5;
--mooncore-color-neutral-content: oklch(14% 0.005 285.823);
--mooncore-color-info: oklch(.546 .245 262.881);
--mooncore-color-info-content: #dde5f5;
--mooncore-color-success: oklch(.627 .194 149.214);
--mooncore-color-success-content: #dde5f5;
--mooncore-color-warning: oklch(.828 .189 84.429);
--mooncore-color-warning-content: #dde5f5;
--mooncore-color-error: oklch(.586 .253 17.585);
--mooncore-color-error-content: #dde5f5;
--mooncore-radius-selector: 0.25rem;
--mooncore-radius-field: 0.5rem;
--mooncore-radius-box: 0.5rem;
--mooncore-size-selector: 0.25rem;
--mooncore-size-field: 0.25rem;
--mooncore-border: 1px;
--mooncore-depth: 0;
--mooncore-noise: 0;
}

View File

@@ -1,8 +1,6 @@
/*
using System.IO.Enumeration;
using MoonCore.Blazor.FlyonUi.Helpers;
using MoonCore.Blazor.Tailwind.Fm;
using MoonCore.Blazor.Tailwind.Fm.Models;
using MoonCore.Blazor.Tailwind.Services;
using MoonCore.Helpers;
using MoonlightServers.Frontend.Services;
@@ -146,4 +144,4 @@ public class ServerFileSystemProvider : IFileSystemProvider, ICompressFileSystem
destination
);
}
}
}*/

View File

@@ -0,0 +1,63 @@
using MoonCore.Blazor.FlyonUi.Files;
using MoonCore.Blazor.FlyonUi.Files.Manager;
using MoonlightServers.Frontend.Services;
namespace MoonlightServers.Frontend.Helpers;
public class ServerFsAccess : IFsAccess
{
private readonly int Id;
private readonly ServerFileSystemService FileSystemService;
public ServerFsAccess(int id, ServerFileSystemService fileSystemService)
{
Id = id;
FileSystemService = fileSystemService;
}
public Task CreateFile(string path)
=> FileSystemService.Touch(Id, path);
public Task CreateDirectory(string path)
=> FileSystemService.Mkdir(Id, path);
public async Task<FsEntry[]> List(string path)
{
var entries = await FileSystemService.List(Id, path);
return entries.Select(x => new FsEntry()
{
Name = x.Name,
Size = x.Size,
CreatedAt = x.CreatedAt,
IsFolder = x.IsFolder,
UpdatedAt = x.UpdatedAt
}).ToArray();
}
public Task Move(string oldPath, string newPath)
=> FileSystemService.Move(Id, oldPath, newPath);
public Task Read(string path, Func<Stream, Task> onHandleData)
{
throw new NotImplementedException();
}
public Task Write(string path, Stream dataStream)
{
throw new NotImplementedException();
}
public Task Delete(string path)
=> FileSystemService.Delete(Id, path);
public Task UploadChunk(string path, int chunkId, long chunkSize, long totalSize, byte[] data)
{
throw new NotImplementedException();
}
public Task<byte[]> DownloadChunk(string path, int chunkId, long chunkSize)
{
throw new NotImplementedException();
}
}

View File

@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
@@ -16,21 +16,11 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.7"/>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="9.0.5" />
<PackageReference Include="Moonlight.Client" Version="2.1.3"/>
<PackageReference Include="XtermBlazor" Version="2.1.2" />
</ItemGroup>
<ItemGroup>
<_ContentIncludedByDefault Remove="wwwroot\css\app.css"/>
<_ContentIncludedByDefault Remove="Pages\Home.razor"/>
</ItemGroup>
<ItemGroup>
<None Remove="Properties\launchSettings.json"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\MoonlightServers.Shared\MoonlightServers.Shared.csproj"/>
</ItemGroup>
@@ -57,4 +47,8 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Styles\" />
</ItemGroup>
</Project>

View File

@@ -1,17 +0,0 @@
using Moonlight.Client;
using Moonlight.Client.Startup;
using MoonlightServers.Frontend.Startup;
// Development Client Startup
// This file is a small helper for development instances for moonlight.
// It calls the moonlight startup with the current project loaded as a plugin.
// This allows you to develop and debug projects without any hassle
// !!! DO NOT HARDCORE ANY SECRETS HERE !!!
var startup = new Startup();
await startup.Run(args, [
new PluginStartup()
]);

View File

@@ -44,6 +44,13 @@ public class ServerFileSystemService
);
}
public async Task Touch(int serverId, string path)
{
await ApiClient.Post(
$"api/client/servers/{serverId}/files/touch?path={path}"
);
}
public async Task<ServerFilesUploadResponse> Upload(int serverId)
{
return await ApiClient.GetJson<ServerFilesUploadResponse>(

View File

@@ -1,4 +1,5 @@
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.DependencyInjection;
using MoonCore.Extensions;
using Moonlight.Client.Interfaces;
using Moonlight.Client.Plugins;
@@ -7,7 +8,6 @@ using MoonlightServers.Frontend.Interfaces;
namespace MoonlightServers.Frontend.Startup;
[PluginStartup]
public class PluginStartup : IPluginStartup
{
public Task BuildApplication(IServiceProvider serviceProvider, WebAssemblyHostBuilder builder)

View File

@@ -0,0 +1,612 @@
!bg-base-100
!border-base-content/40
!border-none
!flex
!font-medium
!font-semibold
!h-2.5
!justify-between
!me-1.5
!ms-auto
!px-2.5
!rounded-full
!text-sm
!w-2.5
*:[grid-area:1/1]
*:first:rounded-tl-lg
*:last:rounded-tr-lg
-left-4
-ml-4
-translate-x-full
-translate-y-1/2
absolute
accordion
accordion-bordered
accordion-toggle
active
active-tab:bg-primary
active-tab:text-base-content
advance-select-menu
advance-select-option
advance-select-tag
advance-select-toggle
alert
alert-error
alert-outline
alert-soft
align-bottom
align-middle
animate-bounce
animate-ping
aria-[current='page']:text-bg-soft-primary
avatar
avatar-away-bottom
avatar-away-top
avatar-busy-bottom
avatar-busy-top
avatar-offline-bottom
avatar-offline-top
avatar-online-bottom
avatar-online-top
avatar-placeholder
badge
badge-error
badge-info
badge-outline
badge-primary
badge-soft
badge-success
bg-background
bg-background/60
bg-base-100
bg-base-150
bg-base-200
bg-base-200/50
bg-base-300
bg-base-300/45
bg-base-300/50
bg-base-300/60
bg-clip-text
bg-error
bg-gradient-to-r
bg-gray-800
bg-gray-900
bg-indigo-600
bg-info
bg-primary
bg-primary/5
bg-red-500
bg-success
bg-transparent
bg-warning
bg-white/5
block
blur
border
border-0
border-2
border-accent
border-b
border-base-content
border-base-content/20
border-base-content/40
border-base-content/5
border-base-content/70
border-dashed
border-l-4
border-primary
border-success
border-t
border-transparent
bottom-0
bottom-full
break-words
btn
btn-accent
btn-active
btn-circle
btn-disabled
btn-error
btn-gradient
btn-info
btn-outline
btn-primary
btn-secondary
btn-sm
btn-soft
btn-square
btn-success
btn-text
btn-warning
card
card-alert
card-body
card-border
card-footer
card-header
card-title
carousel
carousel-body
carousel-next
carousel-prev
carousel-slide
chat
chat-avatar
chat-bubble
chat-footer
chat-header
chat-receiver
chat-sender
checkbox
checkbox-primary
checkbox-xs
col-span-1
col-span-12
col-span-2
collapse
combo-box-selected:block
combo-box-selected:dropdown-active
complete
container
contents
cursor-default
cursor-not-allowed
cursor-pointer
diff
disabled
divide-base-150/60
divide-y
drop-shadow
dropdown
dropdown-disabled
dropdown-item
dropdown-menu
dropdown-open:opacity-100
dropdown-open:rotate-180
dropdown-toggle
duration-300
duration-500
ease-in-out
ease-linear
end-3
error-message
file-upload-complete:progress-success
fill-black
filter
filter-reset
fixed
flex
flex-1
flex-col
flex-grow
flex-nowrap
flex-row
flex-shrink-0
flex-wrap
focus-visible:outline
focus-visible:outline-2
focus-visible:outline-indigo-600
focus-visible:outline-none
focus-visible:outline-offset-2
focus-within:border-primary
focus:border-primary
focus:outline-1
focus:outline-none
focus:outline-primary
focus:ring-0
focus:ring-2
focus:ring-indigo-600
focus:ring-inset
font-bold
font-inter
font-medium
font-normal
font-semibold
from-violet-400
gap-0.5
gap-1
gap-1.5
gap-2
gap-3
gap-4
gap-5
gap-6
gap-x-1
gap-x-2
gap-x-3
gap-x-6
gap-y-1
gap-y-2
gap-y-3
gap-y-8
grid
grid-cols-1
grid-cols-12
grid-cols-2
grid-flow-col
grow
grow-0
h-12
h-14
h-2
h-3
h-32
h-64
h-8
h-auto
h-full
h-screen
helper-text
hidden
hover:bg-indigo-500
hover:bg-primary/5
hover:bg-transparent
hover:text-base-content
hover:text-base-content/60
hover:text-indigo-500
hover:text-primary
image-full
inline
inline-block
inline-flex
inline-grid
input
input-floating
input-floating-label
input-lg
input-md
input-sm
input-xl
input-xs
inset-0
inset-y-0
inset-y-2
invisible
is-invalid
is-valid
isolate
italic
items-center
items-end
items-start
join
join-item
justify-between
justify-center
justify-end
justify-start
justify-stretch
label-text
leading-3
leading-3.5
leading-6
leading-9
leading-[1.1]
left-0
lg:bg-base-100/20
lg:flex
lg:gap-y-0
lg:grid-cols-2
lg:hidden
lg:justify-end
lg:justify-start
lg:min-w-0
lg:p-10
lg:pb-5
lg:pl-64
lg:pr-3.5
lg:pt-5
lg:px-8
lg:ring-1
lg:ring-base-content/10
lg:rounded-lg
lg:shadow-xs
list-disc
list-inside
loading
loading-lg
loading-sm
loading-spinner
loading-xl
loading-xs
lowercase
m-10
mask
max-lg:flex-col
max-lg:hidden
max-w-7xl
max-w-80
max-w-full
max-w-lg
max-w-md
max-w-sm
max-w-xl
mb-0.5
mb-1
mb-2
mb-3
mb-4
mb-5
mb-8
md:col-span-1
md:col-span-6
md:grid-cols-2
md:min-w-md
md:table-cell
md:text-3xl
me-1
me-1.5
me-2
me-5
menu
menu-active
menu-disabled
menu-dropdown
menu-dropdown-show
menu-focus
menu-horizontal
menu-title
min-h-0
min-h-full
min-h-svh
min-w-0
min-w-28
min-w-48
min-w-60
min-w-[100px]
min-w-sm
mix-blend-exclusion
ml-3
ml-4
modal
modal-content
modal-dialog
modal-middle
modal-title
mr-2
mr-4
ms-1
ms-2
ms-3
mt-1
mt-1.5
mt-10
mt-12
mt-2
mt-2.5
mt-3
mt-4
mt-5
mt-6
mt-8
mx-1
mx-auto
my-3
my-5
my-auto
opacity-0
opacity-100
open
origin-top-left
outline
outline-0
overflow-hidden
overflow-x-auto
overflow-y-auto
overlay-open:duration-50
overlay-open:opacity-100
p-0.5
p-1
p-2
p-3
p-4
p-5
p-6
p-8
pin-input
pin-input-underline
placeholder-base-content/60
placeholder:text-gray-600
pointer-events-auto
pointer-events-none
progress
progress-bar
progress-indeterminate
progress-primary
pt-0.5
pt-3
px-1.5
px-2
px-3
px-4
px-5
px-6
py-0.5
py-1.5
py-12
py-2
py-2.5
py-6
radio
range
relative
resize
ring-0
ring-1
ring-gray-700
ring-inset
ring-white/10
rounded-box
rounded-field
rounded-full
rounded-lg
rounded-md
rounded-t-lg
row-active
row-hover
rtl:!mr-0
select
select-disabled:opacity-40
select-disabled:pointer-events-none
select-floating
select-floating-label
select-lg
select-md
select-sm
select-xl
select-xs
selected
selected:select-active
shadow
shadow-base-300/20
shadow-lg
shadow-sm
shadow-xs
shrink-0
size-10
size-4
size-5
size-8
skeleton
skeleton-animated
sm:auto-cols-max
sm:col-span-2
sm:flex
sm:gap-y-0
sm:grid-cols-3
sm:grid-cols-6
sm:items-center
sm:items-end
sm:justify-between
sm:justify-end
sm:leading-6
sm:max-w-2xl
sm:max-w-3xl
sm:max-w-4xl
sm:max-w-5xl
sm:max-w-6xl
sm:max-w-7xl
sm:max-w-[480px]
sm:max-w-lg
sm:max-w-md
sm:max-w-xl
sm:mb-0
sm:mr-3
sm:mt-5
sm:mt-6
sm:mx-auto
sm:p-6
sm:px-12
sm:px-6
sm:py-2
sm:rounded-lg
sm:text-sm
sm:text-sm/5
sm:w-full
space-x-1
space-y-1
space-y-4
space-y-6
sr-only
static
status
status-error
sticky
success-message
switch
tab
tab-active
tab-content
table
table-pin-cols
table-pin-rows
tabs
tabs-bordered
tabs-lg
tabs-lifted
tabs-md
tabs-sm
tabs-vertical
tabs-xl
tabs-xs
text-2xl
text-3xl
text-4xl
text-accent
text-base
text-base-content
text-base-content/40
text-base-content/50
text-base-content/60
text-base-content/70
text-base-content/80
text-base-content/90
text-base/6
text-center
text-error
text-error-content
text-gray-100
text-gray-400
text-gray-500
text-indigo-600
text-info
text-info-content
text-left
text-lg
text-primary
text-primary-content
text-slate-100
text-sm
text-sm/5
text-success
text-success-content
text-transparent
text-warning
text-warning-content
text-white
text-xl
text-xs
text-xs/5
textarea
textarea-floating
textarea-floating-label
textarea-lg
textarea-md
textarea-sm
textarea-xl
textarea-xs
theme-controller
to-purple-400
tooltip
tooltip-content
top-0
top-1/2
top-full
tracking-tight
tracking-wide
transform
transition
transition-all
transition-opacity
translate-x-0
truncate
underline
uppercase
validate
via-sky-400
w-0
w-0.5
w-12
w-32
w-4
w-56
w-64
w-auto
w-fit
w-full
whitespace-nowrap
xl:grid-cols-3
xl:grid-cols-4
z-10
z-40
z-50

View File

@@ -0,0 +1,513 @@
!bg-base-100
!border-base-content/40
!border-none
!flex
!font-medium
!font-semibold
!h-2.5
!justify-between
!me-1.5
!ms-auto
!px-2.5
!rounded-full
!text-sm
!w-2.5
*:[grid-area:1/1]
*:first:rounded-tl-lg
*:last:rounded-tr-lg
-left-4
-ml-4
-translate-x-full
-translate-y-1/2
absolute
accordion
accordion-bordered
accordion-toggle
active
active-tab:bg-primary
active-tab:text-base-content
advance-select-menu
advance-select-option
advance-select-tag
advance-select-toggle
alert
alert-error
alert-outline
alert-soft
align-bottom
align-middle
animate-bounce
animate-ping
aria-[current='page']:text-bg-soft-primary
avatar
avatar-away-bottom
avatar-away-top
avatar-busy-bottom
avatar-busy-top
avatar-offline-bottom
avatar-offline-top
avatar-online-bottom
avatar-online-top
avatar-placeholder
badge
badge-error
badge-info
badge-outline
badge-primary
badge-soft
badge-success
bg-background
bg-background/60
bg-base-100
bg-base-150
bg-base-200
bg-base-200/50
bg-base-300
bg-base-300/45
bg-base-300/50
bg-base-300/60
bg-error
bg-info
bg-primary
bg-primary/5
bg-success
bg-transparent
bg-warning
block
blur
border
border-0
border-2
border-b
border-base-content
border-base-content/20
border-base-content/40
border-base-content/5
border-dashed
border-t
border-transparent
bottom-0
bottom-full
break-words
btn
btn-accent
btn-active
btn-circle
btn-disabled
btn-error
btn-info
btn-outline
btn-primary
btn-secondary
btn-sm
btn-soft
btn-square
btn-success
btn-text
btn-warning
card
card-alert
card-body
card-border
card-footer
card-header
card-title
carousel
carousel-body
carousel-next
carousel-prev
carousel-slide
chat
chat-avatar
chat-bubble
chat-footer
chat-header
chat-receiver
chat-sender
checkbox
checkbox-primary
checkbox-xs
col-span-1
collapse
combo-box-selected:block
combo-box-selected:dropdown-active
complete
container
contents
cursor-default
cursor-not-allowed
cursor-pointer
diff
disabled
divide-base-150/60
divide-y
drop-shadow
dropdown
dropdown-disabled
dropdown-item
dropdown-menu
dropdown-open:opacity-100
dropdown-open:rotate-180
dropdown-toggle
duration-300
duration-500
ease-in-out
ease-linear
end-3
file-upload-complete:progress-success
fill-black
filter
filter-reset
fixed
flex
flex-1
flex-col
flex-grow
flex-nowrap
flex-row
flex-shrink-0
flex-wrap
focus-visible:outline-none
focus-within:border-primary
focus:border-primary
focus:outline-1
focus:outline-none
focus:outline-primary
focus:ring-0
font-bold
font-inter
font-medium
font-normal
font-semibold
gap-0.5
gap-1
gap-1.5
gap-2
gap-3
gap-4
gap-5
gap-6
gap-x-1
gap-x-2
gap-x-3
gap-y-1
gap-y-3
grid
grid-cols-1
grid-flow-col
grow
grow-0
h-12
h-2
h-32
h-64
h-8
h-auto
h-full
h-screen
helper-text
hidden
hover:bg-primary/5
hover:bg-transparent
hover:text-base-content
hover:text-base-content/60
hover:text-primary
image-full
inline
inline-block
inline-flex
inline-grid
input
input-floating
input-floating-label
input-lg
input-md
input-sm
input-xl
inset-0
inset-y-0
inset-y-2
invisible
is-invalid
is-valid
isolate
italic
items-center
items-end
items-start
join
join-item
justify-between
justify-center
justify-end
justify-start
justify-stretch
label-text
leading-3
leading-3.5
leading-6
left-0
lg:bg-base-100/20
lg:flex
lg:gap-y-0
lg:grid-cols-2
lg:hidden
lg:justify-end
lg:justify-start
lg:min-w-0
lg:p-10
lg:pb-5
lg:pl-64
lg:pr-3.5
lg:pt-5
lg:ring-1
lg:ring-base-content/10
lg:rounded-lg
lg:shadow-xs
list-disc
list-inside
loading
loading-lg
loading-sm
loading-spinner
loading-xl
loading-xs
lowercase
m-10
mask
max-lg:flex-col
max-lg:hidden
max-w-7xl
max-w-80
max-w-full
max-w-lg
max-w-sm
max-w-xl
mb-0.5
mb-1
mb-2
mb-3
mb-4
mb-5
md:table-cell
md:text-3xl
me-1
me-1.5
me-2
me-5
menu
menu-active
menu-disabled
menu-dropdown
menu-dropdown-show
menu-focus
menu-horizontal
menu-title
min-h-0
min-h-svh
min-w-0
min-w-28
min-w-48
min-w-60
min-w-[100px]
ml-3
ml-4
modal
modal-content
modal-dialog
modal-middle
modal-title
mr-4
ms-1
ms-2
ms-3
mt-1
mt-1.5
mt-10
mt-12
mt-2
mt-2.5
mt-3
mt-4
mt-5
mt-8
mx-1
mx-auto
my-3
my-auto
opacity-0
opacity-100
open
origin-top-left
outline
outline-0
overflow-hidden
overflow-x-auto
overflow-y-auto
overlay-open:duration-50
overlay-open:opacity-100
p-0.5
p-1
p-2
p-3
p-4
p-5
p-6
p-8
pin-input
pin-input-underline
placeholder-base-content/60
pointer-events-auto
pointer-events-none
progress
progress-bar
progress-indeterminate
progress-primary
pt-0.5
pt-3
px-1.5
px-2
px-3
px-4
px-5
py-0.5
py-1.5
py-2
py-2.5
py-6
radio
range
relative
resize
ring-0
ring-1
ring-white/10
rounded-box
rounded-field
rounded-full
rounded-lg
rounded-md
rounded-t-lg
row-active
row-hover
rtl:!mr-0
select
select-disabled:opacity-40
select-disabled:pointer-events-none
select-floating
select-floating-label
selected
selected:select-active
shadow-base-300/20
shadow-lg
shadow-xs
shrink-0
size-10
size-4
size-5
size-8
skeleton
skeleton-animated
sm:auto-cols-max
sm:flex
sm:items-center
sm:items-end
sm:justify-between
sm:justify-end
sm:max-w-2xl
sm:max-w-3xl
sm:max-w-4xl
sm:max-w-5xl
sm:max-w-6xl
sm:max-w-7xl
sm:max-w-lg
sm:max-w-md
sm:max-w-xl
sm:mb-0
sm:mt-5
sm:mt-6
sm:p-6
sm:py-2
sm:text-sm/5
space-x-1
space-y-1
space-y-4
sr-only
static
status
status-error
sticky
switch
tab
tab-active
table
table-pin-cols
table-pin-rows
tabs
tabs-bordered
tabs-lg
tabs-lifted
tabs-md
tabs-sm
tabs-xl
tabs-xs
text-2xl
text-4xl
text-accent
text-base
text-base-content
text-base-content/40
text-base-content/50
text-base-content/60
text-base-content/70
text-base-content/80
text-base/6
text-center
text-error
text-error-content
text-gray-400
text-info
text-info-content
text-left
text-lg
text-primary
text-primary-content
text-sm
text-sm/5
text-success
text-success-content
text-warning
text-warning-content
text-xl
text-xs
text-xs/5
textarea
textarea-floating
textarea-floating-label
theme-controller
tooltip
tooltip-content
top-0
top-1/2
top-full
transform
transition
transition-all
transition-opacity
translate-x-0
truncate
underline
uppercase
validate
w-0
w-0.5
w-12
w-4
w-56
w-64
w-fit
w-full
whitespace-nowrap
z-10
z-40
z-50

View File

@@ -1 +0,0 @@
/* Custom styles here */

View File

@@ -1,958 +0,0 @@
{
"name": "Styles",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"dependencies": {
"@tailwindcss/cli": "^4.1.4",
"@tailwindcss/forms": "^0.5.10",
"tailwindcss": "^4.1.4",
"xml2js": "^0.6.2"
}
},
"node_modules/@parcel/watcher": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
"integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
"hasInstallScript": true,
"dependencies": {
"detect-libc": "^1.0.3",
"is-glob": "^4.0.3",
"micromatch": "^4.0.5",
"node-addon-api": "^7.0.0"
},
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"@parcel/watcher-android-arm64": "2.5.1",
"@parcel/watcher-darwin-arm64": "2.5.1",
"@parcel/watcher-darwin-x64": "2.5.1",
"@parcel/watcher-freebsd-x64": "2.5.1",
"@parcel/watcher-linux-arm-glibc": "2.5.1",
"@parcel/watcher-linux-arm-musl": "2.5.1",
"@parcel/watcher-linux-arm64-glibc": "2.5.1",
"@parcel/watcher-linux-arm64-musl": "2.5.1",
"@parcel/watcher-linux-x64-glibc": "2.5.1",
"@parcel/watcher-linux-x64-musl": "2.5.1",
"@parcel/watcher-win32-arm64": "2.5.1",
"@parcel/watcher-win32-ia32": "2.5.1",
"@parcel/watcher-win32-x64": "2.5.1"
}
},
"node_modules/@parcel/watcher-android-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
"integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-darwin-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
"integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-darwin-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
"integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-freebsd-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
"integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
"integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
"integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm64-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
"integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-arm64-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
"integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-x64-glibc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
"integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-linux-x64-musl": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
"integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-arm64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
"integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-ia32": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
"integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@parcel/watcher-win32-x64": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
"integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/@tailwindcss/cli": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/cli/-/cli-4.1.5.tgz",
"integrity": "sha512-Kr567rDwDjY1VUnfqh5/+DCpRf4B8lPs5O9flP4kri7n4AM2aubrIxGSh5GN8s+awUKw/U4+6kNlEnZbBNfUeg==",
"dependencies": {
"@parcel/watcher": "^2.5.1",
"@tailwindcss/node": "4.1.5",
"@tailwindcss/oxide": "4.1.5",
"enhanced-resolve": "^5.18.1",
"mri": "^1.2.0",
"picocolors": "^1.1.1",
"tailwindcss": "4.1.5"
},
"bin": {
"tailwindcss": "dist/index.mjs"
}
},
"node_modules/@tailwindcss/forms": {
"version": "0.5.10",
"resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz",
"integrity": "sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==",
"dependencies": {
"mini-svg-data-uri": "^1.2.3"
},
"peerDependencies": {
"tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1"
}
},
"node_modules/@tailwindcss/node": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.5.tgz",
"integrity": "sha512-CBhSWo0vLnWhXIvpD0qsPephiaUYfHUX3U9anwDaHZAeuGpTiB3XmsxPAN6qX7bFhipyGBqOa1QYQVVhkOUGxg==",
"dependencies": {
"enhanced-resolve": "^5.18.1",
"jiti": "^2.4.2",
"lightningcss": "1.29.2",
"tailwindcss": "4.1.5"
}
},
"node_modules/@tailwindcss/oxide": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.5.tgz",
"integrity": "sha512-1n4br1znquEvyW/QuqMKQZlBen+jxAbvyduU87RS8R3tUSvByAkcaMTkJepNIrTlYhD+U25K4iiCIxE6BGdRYA==",
"engines": {
"node": ">= 10"
},
"optionalDependencies": {
"@tailwindcss/oxide-android-arm64": "4.1.5",
"@tailwindcss/oxide-darwin-arm64": "4.1.5",
"@tailwindcss/oxide-darwin-x64": "4.1.5",
"@tailwindcss/oxide-freebsd-x64": "4.1.5",
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.5",
"@tailwindcss/oxide-linux-arm64-gnu": "4.1.5",
"@tailwindcss/oxide-linux-arm64-musl": "4.1.5",
"@tailwindcss/oxide-linux-x64-gnu": "4.1.5",
"@tailwindcss/oxide-linux-x64-musl": "4.1.5",
"@tailwindcss/oxide-wasm32-wasi": "4.1.5",
"@tailwindcss/oxide-win32-arm64-msvc": "4.1.5",
"@tailwindcss/oxide-win32-x64-msvc": "4.1.5"
}
},
"node_modules/@tailwindcss/oxide-android-arm64": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.5.tgz",
"integrity": "sha512-LVvM0GirXHED02j7hSECm8l9GGJ1RfgpWCW+DRn5TvSaxVsv28gRtoL4aWKGnXqwvI3zu1GABeDNDVZeDPOQrw==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-darwin-arm64": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.5.tgz",
"integrity": "sha512-//TfCA3pNrgnw4rRJOqavW7XUk8gsg9ddi8cwcsWXp99tzdBAZW0WXrD8wDyNbqjW316Pk2hiN/NJx/KWHl8oA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-darwin-x64": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.5.tgz",
"integrity": "sha512-XQorp3Q6/WzRd9OalgHgaqgEbjP3qjHrlSUb5k1EuS1Z9NE9+BbzSORraO+ecW432cbCN7RVGGL/lSnHxcd+7Q==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-freebsd-x64": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.5.tgz",
"integrity": "sha512-bPrLWbxo8gAo97ZmrCbOdtlz/Dkuy8NK97aFbVpkJ2nJ2Jo/rsCbu0TlGx8joCuA3q6vMWTSn01JY46iwG+clg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.5.tgz",
"integrity": "sha512-1gtQJY9JzMAhgAfvd/ZaVOjh/Ju/nCoAsvOVJenWZfs05wb8zq+GOTnZALWGqKIYEtyNpCzvMk+ocGpxwdvaVg==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.5.tgz",
"integrity": "sha512-dtlaHU2v7MtdxBXoqhxwsWjav7oim7Whc6S9wq/i/uUMTWAzq/gijq1InSgn2yTnh43kR+SFvcSyEF0GCNu1PQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-arm64-musl": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.5.tgz",
"integrity": "sha512-fg0F6nAeYcJ3CriqDT1iVrqALMwD37+sLzXs8Rjy8Z1ZHshJoYceodfyUwGJEsQoTyWbliFNRs2wMQNXtT7MVA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-x64-gnu": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.5.tgz",
"integrity": "sha512-SO+F2YEIAHa1AITwc8oPwMOWhgorPzzcbhWEb+4oLi953h45FklDmM8dPSZ7hNHpIk9p/SCZKUYn35t5fjGtHA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-linux-x64-musl": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.5.tgz",
"integrity": "sha512-6UbBBplywkk/R+PqqioskUeXfKcBht3KU7juTi1UszJLx0KPXUo10v2Ok04iBJIaDPkIFkUOVboXms5Yxvaz+g==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-wasm32-wasi": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.5.tgz",
"integrity": "sha512-hwALf2K9FHuiXTPqmo1KeOb83fTRNbe9r/Ixv9ZNQ/R24yw8Ge1HOWDDgTdtzntIaIUJG5dfXCf4g9AD4RiyhQ==",
"bundleDependencies": [
"@napi-rs/wasm-runtime",
"@emnapi/core",
"@emnapi/runtime",
"@tybys/wasm-util",
"@emnapi/wasi-threads",
"tslib"
],
"cpu": [
"wasm32"
],
"optional": true,
"dependencies": {
"@emnapi/core": "^1.4.3",
"@emnapi/runtime": "^1.4.3",
"@emnapi/wasi-threads": "^1.0.2",
"@napi-rs/wasm-runtime": "^0.2.9",
"@tybys/wasm-util": "^0.9.0",
"tslib": "^2.8.0"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.5.tgz",
"integrity": "sha512-oDKncffWzaovJbkuR7/OTNFRJQVdiw/n8HnzaCItrNQUeQgjy7oUiYpsm9HUBgpmvmDpSSbGaCa2Evzvk3eFmA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/oxide-win32-x64-msvc": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.5.tgz",
"integrity": "sha512-WiR4dtyrFdbb+ov0LK+7XsFOsG+0xs0PKZKkt41KDn9jYpO7baE3bXiudPVkTqUEwNfiglCygQHl2jklvSBi7Q==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 10"
}
},
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dependencies": {
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
"bin": {
"detect-libc": "bin/detect-libc.js"
},
"engines": {
"node": ">=0.10"
}
},
"node_modules/enhanced-resolve": {
"version": "5.18.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
"integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==",
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/graceful-fs": {
"version": "4.2.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dependencies": {
"is-extglob": "^2.1.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/jiti": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
"integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
"bin": {
"jiti": "lib/jiti-cli.mjs"
}
},
"node_modules/lightningcss": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz",
"integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==",
"dependencies": {
"detect-libc": "^2.0.3"
},
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"lightningcss-darwin-arm64": "1.29.2",
"lightningcss-darwin-x64": "1.29.2",
"lightningcss-freebsd-x64": "1.29.2",
"lightningcss-linux-arm-gnueabihf": "1.29.2",
"lightningcss-linux-arm64-gnu": "1.29.2",
"lightningcss-linux-arm64-musl": "1.29.2",
"lightningcss-linux-x64-gnu": "1.29.2",
"lightningcss-linux-x64-musl": "1.29.2",
"lightningcss-win32-arm64-msvc": "1.29.2",
"lightningcss-win32-x64-msvc": "1.29.2"
}
},
"node_modules/lightningcss-darwin-arm64": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz",
"integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-darwin-x64": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz",
"integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-freebsd-x64": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz",
"integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm-gnueabihf": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz",
"integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm64-gnu": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz",
"integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-arm64-musl": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz",
"integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-x64-gnu": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz",
"integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-linux-x64-musl": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz",
"integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-win32-arm64-msvc": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz",
"integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss-win32-x64-msvc": {
"version": "1.29.2",
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz",
"integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">= 12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
}
},
"node_modules/lightningcss/node_modules/detect-libc": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
"integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
"engines": {
"node": ">=8"
}
},
"node_modules/micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dependencies": {
"braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
"node": ">=8.6"
}
},
"node_modules/mini-svg-data-uri": {
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz",
"integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==",
"bin": {
"mini-svg-data-uri": "cli.js"
}
},
"node_modules/mri": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
"engines": {
"node": ">=4"
}
},
"node_modules/node-addon-api": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ=="
},
"node_modules/picocolors": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/sax": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg=="
},
"node_modules/tailwindcss": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.5.tgz",
"integrity": "sha512-nYtSPfWGDiWgCkwQG/m+aX83XCwf62sBgg3bIlNiiOcggnS1x3uVRDAuyelBFL+vJdOPPCGElxv9DjHJjRHiVA=="
},
"node_modules/tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
"engines": {
"node": ">=6"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/xml2js": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.6.2.tgz",
"integrity": "sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==",
"dependencies": {
"sax": ">=0.6.0",
"xmlbuilder": "~11.0.0"
},
"engines": {
"node": ">=4.0.0"
}
},
"node_modules/xmlbuilder": {
"version": "11.0.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
"engines": {
"node": ">=4.0"
}
}
}
}

View File

@@ -1,12 +0,0 @@
{
"dependencies": {
"@tailwindcss/cli": "^4.1.4",
"@tailwindcss/forms": "^0.5.10",
"tailwindcss": "^4.1.4",
"xml2js": "^0.6.2"
},
"scripts": {
"tailwind": "npx tailwindcss -i style.css -o ../wwwroot/css/style.min.css --watch",
"pretailwind": "node resolveNuget.js ../MoonlightServers.Frontend.csproj"
}
}

View File

@@ -1 +0,0 @@
/* Import custom fonts here */

View File

@@ -1,80 +0,0 @@
const fs = require('fs');
const path = require('path');
const os = require('os');
const xml2js = require('xml2js');
// Helpers
function getPackageRefs(csprojPath) {
const xml = fs.readFileSync(csprojPath, 'utf8');
const parser = new xml2js.Parser();
return new Promise((resolve, reject) => {
parser.parseString(xml, (err, result) => {
if (err) return reject(err);
const itemGroups = result.Project.ItemGroup || [];
const refs = [];
for (const group of itemGroups) {
const packages = group.PackageReference || [];
for (const pkg of packages) {
const name = pkg.$.Include;
const version = pkg.$.Version || (pkg.Version && pkg.Version[0]);
if (name && version) {
refs.push({ name: name.toLowerCase(), version });
}
}
}
resolve(refs);
});
});
}
async function main() {
const csprojPath = process.argv[2];
if (!csprojPath || !fs.existsSync(csprojPath)) {
console.error('Usage: Missing csproj path');
process.exit(1);
}
const nugetPath = path.join(os.homedir(), '.nuget', 'packages');
const moonlightDir = path.join(__dirname, 'node_modules', 'moonlight');
fs.mkdirSync(moonlightDir, { recursive: true });
const refs = await getPackageRefs(csprojPath);
var outputCss = "";
var preOutputCss = "";
for (const { name, version } of refs) {
const packagePath = path.join(nugetPath, name, version);
const exportsFile = path.join(packagePath, 'styles', 'exports.css');
const preTailwindFile = path.join(packagePath, 'styles', 'preTailwind.css');
const sourceFolder = path.join(packagePath, 'src');
const rel = (p) => p.replace(/\\/g, '/');
if (fs.existsSync(exportsFile)) {
outputCss += `@import "${rel(exportsFile)}";\n`;
}
if (fs.existsSync(preTailwindFile)) {
preOutputCss += `@import "${rel(preTailwindFile)}";\n`;
}
if (fs.existsSync(sourceFolder)) {
outputCss += `@source "${rel(path.join(sourceFolder, "**", "*.razor"))}";\n`;
outputCss += `@source "${rel(path.join(sourceFolder, "**", "*.cs"))}";\n`;
outputCss += `@source "${rel(path.join(sourceFolder, "**", "*.html"))}";\n`;
}
}
fs.writeFileSync(path.join(moonlightDir, 'nuget.css'), outputCss);
fs.writeFileSync(path.join(moonlightDir, 'preTailwind.nuget.css'), preOutputCss);
console.log(`Generated nuget.css in ${moonlightDir}`);
}
main().catch(err => {
console.error(err);
process.exit(1);
});

View File

@@ -1,15 +0,0 @@
@import "./preTailwind.css";
@import "moonlight/preTailwind.nuget.css";
@import "tailwindcss";
@import "./exports.css";
@import "moonlight/nuget.css";
@plugin "@tailwindcss/forms" {
strategy: "base";
}
@source "../**/*.razor";
@source "../**/*.cs";
@source "../**/*.html";

View File

@@ -5,26 +5,18 @@
@inherits InputBase<bool>
<div class="flex items-center">
<div class="form-switch">
<input @bind="CurrentValue" type="checkbox" id="@("switch-" + GetHashCode())" class="sr-only">
<label class="bg-gray-700" for="switch-@(GetHashCode())">
<span class="bg-white shadow-sm" aria-hidden="true"></span>
<span class="sr-only">Switch label</span>
</label>
</div>
<div class="text-sm text-gray-500 italic ml-2">
<div class="flex items-center gap-1">
<input @bind="CurrentValue" type="checkbox" class="switch switch-primary" id="switch-@GetHashCode()" />
<label class="label-text text-base" for="switch-@GetHashCode()">
@if (CurrentValue)
{
<span>On</span>
}
else
{
<span>
Off
</span>
<span>Off</span>
}
</div>
</label>
</div>
@code

View File

@@ -1,6 +1,4 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Modals.Components
@using MoonCore.Blazor.Tailwind.Components
@using MoonlightServers.Shared.Http.Requests.Admin.NodeAllocations
@inherits MoonCore.Blazor.FlyonUi.Modals.Components.BaseModal
@@ -10,13 +8,13 @@
<HandleForm @ref="HandleForm" Model="Form" OnValidSubmit="OnValidSubmit">
<div class="grid grid-cols-1 gap-2">
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">IP Address</label>
<input @bind="Form.IpAddress" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">IP Address</label>
<input @bind="Form.IpAddress" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Port</label>
<input @bind="Form.Port" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Port</label>
<input @bind="Form.Port" type="text" class="input w-full"/>
</div>
</div>
</HandleForm>

View File

@@ -1,6 +1,4 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Modals.Components
@using MoonCore.Blazor.Tailwind.Components
@using MoonlightServers.Shared.Http.Requests.Admin.NodeAllocations
@inherits MoonCore.Blazor.FlyonUi.Modals.Components.BaseModal
@@ -10,18 +8,18 @@
<HandleForm @ref="HandleForm" Model="Form" OnValidSubmit="OnValidSubmit">
<div class="grid grid-cols-1 gap-2">
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">IP Address</label>
<input @bind="Form.IpAddress" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">IP Address</label>
<input @bind="Form.IpAddress" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Start Port</label>
<input @bind="Form.Start" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Start Port</label>
<input @bind="Form.Start" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">End Port</label>
<input @bind="Form.End" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">End Port</label>
<input @bind="Form.End" type="text" class="input w-full"/>
</div>
</div>
</HandleForm>

View File

@@ -1,7 +1,4 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Modals.Components
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Helpers
@using MoonlightServers.Shared.Http.Requests.Admin.NodeAllocations
@using MoonlightServers.Shared.Http.Responses.Admin.NodeAllocations
@@ -12,13 +9,13 @@
<HandleForm @ref="HandleForm" Model="Form" OnValidSubmit="OnValidSubmit">
<div class="grid grid-cols-1 gap-2">
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">IP Address</label>
<input @bind="Form.IpAddress" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">IP Address</label>
<input @bind="Form.IpAddress" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Port</label>
<input @bind="Form.Port" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Port</label>
<input @bind="Form.Port" type="text" class="input w-full"/>
</div>
</div>
</HandleForm>
@@ -38,7 +35,11 @@
protected override void OnInitialized()
{
Form = Mapper.Map<UpdateNodeAllocationRequest>(Allocation);
Form = new UpdateNodeAllocationRequest()
{
IpAddress = Allocation.IpAddress,
Port = Allocation.Port
};
}
private async Task OnValidSubmit()

View File

@@ -2,19 +2,23 @@
@using MoonlightServers.Shared.Http.Requests.Admin.Nodes
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2"><label class="block text-sm font-medium leading-6 text-white">Enable Transparent
Mode</label>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-base-content">Enable Transparent
Mode
</label>
<div class="mt-2">
<div class="flex items-center">
<Switch @bind-Value="Request.EnableTransparentMode" />
<Switch @bind-Value="Request.EnableTransparentMode"/>
</div>
</div>
</div>
<div class="sm:col-span-2"><label class="block text-sm font-medium leading-6 text-white">Enable Dynamic
Firewall</label>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-base-content">
Enable Dynamic Firewall
</label>
<div class="mt-2">
<div class="flex items-center">
<Switch @bind-Value="Request.EnableDynamicFirewall" />
<Switch @bind-Value="Request.EnableDynamicFirewall"/>
</div>
</div>
</div>

View File

@@ -2,11 +2,7 @@
@using MoonCore.Blazor.FlyonUi.DataTables
@using MoonCore.Blazor.FlyonUi.Modals
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Alerts
@using MoonlightServers.Shared.Http.Responses.Admin.Nodes
@using MoonCore.Blazor.Tailwind.Dt
@using MoonCore.Blazor.Tailwind.Modals
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonCore.Helpers
@using MoonCore.Models
@using MoonlightServers.Frontend.UI.Components.Nodes.Modals
@@ -21,15 +17,14 @@
<div class="grid grid-cols-1 md:grid-cols-3 md:gap-x-5">
<div class="col-span-1">
<div class="card">
<div
class="card-header card-header bg-gray-700 rounded-t-lg text-gray-500 bg-opacity-50 border-0 py-2 text-base font-semibold">
<span class="card-title">Actions</span>
<div class="card-header">
Actions
</div>
<div class="card-body">
<div class="flex flex-col gap-y-3">
<button @onclick="AddAllocation" class="btn btn-primary">Create</button>
<button @onclick="AddAllocationRange" class="btn btn-tertiary">Create multiple</button>
<button @onclick="DeleteAllAllocations" class="btn btn-danger">Delete all</button>
<button type="button" @onclick="AddAllocation" class="btn btn-primary">Create</button>
<button type="button" @onclick="AddAllocationRange" class="btn btn-accent">Create multiple</button>
<button type="button" @onclick="DeleteAllAllocations" class="btn btn-error">Delete all</button>
</div>
</div>
</div>
@@ -37,19 +32,21 @@
<div class="col-span-1 md:col-span-2 -mb-3">
<DataTable @ref="Table" TItem="NodeAllocationResponse">
<Configuration>
<Pagination TItem="NodeAllocationResponse" ItemSource="LoadData" />
<Pagination TItem="NodeAllocationResponse" ItemSource="LoadData"/>
<DataTableColumn TItem="NodeAllocationResponse" Field="@(x => x.IpAddress)" Name="IP Address"/>
<DataTableColumn TItem="NodeAllocationResponse" Field="@(x => x.Port)" Name="Port"/>
<DataTableColumn TItem="NodeAllocationResponse">
<ColumnTemplate>
<div class="flex justify-end items-center">
<a @onclick="() => UpdateAllocation(context)" @onclick:preventDefault href="#"
<a @onclick="() => UpdateAllocation(context)"
@onclick:preventDefault href="#"
class="text-primary mr-2 sm:mr-3">
<i class="icon-pencil text-base"></i>
</a>
<a @onclick="() => DeleteAllocation(context)" @onclick:preventDefault href="#"
class="text-danger">
<a @onclick="() => DeleteAllocation(context)"
@onclick:preventDefault href="#"
class="text-error">
<i class="icon-trash text-base"></i>
</a>
</div>
@@ -83,10 +80,7 @@
await Table.Refresh();
};
await ModalService.Launch<CreateMultipleAllocationModal>(parameters =>
{
parameters.Add("OnSubmit", onSubmit);
});
await ModalService.Launch<CreateMultipleAllocationModal>(parameters => { parameters.Add("OnSubmit", onSubmit); });
}
private async Task AddAllocation()

View File

@@ -2,26 +2,26 @@
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Name</label>
<label class="block text-sm font-medium leading-6 text-base-content">Name</label>
<div class="mt-2">
<input @bind="Request.Name" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.Name" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Fqdn</label>
<label class="block text-sm font-medium leading-6 text-base-content">Fqdn</label>
<div class="mt-2">
<input @bind="Request.Fqdn" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.Fqdn" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Http Port</label>
<label class="block text-sm font-medium leading-6 text-base-content">Http Port</label>
<div class="mt-2">
<input @bind="Request.HttpPort" type="number" autocomplete="off" class="form-input w-full">
<input @bind="Request.HttpPort" type="number" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2"><label class="block text-sm font-medium leading-6 text-white">Ftp Port</label>
<div class="sm:col-span-2"><label class="block text-sm font-medium leading-6 text-base-content">Ftp Port</label>
<div class="mt-2">
<input @bind="Request.FtpPort" type="number" autocomplete="off" class="form-input w-full">
<input @bind="Request.FtpPort" type="number" autocomplete="off" class="input w-full">
</div>
</div>
</div>

View File

@@ -1,7 +1,6 @@
@using Microsoft.Extensions.Logging
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonCore.Helpers
@using MoonlightServers.Frontend.Services
@using MoonlightServers.Shared.Http.Responses.Admin.Nodes
@@ -22,8 +21,8 @@
<div class="grid grid-cols-1 lg:grid-cols-3 gap-5">
<div class="col-span-1 card card-body">
<div class="flex justify-between">
<p class="text-xl font-semibold text-slate-200">
@Math.Round(Statistics.Cpu.Usage, 2)%
<p class="text-xl font-semibold text-base-content">
@(Math.Round(Statistics.Cpu.Usage, 2))%
</p>
<i class="icon-cpu text-4xl text-primary"></i>
</div>
@@ -36,10 +35,10 @@
<div class="col-span-1 card card-body">
<div class="flex justify-between">
<p class="text-xl font-semibold text-slate-200">
@Formatter.FormatSize(Statistics.Memory.Total - Statistics.Memory.Available)
<p class="text-xl font-semibold text-base-content">
@(Formatter.FormatSize(Statistics.Memory.Total - Statistics.Memory.Available))
/
@Formatter.FormatSize(Statistics.Memory.Total)
@(Formatter.FormatSize(Statistics.Memory.Total))
</p>
<i class="icon-memory-stick text-4xl text-primary"></i>
</div>
@@ -50,10 +49,10 @@
<div class="col-span-1 card card-body">
<div class="flex justify-between">
<div class="text-xl font-semibold text-slate-200">
@Formatter.FormatSize(Statistics.Memory.SwapTotal - Statistics.Memory.SwapFree)
<div class="text-xl font-semibold text-base-content">
@(Formatter.FormatSize(Statistics.Memory.SwapTotal - Statistics.Memory.SwapFree))
/
@Formatter.FormatSize(Statistics.Memory.SwapTotal)
@(Formatter.FormatSize(Statistics.Memory.SwapTotal))
</div>
<i class="icon-shapes text-4xl text-primary"></i>
</div>
@@ -81,9 +80,8 @@
<span>#@(i)</span>
</div>
<div class="grow">
<div class="progress bg-gray-750">
<div style="width: @(usage)%"
class="progress-bar h-3 @(GetBackgroundColorByPercent(percentRounded))"></div>
<div class="progress h-2" role="progressbar">
<div class="progress-bar transition-all duration-300 ease-in-out @(GetBackgroundColorByPercent(percentRounded))" style="width: @(usage)%"></div>
</div>
</div>
</div>
@@ -105,9 +103,8 @@
<div class="col-span-1 card card-body">
<div class="flex items-center">
<div class="grow">
<div class="progress bg-gray-750">
<div style="width: @(usedPercent)%"
class="progress-bar h-3 @(GetBackgroundColorByPercent(usedPercent))"></div>
<div class="progress h-2" role="progressbar">
<div class="progress-bar transition-all duration-300 ease-in-out @(GetBackgroundColorByPercent(usedPercent))" style="width: @(usedPercent)%"></div>
</div>
</div>
</div>
@@ -134,7 +131,7 @@
<div class="grid grid-cols-1 lg:grid-cols-3 gap-5">
<div class="col-span-1 card card-body">
<div class="flex justify-between">
<p class="text-xl font-semibold text-slate-200">
<p class="text-xl font-semibold text-base-content">
@Formatter.FormatSize(DockerStatistics.ImagesUsed) (@Formatter.FormatSize(DockerStatistics.ImagesReclaimable) unused)
</p>
<i class="icon-gallery-horizontal-end text-4xl text-primary"></i>
@@ -146,7 +143,7 @@
<div class="col-span-1 card card-body">
<div class="flex justify-between">
<p class="text-xl font-semibold text-slate-200">
<p class="text-xl font-semibold text-base-content">
@Formatter.FormatSize(DockerStatistics.ContainersUsed) ( @Formatter.FormatSize(DockerStatistics.ContainersReclaimable) unused)
</p>
<i class="icon-container text-4xl text-primary"></i>
@@ -158,7 +155,7 @@
<div class="col-span-1 card card-body">
<div class="flex justify-between">
<p class="text-xl font-semibold text-slate-200">
<p class="text-xl font-semibold text-base-content">
@Formatter.FormatSize(DockerStatistics.BuildCacheUsed) (@Formatter.FormatSize(DockerStatistics.BuildCacheReclaimable) unused)
</p>
<i class="icon-hard-hat text-4xl text-primary"></i>
@@ -199,7 +196,7 @@
catch (Exception e)
{
Logger.LogWarning("An error occured while fetching status update: {e}", e);
await ToastService.Danger("Unable to fetch status update", e.Message);
await ToastService.Error("Unable to fetch status update", e.Message);
}
}
@@ -210,7 +207,7 @@
else if (percent < 80)
return "bg-warning";
else
return "bg-danger";
return "bg-error";
}
public void Dispose()

View File

@@ -1,35 +1,25 @@
@using MoonlightServers.Shared.Http.Requests.Admin.Servers
@using MoonCore.Blazor.Tailwind.Inputs
@using MoonCore.Blazor.FlyonUi.Components
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Storage</label>
<label class="block text-sm font-medium leading-6 text-base-content">Storage</label>
<div class="mt-2">
<InputCustomSelect TValue="bool" @bind-Value="Request.UseVirtualDisk">
<CustomSelectOption Value="false">
<Template>
<span>
<i class="icon-database me-1 align-middle"></i>
<span class="align-middle">Docker Volume</span>
</span>
</Template>
</CustomSelectOption>
<CustomSelectOption Value="true">
<Template>
<span>
<i class="icon-hard-drive me-1 align-middle"></i>
<span class="align-middle">Virtual Disk</span>
</span>
</Template>
</CustomSelectOption>
</InputCustomSelect>
<div class="select">
<span class="icon-hard-drive text-base-content/80 my-auto"></span>
<label class="sr-only" for="virtual-disk">Select the storage provider</label>
<select @bind="Request.UseVirtualDisk" id="virtual-disk">
<option value="false">Volume</option>
<option value="true">Virtual Disk</option>
</select>
</div>
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Bandwidth</label>
<label class="block text-sm font-medium leading-6 text-base-content">Bandwidth</label>
<div class="mt-2">
<input @bind="Request.Bandwidth" type="number" autocomplete="off" class="form-input w-full">
<input @bind="Request.Bandwidth" type="number" autocomplete="off" class="input w-full">
</div>
</div>
</div>

View File

@@ -1,22 +1,22 @@
@using MoonlightServers.Shared.Http.Requests.Admin.Servers
@using MoonCore.Blazor.Tailwind.Inputs
@using MoonCore.Helpers
@using MoonCore.Models
@using MoonlightServers.Shared.Http.Responses.Admin.NodeAllocations
@using MoonCore.Blazor.FlyonUi.Forms
@using MoonlightServers.Shared.Http.Responses.Admin.Nodes
@inject HttpApiClient ApiClient
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Allocations</label>
<label class="block text-sm font-medium leading-6 text-base-content">Allocations</label>
<div class="mt-2">
<InputMultiSelect TItem="NodeAllocationDetailResponse"
TProperty="int"
@bind-Value="Request.AllocationIds"
Loader="Loader"
AllowSearch="true"
DisplayProperty="@(x => $"{x.IpAddress}:{x.Port}")"
ValueProperty="@(x => x.Id)"/>
<InputMultipleItem TItem="NodeAllocationResponse"
DisplayField="@(x => $"{x.IpAddress}:{x.Port}")"
SearchField="@(x => $"{x.IpAddress}:{x.Port}")"
Value="Allocations"
ItemSource="ItemSource">
</InputMultipleItem>
</div>
</div>
</div>
@@ -24,16 +24,19 @@
@code
{
[Parameter] public CreateServerRequest Request { get; set; }
[Parameter] public List<NodeAllocationResponse> Allocations { get; set; }
[Parameter] public NodeResponse? Node { get; set; }
private async Task<NodeAllocationResponse[]> Loader()
private async Task<NodeAllocationResponse[]> ItemSource()
{
// Handle unselected node
if (Request.NodeId <= 0)
// ReSharper disable once ConditionIsAlwaysTrueOrFalseAccordingToNullableAPIContract
if (Node == null)
return [];
var items = await PagedData<NodeAllocationResponse>.All(async (page, pageSize) =>
await ApiClient.GetJson<PagedData<NodeAllocationResponse>>(
$"api/admin/servers/nodes/{Request.NodeId}/allocations/free?page={page}&pageSize={pageSize}"
$"api/admin/servers/nodes/{Node.Id}/allocations/free?page={page}&pageSize={pageSize}"
)
);

View File

@@ -3,83 +3,83 @@
@using MoonCore.Models
@using MoonlightServers.Shared.Http.Responses.Admin.Nodes
@using MoonlightServers.Shared.Http.Responses.Admin.Stars
@using MoonCore.Blazor.Tailwind.Inputs
@using Moonlight.Shared.Http.Responses.Admin.Users
@using MoonCore.Blazor.FlyonUi.Forms
@inject HttpApiClient ApiClient
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Name</label>
<label class="block text-sm font-medium leading-6 text-base-content">Name</label>
<div class="mt-2">
<input @bind="Request.Name" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.Name" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Owner</label>
<label class="block text-sm font-medium leading-6 text-base-content">Owner</label>
<div class="mt-2">
<InputItemSearchSelect TItem="UserResponse"
TProperty="int"
@bind-Value="Request.OwnerId"
AllowNone="false"
Loader="Loader"
DisplayProperty="@(x => x.Email)"
ValueProperty="@(x => x.Id)"/>
<InputItem TItem="UserResponse"
DisplayField="@(x => x.Username)"
SearchField="@(x => x.Username)"
ItemSource="LoadUsers"
@bind-Value="User">
</InputItem>
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Star</label>
<label class="block text-sm font-medium leading-6 text-base-content">Star</label>
<div class="mt-2">
<InputItemSelect TItem="StarDetailResponse"
TProperty="int"
@bind-Value="Request.StarId"
DisplayProperty="@(x => x.Name)"
ValueProperty="@(x => x?.Id ?? -1)"
Loader="LoadStars"/>
<InputItem TItem="StarDetailResponse"
DisplayField="@(x => x.Name)"
SearchField="@(x => x.Name)"
ItemSource="LoadStars"
@bind-Value="Star">
</InputItem>
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Node</label>
<label class="block text-sm font-medium leading-6 text-base-content">Node</label>
<div class="mt-2">
<InputItemSelect TItem="NodeDetailResponse"
TProperty="int"
@bind-Value="Request.NodeId"
DisplayProperty="@(x => x.Name)"
ValueProperty="@(x => x?.Id ?? -1)"
Loader="LoadNodes"/>
<InputItem TItem="NodeResponse"
DisplayField="@(x => x.Name)"
SearchField="@(x => x.Name)"
ItemSource="LoadNodes"
@bind-Value="Node">
</InputItem>
</div>
</div>
</div>
<div class="border-t border-gray-100/10 pt-6 my-8">
<div class="mb-8"><h2 class="text-base font-semibold leading-7 text-gray-100">
<div class="border-t border-base-content/20 pt-6 my-8">
<div class="mb-8">
<h2 class="text-base font-semibold leading-7 text-base-content">
Resources
</h2>
<p class="mt-1 text-sm leading-6 text-gray-400">Define the servers resource limit</p></div>
<p class="mt-1 text-sm leading-6 text-base-content/60">Define the servers resource limit</p>
</div>
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Cpu</label>
<label class="block text-sm font-medium leading-6 text-base-content">Cpu</label>
<div class="mt-2">
<input @bind="Request.Cpu" type="number" autocomplete="off" class="form-input w-full">
<input @bind="Request.Cpu" type="number" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Memory</label>
<label class="block text-sm font-medium leading-6 text-base-content">Memory</label>
<div class="mt-2">
<input @bind="Request.Memory" type="number" autocomplete="off" class="form-input w-full">
<input @bind="Request.Memory" type="number" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Disk</label>
<label class="block text-sm font-medium leading-6 text-base-content">Disk</label>
<div class="mt-2">
<input @bind="Request.Disk" type="number" autocomplete="off" class="form-input w-full">
<input @bind="Request.Disk" type="number" autocomplete="off" class="input w-full">
</div>
</div>
</div>
@@ -89,46 +89,34 @@
{
[Parameter] public CreateServerRequest Request { get; set; }
private UserResponse[]? Users;
[Parameter] public UserResponse? User { get; set; }
[Parameter] public NodeResponse? Node { get; set; }
[Parameter] public StarDetailResponse? Star { get; set; }
private async Task<StarDetailResponse[]> LoadStars()
{
var items = await PagedData<StarDetailResponse>.All(async (page, pageSize) =>
return await PagedData<StarDetailResponse>.All(async (page, pageSize) =>
await ApiClient.GetJson<PagedData<StarDetailResponse>>(
$"api/admin/servers/stars?page={page}&pageSize={pageSize}"
)
);
return items;
}
private async Task<NodeResponse[]> LoadNodes()
{
var items = await PagedData<NodeResponse>.All(async (page, pageSize) =>
return await PagedData<NodeResponse>.All(async (page, pageSize) =>
await ApiClient.GetJson<PagedData<NodeResponse>>(
$"api/admin/servers/nodes?page={page}&pageSize={pageSize}"
)
);
return items;
}
private async Task<UserResponse[]> Loader(string searchTerm)
private async Task<UserResponse[]> LoadUsers()
{
if (Users == null)
{
Users = await PagedData<UserResponse>.All(async (page, pageSize) =>
return await PagedData<UserResponse>.All(async (page, pageSize) =>
await ApiClient.GetJson<PagedData<UserResponse>>(
$"api/admin/users?page={page}&pageSize={pageSize}"
)
);
}
if (string.IsNullOrEmpty(searchTerm))
return Users;
return Users
.Where(x => x.Email.Contains(searchTerm))
.ToArray();
}
}

View File

@@ -1,9 +1,9 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonlightServers.Shared.Http.Requests.Admin.Servers
@using MoonCore.Helpers
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Models
@using MoonlightServers.Shared.Http.Requests.Admin.ServerVariables
@using MoonlightServers.Shared.Http.Responses.Admin.Stars
@using MoonlightServers.Shared.Http.Responses.Admin.StarVariables
@inject HttpApiClient ApiClient
@@ -19,17 +19,17 @@
: variable.DefaultValue;
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">
<label class="block text-sm font-medium leading-6 text-base-content">
@variable.Name
</label>
<div class="mt-2">
<input type="text"
class="form-input placeholder-gray-500 w-full"
class="input placeholder-base-content/50 w-full"
value="@value"
placeholder="@variable.DefaultValue"
@onchange="@(args => UpdateValue(variable, args))"/>
</div>
<p class="mt-1 text-sm leading-6 text-gray-400">
<p class="mt-1 text-sm leading-6 text-base-content/60">
@variable.Description
</p>
</div>
@@ -40,12 +40,13 @@
@code
{
[Parameter] public CreateServerRequest Request { get; set; }
[Parameter] public StarDetailResponse? Star { get; set; }
private StarVariableDetailResponse[] StarVariables;
private async Task Load(LazyLoader _)
{
if (Request.StarId <= 0)
if (Star == null)
{
StarVariables = [];
return;

View File

@@ -1,10 +1,9 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Components
@using MoonlightServers.Shared.Enums
@using MoonlightServers.Shared.Http.Requests.Client.Servers.Shares
@using MoonlightServers.Shared.Models
@inherits MoonCore.Blazor.Tailwind.Modals.Components.BaseModal
@inherits MoonCore.Blazor.FlyonUi.Modals.Components.BaseModal
<div class="text-lg font-semibold mb-5">
Create a new share
@@ -12,8 +11,8 @@
<HandleForm @ref="HandleForm" Model="Request" OnValidSubmit="OnValidSubmit">
<div class="mb-8">
<label class="block text-sm font-medium leading-6 text-white">Username</label>
<input @bind="Request.Username" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Username</label>
<input @bind="Request.Username" type="text" class="input w-full"/>
</div>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-y-5 lg:gap-y-3">
@foreach (var name in Names)

View File

@@ -1,3 +1,4 @@
@using Microsoft.Extensions.Logging
@using MoonCore.Helpers
@using MoonlightServers.Frontend.Services
@using MoonlightServers.Shared.Enums
@@ -7,38 +8,38 @@
@inject ILogger<ServerCard> Logger
@{
var gradient = "from-gray-600/20";
var border = "border-gray-600";
var gradient = "from-base-content/20";
var border = "border-base-content";
if (IsLoaded && !IsFailed)
{
gradient = Status.State switch
{
ServerState.Installing => "from-primary/20",
ServerState.Offline => "from-danger/20",
ServerState.Offline => "from-error/20",
ServerState.Starting => "from-warning/20",
ServerState.Stopping => "from-warning/20",
ServerState.Online => "from-success/20",
_ => "from-gray-600/20"
_ => "from-base-content/20"
};
border = Status.State switch
{
ServerState.Installing => "border-primary",
ServerState.Offline => "border-danger",
ServerState.Offline => "border-error",
ServerState.Starting => "border-warning",
ServerState.Stopping => "border-warning",
ServerState.Online => "border-success",
_ => "border-gray-600"
_ => "border-base-content"
};
}
}
<a href="/servers/@Server.Id"
class="w-full bg-gradient-to-r @gradient to-gray-750 to-25% px-5 py-3.5 rounded-xl border-l-8 @border">
class="w-full bg-gradient-to-r @gradient to-base-content/75 to-25% px-5 py-3.5 rounded-xl border-l-8 @border">
<div class="grid grid-cols-6">
<div class="flex items-center col-span-6 sm:col-span-2 2xl:col-span-1">
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex items-center">
<div class="bg-base-content/10 bg-opacity-45 py-1 px-2 rounded-lg flex items-center">
<i class="icon-server me-3 align-middle"></i>
<div class="text-lg align-middle">
@Server.Name
@@ -53,7 +54,7 @@
Status.State is ServerState.Starting or ServerState.Stopping or ServerState.Online
)
{
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
<div class="bg-base-content/35 py-1 px-2 rounded-lg flex flex-row">
<div>
<i class="icon-cpu"></i>
</div>
@@ -61,7 +62,7 @@
<div class="ms-3">@(Stats.CpuUsage)%</div>
</div>
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
<div class="bg-base-content/35 py-1 px-2 rounded-lg flex flex-row">
<div>
<i class="icon-memory-stick"></i>
</div>
@@ -69,7 +70,7 @@
<div class="ms-3">@(Formatter.FormatSize(Stats.MemoryUsage)) / @(Formatter.FormatSize(ByteConverter.FromMegaBytes(Server.Memory).Bytes))</div>
</div>
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
<div class="bg-base-content/35 py-1 px-2 rounded-lg flex flex-row">
<div>
<i class="icon-hard-drive"></i>
</div>
@@ -81,7 +82,7 @@
{
if (!IsLoaded)
{
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row text-gray-700">
<div class="bg-base-content/35 py-1 px-2 rounded-lg flex flex-row text-gray-700">
<div>
<i class="icon-loader"></i>
</div>
@@ -91,7 +92,7 @@
}
else if (IsFailed)
{
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row text-danger">
<div class="bg-base-content/35 py-1 px-2 rounded-lg flex flex-row text-error">
<div>
<i class="icon-cable"></i>
</div>
@@ -101,7 +102,7 @@
}
else if (IsLoaded && !IsFailed && Status.State is ServerState.Offline)
{
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row text-danger">
<div class="bg-base-content/35 py-1 px-2 rounded-lg flex flex-row text-error">
<div>
<i class="icon-power-off"></i>
</div>
@@ -111,7 +112,7 @@
}
else if (IsLoaded && !IsFailed && Status.State is ServerState.Installing)
{
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row text-primary">
<div class="bg-base-content/35 py-1 px-2 rounded-lg flex flex-row text-primary">
<div>
<i class="icon-hammer"></i>
</div>
@@ -126,7 +127,7 @@
@if (Server.Share != null)
{
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row col-span-2">
<div class="bg-base-content/35 py-1 px-2 rounded-lg flex flex-row col-span-2">
<div>
<i class="icon-share-2"></i>
</div>
@@ -136,7 +137,7 @@
}
else
{
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
<div class="bg-base-content/35 py-1 px-2 rounded-lg flex flex-row">
<div>
<i class="icon-sparkles"></i>
</div>
@@ -144,7 +145,7 @@
<div class="ms-3">@Server.StarName</div>
</div>
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row">
<div class="bg-base-content/35 py-1 px-2 rounded-lg flex flex-row">
<div>
<i class="icon-database"></i>
</div>

View File

@@ -1,26 +1,22 @@
@using MoonCore.Blazor.FlyonUi.Helpers
@using MoonlightServers.Frontend.Services
@using MoonCore.Blazor.Tailwind.Fm
@using MoonCore.Blazor.Tailwind.Services
@using MoonCore.Blazor.FlyonUi.Files.Manager
@using MoonlightServers.Frontend.Helpers
@inherits BaseServerTab
@inject ServerFileSystemService FileSystemService
@inject DownloadService DownloadService
<FileManager FileSystemProvider="Provider" MaxUploadSize="4096"/>
<FileManager FsAccess="FsAccess" />
@code
{
private IFileSystemProvider Provider;
private IFsAccess FsAccess;
protected override void OnInitialized()
{
Provider = new ServerFileSystemProvider(
FsAccess = new ServerFsAccess(
Server.Id,
FileSystemService,
DownloadService
FileSystemService
);
}
}

View File

@@ -1,8 +1,5 @@
@using MoonCore.Blazor.FlyonUi.Alerts
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Alerts
@using MoonCore.Helpers
@using MoonCore.Blazor.Tailwind.Components
@using MoonlightServers.Frontend.Services
@using MoonlightServers.Shared.Enums

View File

@@ -2,10 +2,6 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.FlyonUi.Modals
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Alerts
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Modals
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonCore.Models
@using MoonlightServers.Frontend.Services
@using MoonlightServers.Shared.Http.Requests.Client.Servers.Shares
@@ -19,7 +15,7 @@
@inject AlertService AlertService
<div class="flex flex-row mb-5">
<input @bind="UsernameInput" class="form-input grow placeholder-gray-500 me-1.5" autocomplete="none" placeholder="Enter a username"/>
<input @bind="UsernameInput" class="input grow placeholder-base-content/50 me-1.5" autocomplete="none" placeholder="Enter a username"/>
<button @onclick="OpenCreateModal" class="btn btn-primary">
<i class="icon-send me-1"></i>
<span>Invite</span>
@@ -48,7 +44,7 @@
<i class="icon-settings-2 me-1"></i>
<span>Edit</span>
</WButton>
<WButton OnClick="_ => Delete(share)" CssClasses="btn btn-danger">
<WButton OnClick="_ => Delete(share)" CssClasses="btn btn-error">
<i class="icon-trash-2 me-1"></i>
<span>Delete</span>
</WButton>

View File

@@ -1,7 +1,5 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonlightServers.Frontend.Services
@using MoonlightServers.Shared.Http.Responses.Client.Servers.Variables
@@ -15,17 +13,17 @@
@foreach (var variable in Variables)
{
<div class="sm:col-span-2 card card-body p-5">
<label class="block text-sm font-medium leading-6 text-white">
<label class="block text-sm font-medium leading-6 text-base-content">
@variable.Name
</label>
<p class="mt-1 mb-2.5 text-sm leading-6 text-gray-400">
<p class="mt-1 mb-2.5 text-sm leading-6 text-base-content/60">
@variable.Description
</p>
<div class="mt-auto">
<input @onchange="e => UpdateVariable(variable, e)"
value="@variable.Value"
type="text"
class="form-input w-full">
class="input w-full">
</div>
</div>
}

View File

@@ -71,7 +71,7 @@
}
else if (Status == 3)
{
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row text-danger">
<div class="bg-gray-900 bg-opacity-45 py-1 px-2 rounded-lg flex flex-row text-error">
<div>
<i class="icon-power-off"></i>
</div>

View File

@@ -1,11 +1,10 @@
@using MoonlightServers.Shared.Http.Requests.Admin.Servers
@using MoonCore.Blazor.Tailwind.Inputs
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Bandwidth</label>
<label class="block text-sm font-medium leading-6 text-base-content">Bandwidth</label>
<div class="mt-2">
<input @bind="Request.Bandwidth" type="number" autocomplete="off" class="form-input w-full">
<input @bind="Request.Bandwidth" type="number" autocomplete="off" class="input w-full">
</div>
</div>
</div>

View File

@@ -1,23 +1,22 @@
@using MoonlightServers.Shared.Http.Requests.Admin.Servers
@using MoonCore.Blazor.Tailwind.Inputs
@using MoonCore.Helpers
@using MoonCore.Models
@using MoonlightServers.Shared.Http.Responses.Admin.NodeAllocations
@using MoonlightServers.Shared.Http.Responses.Admin.Servers
@using MoonCore.Blazor.FlyonUi.Forms
@inject HttpApiClient ApiClient
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Allocations</label>
<label class="block text-sm font-medium leading-6 text-base-content">Allocations</label>
<div class="mt-2">
<InputMultiSelect TItem="NodeAllocationDetailResponse"
TProperty="int"
@bind-Value="Request.AllocationIds"
Loader="Loader"
AllowSearch="true"
DisplayProperty="@(x => $"{x.IpAddress}:{x.Port}")"
ValueProperty="@(x => x.Id)"/>
<InputMultipleItem TItem="NodeAllocationResponse"
Value="Allocations"
DisplayField="@(x => $"{x.IpAddress}:{x.Port}")"
SearchField="@(x => $"{x.IpAddress}:{x.Port}")"
ItemSource="Loader">
</InputMultipleItem>
</div>
</div>
</div>
@@ -26,15 +25,14 @@
{
[Parameter] public UpdateServerRequest Request { get; set; }
[Parameter] public ServerResponse Server { get; set; }
[Parameter] public List<NodeAllocationResponse> Allocations { get; set; }
private async Task<NodeAllocationResponse[]> Loader()
{
var items = await PagedData<NodeAllocationResponse>.All(async (page, pageSize) =>
return await PagedData<NodeAllocationResponse>.All(async (page, pageSize) =>
await ApiClient.GetJson<PagedData<NodeAllocationResponse>>(
$"api/admin/servers/nodes/{Server.NodeId}/allocations/free?page={page}&pageSize={pageSize}&serverId={Server.Id}"
)
);
return items;
}
}

View File

@@ -1,59 +1,58 @@
@using MoonlightServers.Shared.Http.Requests.Admin.Servers
@using MoonCore.Helpers
@using MoonCore.Models
@using MoonCore.Blazor.Tailwind.Inputs
@using Moonlight.Shared.Http.Responses.Admin.Users
@using MoonCore.Blazor.FlyonUi.Forms
@inject HttpApiClient ApiClient
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Name</label>
<label class="block text-sm font-medium leading-6 text-base-content">Name</label>
<div class="mt-2">
<input @bind="Request.Name" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.Name" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Owner</label>
<label class="block text-sm font-medium leading-6 text-base-content">Owner</label>
<div class="mt-2">
<InputItemSearchSelect TItem="UserResponse"
TProperty="int"
@bind-Value="Request.OwnerId"
AllowNone="false"
Loader="Loader"
DisplayProperty="@(x => x.Email)"
ValueProperty="@(x => x.Id)"/>
<InputItem TItem="UserResponse"
DisplayField="@(x => x.Username)"
SearchField="@(x => x.Username)"
@bind-Value="Owner"
ItemSource="Loader">
</InputItem>
</div>
</div>
</div>
<div class="border-t border-gray-100/10 pt-6 my-8">
<div class="mb-8"><h2 class="text-base font-semibold leading-7 text-gray-100">
<div class="border-t border-base-content/10 pt-6 my-8">
<div class="mb-8"><h2 class="text-base font-semibold leading-7 text-base-content">
Resources
</h2>
<p class="mt-1 text-sm leading-6 text-gray-400">Define the servers resource limit</p></div>
<p class="mt-1 text-sm leading-6 text-base-content/60">Define the servers resource limit</p></div>
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Cpu</label>
<label class="block text-sm font-medium leading-6 text-base-content">Cpu</label>
<div class="mt-2">
<input @bind="Request.Cpu" type="number" autocomplete="off" class="form-input w-full">
<input @bind="Request.Cpu" type="number" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Memory</label>
<label class="block text-sm font-medium leading-6 text-base-content">Memory</label>
<div class="mt-2">
<input @bind="Request.Memory" type="number" autocomplete="off" class="form-input w-full">
<input @bind="Request.Memory" type="number" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Disk</label>
<label class="block text-sm font-medium leading-6 text-base-content">Disk</label>
<div class="mt-2">
<input @bind="Request.Disk" type="number" autocomplete="off" class="form-input w-full">
<input @bind="Request.Disk" type="number" autocomplete="off" class="input w-full">
</div>
</div>
</div>
@@ -62,25 +61,14 @@
@code
{
[Parameter] public UpdateServerRequest Request { get; set; }
[Parameter] public UserResponse Owner { get; set; }
private UserResponse[]? Users;
private async Task<UserResponse[]> Loader(string searchTerm)
private async Task<UserResponse[]> Loader()
{
if (Users == null)
{
Users = await PagedData<UserResponse>.All(async (page, pageSize) =>
return await PagedData<UserResponse>.All(async (page, pageSize) =>
await ApiClient.GetJson<PagedData<UserResponse>>(
$"api/admin/users?page={page}&pageSize={pageSize}"
)
);
}
if (string.IsNullOrEmpty(searchTerm))
return Users;
return Users
.Where(x => x.Email.Contains(searchTerm))
.ToArray();
}
}

View File

@@ -1,7 +1,6 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonlightServers.Shared.Http.Requests.Admin.Servers
@using MoonCore.Helpers
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Models
@using MoonlightServers.Shared.Http.Requests.Admin.ServerVariables
@using MoonlightServers.Shared.Http.Responses.Admin.Servers
@@ -26,14 +25,14 @@
: variable.Value;
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">
<label class="block text-sm font-medium leading-6 text-base-content">
@starVariable.Name
</label>
<div class="mt-2">
<input type="text" class="form-input w-full" value="@value"
<input type="text" class="input w-full" value="@value"
@onchange="@(args => UpdateValue(variable, args))"/>
</div>
<p class="mt-1 text-sm leading-6 text-gray-400">
<p class="mt-1 text-sm leading-6 text-base-content/60">
@starVariable.Description
</p>
</div>

View File

@@ -1,11 +1,10 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Components
@using MoonlightServers.Shared.Enums
@using MoonlightServers.Shared.Http.Requests.Client.Servers.Shares
@using MoonlightServers.Shared.Http.Responses.Client.Servers.Shares
@using MoonlightServers.Shared.Models
@inherits MoonCore.Blazor.Tailwind.Modals.Components.BaseModal
@inherits MoonCore.Blazor.FlyonUi.Modals.Components.BaseModal
<div class="text-lg font-semibold mb-5">
Update share for @Share.Username

View File

@@ -1,8 +1,5 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Modals.Components
@using MoonlightServers.Shared.Enums
@using MoonlightServers.Frontend.UI.Components.Forms
@using MoonCore.Blazor.Tailwind.Components
@using MoonlightServers.Shared.Http.Requests.Admin.StarDockerImages
@inherits MoonCore.Blazor.FlyonUi.Modals.Components.BaseModal
@@ -12,17 +9,17 @@
<HandleForm @ref="HandleForm" Model="Form" OnValidSubmit="OnValidSubmit">
<div class="grid grid-cols-2 gap-2">
<div class="col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Display Name</label>
<input @bind="Form.DisplayName" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Display Name</label>
<input @bind="Form.DisplayName" type="text" class="input w-full"/>
</div>
<div class="col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Identifier</label>
<input @bind="Form.Identifier" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Identifier</label>
<input @bind="Form.Identifier" type="text" class="input w-full"/>
</div>
<div class="col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Automatic pulling</label>
<label class="block text-sm font-medium leading-6 text-base-content">Automatic pulling</label>
<Switch @bind-Value="Form.AutoPulling"/>
</div>
</div>

View File

@@ -1,7 +1,5 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Modals.Components
@using MoonlightServers.Shared.Enums
@using MoonCore.Blazor.Tailwind.Components
@using MoonlightServers.Shared.Models
@inherits MoonCore.Blazor.FlyonUi.Modals.Components.BaseModal
@@ -11,13 +9,13 @@
<HandleForm @ref="HandleForm" Model="Form" OnValidSubmit="OnValidSubmit">
<div class="grid grid-cols-2 gap-x-2 gap-y-4">
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">File</label>
<input @bind="Form.File" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">File</label>
<input @bind="Form.File" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Type</label>
<select @bind="Form.Parser" class="form-select w-full">
<label class="block text-sm font-medium leading-6 text-base-content">Type</label>
<select @bind="Form.Parser" class="select w-full">
@foreach (var val in Enum.GetValues<FileParsers>())
{
<option value="@val">@val</option>
@@ -26,16 +24,16 @@
</div>
<div class="col-span-2">
<button @onclick="AddEntry" class="btn btn-primary w-full">Add entry</button>
<button type="button" @onclick="AddEntry" class="btn btn-primary w-full">Add entry</button>
</div>
@foreach (var entry in Form.Entries)
{
<div class="col-span-2">
<div class="flex flex-row">
<input @bind="entry.Key" placeholder="Key" class="form-input placeholder-gray-500 grow rounded-r-none"/>
<input @bind="entry.Value" placeholder="Value" class="form-input placeholder-gray-500 grow rounded-none"/>
<button @onclick="() => RemoveEntry(entry)" class="btn btn-danger grow-0 rounded-l-none">
<input @bind="entry.Key" placeholder="Key" class="input placeholder-base-content/50 grow rounded-r-none"/>
<input @bind="entry.Value" placeholder="Value" class="input placeholder-base-content/50 grow rounded-none"/>
<button type="button" @onclick="() => RemoveEntry(entry)" class="btn btn-error grow-0 rounded-l-none">
<i class="icon-x"></i>
</button>
</div>

View File

@@ -1,9 +1,7 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Modals.Components
@using MoonlightServers.Shared.Enums
@using MoonlightServers.Shared.Http.Requests.Admin.StarVariables
@using MoonlightServers.Frontend.UI.Components.Forms
@using MoonCore.Blazor.Tailwind.Components
@inherits MoonCore.Blazor.FlyonUi.Modals.Components.BaseModal
@@ -12,38 +10,38 @@
<HandleForm @ref="HandleForm" Model="Form" OnValidSubmit="OnValidSubmit">
<div class="grid grid-cols-2 gap-2">
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Name</label>
<input @bind="Form.Name" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Name</label>
<input @bind="Form.Name" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Description</label>
<input @bind="Form.Description" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Description</label>
<input @bind="Form.Description" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Key</label>
<input @bind="Form.Key" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Key</label>
<input @bind="Form.Key" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Default Value</label>
<input @bind="Form.DefaultValue" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Default Value</label>
<input @bind="Form.DefaultValue" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Allow Viewing</label>
<label class="block text-sm font-medium leading-6 text-base-content">Allow Viewing</label>
<Switch @bind-Value="Form.AllowViewing"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Allow Editing</label>
<label class="block text-sm font-medium leading-6 text-base-content">Allow Editing</label>
<Switch @bind-Value="Form.AllowEditing"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Type</label>
<select @bind="Form.Type" class="form-select w-full">
<label class="block text-sm font-medium leading-6 text-base-content">Type</label>
<select @bind="Form.Type" class="select w-full">
@foreach (var val in Enum.GetValues<StarVariableType>())
{
<option value="@val">@val</option>
@@ -52,8 +50,8 @@
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Filter</label>
<input @bind="Form.Filter" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Filter</label>
<input @bind="Form.Filter" type="text" class="input w-full"/>
</div>
</div>
</HandleForm>

View File

@@ -1,8 +1,5 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Modals.Components
@using MoonlightServers.Frontend.UI.Components.Forms
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Helpers
@using MoonlightServers.Shared.Http.Requests.Admin.StarDockerImages
@using MoonlightServers.Shared.Http.Responses.Admin.StarDockerImages
@@ -13,17 +10,17 @@
<HandleForm @ref="HandleForm" Model="Form" OnValidSubmit="OnValidSubmit">
<div class="grid grid-cols-2 gap-2">
<div class="col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Display Name</label>
<input @bind="Form.DisplayName" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Display Name</label>
<input @bind="Form.DisplayName" type="text" class="input w-full"/>
</div>
<div class="col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Identifier</label>
<input @bind="Form.Identifier" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Identifier</label>
<input @bind="Form.Identifier" type="text" class="input w-full"/>
</div>
<div class="col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Automatic pulling</label>
<label class="block text-sm font-medium leading-6 text-base-content">Automatic pulling</label>
<Switch @bind-Value="Form.AutoPulling"/>
</div>
</div>
@@ -44,7 +41,12 @@
protected override void OnInitialized()
{
Form = Mapper.Map<UpdateStarDockerImageRequest>(DockerImage);
Form = new UpdateStarDockerImageRequest()
{
AutoPulling = DockerImage.AutoPulling,
DisplayName = DockerImage.DisplayName,
Identifier = DockerImage.Identifier
};
}
private async Task OnValidSubmit()

View File

@@ -1,8 +1,5 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Modals.Components
@using MoonlightServers.Shared.Enums
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Helpers
@using MoonlightServers.Shared.Models
@inherits MoonCore.Blazor.FlyonUi.Modals.Components.BaseModal
@@ -12,13 +9,13 @@
<HandleForm @ref="HandleForm" Model="Form" OnValidSubmit="OnValidSubmit">
<div class="grid grid-cols-2 gap-x-2 gap-y-4">
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">File</label>
<input @bind="Form.File" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">File</label>
<input @bind="Form.File" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Type</label>
<select @bind="Form.Parser" class="form-select w-full">
<label class="block text-sm font-medium leading-6 text-base-content">Type</label>
<select @bind="Form.Parser" class="select w-full">
@foreach (var val in Enum.GetValues<FileParsers>())
{
<option value="@val">@val</option>
@@ -27,16 +24,16 @@
</div>
<div class="col-span-2">
<button @onclick="AddEntry" class="btn btn-primary w-full">Add entry</button>
<button type="button" @onclick="AddEntry" class="btn btn-primary w-full">Add entry</button>
</div>
@foreach (var entry in Form.Entries)
{
<div class="col-span-2">
<div class="flex flex-row">
<input @bind="entry.Key" placeholder="Key" class="form-input placeholder-gray-500 grow rounded-r-none"/>
<input @bind="entry.Value" placeholder="Value" class="form-input placeholder-gray-500 grow rounded-none"/>
<button @onclick="() => RemoveEntry(entry)" class="btn btn-danger grow-0 rounded-l-none">
<input @bind="entry.Key" placeholder="Key" class="input placeholder-base-content/50 grow rounded-r-none"/>
<input @bind="entry.Value" placeholder="Value" class="input placeholder-base-content/50 grow rounded-none"/>
<button type="button" @onclick="() => RemoveEntry(entry)" class="btn btn-error grow-0 rounded-l-none">
<i class="icon-x"></i>
</button>
</div>

View File

@@ -1,10 +1,7 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Modals.Components
@using MoonlightServers.Shared.Enums
@using MoonlightServers.Shared.Http.Requests.Admin.StarVariables
@using MoonlightServers.Frontend.UI.Components.Forms
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Helpers
@using MoonlightServers.Shared.Http.Responses.Admin.StarVariables
@inherits MoonCore.Blazor.FlyonUi.Modals.Components.BaseModal
@@ -14,38 +11,38 @@
<HandleForm @ref="HandleForm" Model="Form" OnValidSubmit="OnValidSubmit">
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Name</label>
<input @bind="Form.Name" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Name</label>
<input @bind="Form.Name" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Description</label>
<input @bind="Form.Description" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Description</label>
<input @bind="Form.Description" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Key</label>
<input @bind="Form.Key" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Key</label>
<input @bind="Form.Key" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Default Value</label>
<input @bind="Form.DefaultValue" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Default Value</label>
<input @bind="Form.DefaultValue" type="text" class="input w-full"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Allow Viewing</label>
<label class="block text-sm font-medium leading-6 text-base-content">Allow Viewing</label>
<Switch @bind-Value="Form.AllowViewing"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Allow Editing</label>
<label class="block text-sm font-medium leading-6 text-base-content">Allow Editing</label>
<Switch @bind-Value="Form.AllowEditing"/>
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Type</label>
<select @bind="Form.Type" class="form-select w-full">
<label class="block text-sm font-medium leading-6 text-base-content">Type</label>
<select @bind="Form.Type" class="select w-full">
@foreach (var val in Enum.GetValues<StarVariableType>())
{
<option value="@val">@val</option>
@@ -54,8 +51,8 @@
</div>
<div class="col-span-1">
<label class="block text-sm font-medium leading-6 text-white">Filter</label>
<input @bind="Form.Filter" type="text" class="form-input w-full"/>
<label class="block text-sm font-medium leading-6 text-base-content">Filter</label>
<input @bind="Form.Filter" type="text" class="input w-full"/>
</div>
</div>
</HandleForm>
@@ -75,7 +72,17 @@
protected override void OnInitialized()
{
Form = Mapper.Map<UpdateStarVariableRequest>(Variable);
Form = new()
{
Name = Variable.Name,
AllowEditing = Variable.AllowEditing,
AllowViewing = Variable.AllowViewing,
DefaultValue = Variable.DefaultValue,
Description = Variable.Description,
Filter = Variable.Filter,
Key = Variable.Key,
Type = Variable.Type
};
}
private async Task OnValidSubmit()

View File

@@ -2,10 +2,6 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.FlyonUi.Modals
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Alerts
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Modals
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonCore.Helpers
@using MoonCore.Models
@using MoonlightServers.Frontend.UI.Components.Stars.Modals
@@ -34,11 +30,11 @@
</div>
<div class="gap-x-2">
<button @onclick="() => UpdateDockerImage(dockerImage)" class="btn btn-primary">
<button type="button" @onclick="() => UpdateDockerImage(dockerImage)" class="btn btn-primary">
<i class="icon-settings text-base"></i>
</button>
<button @onclick="() => DeleteDockerImage(dockerImage)" class="btn btn-danger">
<button type="button" @onclick="() => DeleteDockerImage(dockerImage)" class="btn btn-error">
<i class="icon-trash text-base"></i>
</button>
</div>

View File

@@ -3,33 +3,33 @@
<div>
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Name</label>
<label class="block text-sm font-medium leading-6 text-base-content">Name</label>
<div class="mt-2">
<input @bind="Request.Name" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.Name" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Version</label>
<label class="block text-sm font-medium leading-6 text-base-content">Version</label>
<div class="mt-2">
<input @bind="Request.Version" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.Version" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Author</label>
<label class="block text-sm font-medium leading-6 text-base-content">Author</label>
<div class="mt-2">
<input @bind="Request.Author" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.Author" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Donate Url</label>
<label class="block text-sm font-medium leading-6 text-base-content">Donate Url</label>
<div class="mt-2">
<input @bind="Request.DonateUrl" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.DonateUrl" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Update Url</label>
<label class="block text-sm font-medium leading-6 text-base-content">Update Url</label>
<div class="mt-2">
<input @bind="Request.UpdateUrl" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.UpdateUrl" type="text" autocomplete="off" class="input w-full">
</div>
</div>
</div>

View File

@@ -1,23 +1,22 @@
@using MoonCore.Blazor.FlyonUi.Ace
@using MoonlightServers.Shared.Http.Requests.Admin.Stars
@using MoonCore.Blazor.Tailwind.Ace
<div>
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-3">
<label class="block text-sm font-medium leading-6 text-white">Docker Image</label>
<label class="block text-sm font-medium leading-6 text-base-content">Docker Image</label>
<div class="mt-2">
<input @bind="Request.InstallDockerImage" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.InstallDockerImage" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-3">
<label class="block text-sm font-medium leading-6 text-white">Shell</label>
<label class="block text-sm font-medium leading-6 text-base-content">Shell</label>
<div class="mt-2">
<input @bind="Request.InstallShell" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.InstallShell" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-6">
<label class="block text-sm font-medium leading-6 text-white">Script</label>
<label class="block text-sm font-medium leading-6 text-base-content">Script</label>
<div class="mt-2" @onfocusout="OnFocusOut">
<CodeEditor @ref="CodeEditor" InitialContent="@Request.InstallScript" OnConfigure="OnConfigure" />
</div>

View File

@@ -1,5 +1,4 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Helpers
@using MoonCore.Models
@using MoonlightServers.Shared.Http.Requests.Admin.Stars
@@ -13,15 +12,15 @@
<div>
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Allow docker image change</label>
<label class="block text-sm font-medium leading-6 text-base-content">Allow docker image change</label>
<div class="mt-2">
<Switch @bind-Value="Request.AllowDockerImageChange" />
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Default docker image</label>
<label class="block text-sm font-medium leading-6 text-base-content">Default docker image</label>
<div class="mt-2">
<select @bind="Request.DefaultDockerImage" class="form-select w-full">
<select @bind="Request.DefaultDockerImage" class="select w-full">
@foreach (var dockerImage in DockerImages)
{
var index = DockerImages.IndexOf(dockerImage);

View File

@@ -1,10 +1,8 @@
@using System.Text.Json
@using Microsoft.Extensions.Logging
@using MoonCore.Blazor.FlyonUi.Alerts
@using MoonCore.Blazor.FlyonUi.Modals
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Alerts
@using MoonCore.Blazor.Tailwind.Modals
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonlightServers.Frontend.UI.Components.Stars.Modals
@using MoonlightServers.Shared.Http.Requests.Admin.Stars
@using MoonlightServers.Shared.Models
@@ -35,11 +33,11 @@ else
</div>
<div class="gap-x-2">
<button @onclick="() => UpdateConfig(configuration)" class="btn btn-primary">
<button type="button" @onclick="() => UpdateConfig(configuration)" class="btn btn-primary">
<i class="icon-settings text-base"></i>
</button>
<button @onclick="() => DeleteConfig(configuration)" class="btn btn-danger">
<button type="button" @onclick="() => DeleteConfig(configuration)" class="btn btn-error">
<i class="icon-trash text-base"></i>
</button>
</div>

View File

@@ -2,21 +2,21 @@
<div>
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-4">
<label class="block text-sm font-medium leading-6 text-white">Startup Command</label>
<label class="block text-sm font-medium leading-6 text-base-content">Startup Command</label>
<div class="mt-2">
<input @bind="Request.StartupCommand" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.StartupCommand" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Stop Command</label>
<label class="block text-sm font-medium leading-6 text-base-content">Stop Command</label>
<div class="mt-2">
<input @bind="Request.StopCommand" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.StopCommand" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Online Detection</label>
<label class="block text-sm font-medium leading-6 text-base-content">Online Detection</label>
<div class="mt-2">
<input @bind="Request.OnlineDetection" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.OnlineDetection" type="text" autocomplete="off" class="input w-full">
</div>
</div>
</div>

View File

@@ -2,10 +2,6 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.FlyonUi.Modals
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Alerts
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Modals
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonCore.Helpers
@using MoonCore.Models
@using MoonlightServers.Frontend.UI.Components.Stars.Modals
@@ -34,11 +30,11 @@
</div>
<div class="gap-x-2">
<button @onclick="() => UpdateVariable(variable)" class="btn btn-primary">
<button type="button" @onclick="() => UpdateVariable(variable)" class="btn btn-primary">
<i class="icon-settings text-base"></i>
</button>
<button @onclick="() => DeleteVariable(variable)" class="btn btn-danger">
<button type="button" @onclick="() => DeleteVariable(variable)" class="btn btn-error">
<i class="icon-trash text-base"></i>
</button>
</div>

View File

@@ -1,9 +1,10 @@
@using Microsoft.Extensions.Logging
@using XtermBlazor
@inject IJSRuntime JsRuntime
@inject ILogger<XtermConsole> Logger
<div class="bg-black rounded-lg p-2">
<div class="bg-background rounded-lg p-2">
@if (IsInitialized)
{
<Xterm @ref="Terminal"

View File

@@ -2,11 +2,13 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonCore.Helpers
@using Moonlight.Shared.Http.Responses.Admin.Users
@using MoonlightServers.Shared.Http.Requests.Admin.Servers
@using MoonlightServers.Frontend.UI.Components.Servers.CreateServerPartials
@using MoonlightServers.Shared.Http.Responses.Admin.NodeAllocations
@using MoonlightServers.Shared.Http.Responses.Admin.Nodes
@using MoonlightServers.Shared.Http.Responses.Admin.Stars
@inject HttpApiClient ApiClient
@inject NavigationManager Navigation
@@ -29,13 +31,13 @@
<HandleForm @ref="Form" Model="Request" OnValidSubmit="OnSubmit">
<Tabs>
<Tab Name="General">
<GeneralServerCreate Request="Request" />
<GeneralServerCreate Request="Request" Star="Star" Node="Node" User="Owner" />
</Tab>
<Tab Name="Allocations">
<AllocationsServerCreate Request="Request" />
<AllocationsServerCreate Request="Request" Allocations="Allocations" Node="Node" />
</Tab>
<Tab Name="Variables">
<VariablesServerCreate Request="Request" />
<VariablesServerCreate Request="Request" Star="Star" />
</Tab>
<Tab Name="Advanced">
<AdvancedServerCreate Request="Request" />
@@ -49,6 +51,11 @@
private HandleForm Form;
private CreateServerRequest Request;
private List<NodeAllocationResponse> Allocations = new();
private UserResponse? Owner;
private StarDetailResponse? Star;
private NodeResponse? Node;
protected override void OnInitialized()
{
Request = new();
@@ -56,6 +63,14 @@
private async Task OnSubmit()
{
Request.AllocationIds = Allocations
.Select(x => x.Id)
.ToArray();
Request.StarId = Star?.Id ?? -1;
Request.NodeId = Node?.Id ?? -1;
Request.OwnerId = Owner?.Id ?? -1;
await ApiClient.Post("api/admin/servers", Request);
await ToastService.Success("Successfully created Server");

View File

@@ -3,15 +3,12 @@
@using MoonCore.Blazor.FlyonUi.Alerts
@using MoonCore.Blazor.FlyonUi.DataTables
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Alerts
@using MoonCore.Helpers
@using MoonCore.Models
@using MoonlightServers.Shared.Http.Responses.Admin.Nodes
@using MoonlightServers.Shared.Http.Responses.Admin.Servers
@using MoonlightServers.Shared.Http.Responses.Admin.Stars
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Dt
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonCore.Blazor.FlyonUi.Components
@inject HttpApiClient ApiClient
@inject AlertService AlertService
@@ -67,7 +64,7 @@
</a>
<a href="#" @onclick="() => Delete(context)" @onclick:preventDefault
class="text-danger">
class="text-error">
<i class="icon-trash text-base"></i>
</a>
</div>

View File

@@ -2,12 +2,12 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonCore.Helpers
@using Moonlight.Shared.Http.Responses.Admin.Users
@using MoonlightServers.Shared.Http.Requests.Admin.Servers
@using MoonlightServers.Shared.Http.Responses.Admin.Servers
@using MoonlightServers.Frontend.UI.Components.Servers.UpdateServerPartials
@using MoonlightServers.Shared.Http.Responses.Admin.NodeAllocations
@inject HttpApiClient ApiClient
@inject NavigationManager Navigation
@@ -31,16 +31,16 @@
<HandleForm @ref="Form" Model="Request" OnValidSubmit="OnSubmit">
<Tabs>
<Tab Name="General">
<GeneralServerUpdate Request="Request" />
<GeneralServerUpdate Request="Request" Owner="Owner"/>
</Tab>
<Tab Name="Allocations">
<AllocationsServerUpdate Request="Request" Server="Server" />
<AllocationsServerUpdate Request="Request" Server="Server" Allocations="Allocations"/>
</Tab>
<Tab Name="Variables">
<VariablesServerUpdate Request="Request" Server="Server" />
<VariablesServerUpdate Request="Request" Server="Server"/>
</Tab>
<Tab Name="Advanced">
<AdvancedServerUpdate Request="Request" />
<AdvancedServerUpdate Request="Request"/>
</Tab>
</Tabs>
</HandleForm>
@@ -55,14 +55,45 @@
private UpdateServerRequest Request;
private ServerResponse Server;
private List<NodeAllocationResponse> Allocations = new();
private UserResponse Owner;
private async Task Load(LazyLoader _)
{
Server = await ApiClient.GetJson<ServerResponse>($"api/admin/servers/{Id}");
Request = Mapper.Map<UpdateServerRequest>(Server);
Request = new()
{
Name = Server.Name,
AllocationIds = Server.AllocationIds,
OwnerId = Server.OwnerId,
Bandwidth = Server.Bandwidth,
Cpu = Server.Cpu,
Disk = Server.Disk,
DockerImageIndex = Server.DockerImageIndex,
Memory = Server.Memory,
StartupOverride = Server.StartupOverride
};
foreach (var allocationId in Server.AllocationIds)
{
var allocation = await ApiClient.GetJson<NodeAllocationResponse>(
$"api/admin/servers/nodes/{Server.NodeId}/allocations/{allocationId}"
);
Allocations.Add(allocation);
}
Owner = await ApiClient.GetJson<UserResponse>(
$"api/admin/users/{Server.OwnerId}"
);
}
private async Task OnSubmit()
{
Request.AllocationIds = Allocations.Select(x => x.Id).ToArray();
Request.OwnerId = Owner.Id;
await ApiClient.Patch($"api/admin/servers/{Id}", Request);
await ToastService.Success("Successfully updated server");

View File

@@ -1,6 +1,6 @@
@page "/admin/servers"
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Components
@attribute [Authorize(Policy = "permissions:admin.servers.overview")]

View File

@@ -2,8 +2,6 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonCore.Helpers
@using MoonlightServers.Shared.Http.Requests.Admin.Nodes
@@ -28,27 +26,27 @@
<HandleForm @ref="Form" Model="Request" OnValidSubmit="OnSubmit">
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Name</label>
<label class="block text-sm font-medium leading-6 text-base-content">Name</label>
<div class="mt-2">
<input @bind="Request.Name" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.Name" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Fqdn</label>
<label class="block text-sm font-medium leading-6 text-base-content">Fqdn</label>
<div class="mt-2">
<input @bind="Request.Fqdn" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.Fqdn" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">HttpPort</label>
<label class="block text-sm font-medium leading-6 text-base-content">HttpPort</label>
<div class="mt-2">
<input @bind="Request.HttpPort" type="number" autocomplete="off" class="form-input w-full">
<input @bind="Request.HttpPort" type="number" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">FtpPort</label>
<label class="block text-sm font-medium leading-6 text-base-content">FtpPort</label>
<div class="mt-2">
<input @bind="Request.FtpPort" type="number" autocomplete="off" class="form-input w-full">
<input @bind="Request.FtpPort" type="number" autocomplete="off" class="input w-full">
</div>
</div>
</div>

View File

@@ -1,18 +1,16 @@
@page "/admin/servers/nodes"
@using Microsoft.Extensions.Logging
@using MoonCore.Blazor.FlyonUi.Alerts
@using MoonCore.Blazor.FlyonUi.DataTables
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Alerts
@using MoonCore.Helpers
@using MoonCore.Models
@using MoonlightServers.Shared.Http.Responses.Admin.Nodes
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Dt
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonlightServers.Frontend.Services
@using MoonlightServers.Shared.Http.Responses.Admin.Nodes.Statistics
@using MoonlightServers.Shared.Http.Responses.Admin.Nodes.Sys
@using MoonCore.Blazor.FlyonUi.Components
@inject HttpApiClient ApiClient
@inject NodeService NodeService
@@ -57,7 +55,7 @@
{
if (data == null)
{
<div class="text-danger flex items-center">
<div class="text-error flex items-center">
<i class="icon-server-off text-base me-1"></i>
<span>
API Error
@@ -75,13 +73,13 @@
}
else
{
<div class="text-danger flex items-center">
<div class="text-error flex items-center">
<i class="icon-server-off text-base me-1"></i>
<span class="me-2">
Error
</span>
<a @onclick="() => ShowErrorDetails(context.Id)" @onclick:preventDefault
href="#" class="ms-1 text-gray-600">Details</a>
href="#" class="ms-1 text-base-content/40">Details</a>
</div>
}
}
@@ -108,7 +106,7 @@
{
if (data == null)
{
<div class="flex items-center text-danger">
<div class="flex items-center text-error">
<i class="icon-server-off text-base me-1"></i>
<span>
API Error
@@ -149,7 +147,7 @@
</a>
<a href="#" @onclick="() => Delete(context)" @onclick:preventDefault
class="text-danger">
class="text-error">
<i class="icon-trash text-base"></i>
</a>
</div>
@@ -243,6 +241,6 @@
(data.RoundtripRemoteFailure ? "(Failed at node)" : "(Failed at api server)") +
$" {data.RoundtripError}";
await AlertService.Danger("Node error details", message);
await AlertService.Error("Node error details", message);
}
}

View File

@@ -2,8 +2,6 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonCore.Helpers
@using MoonlightServers.Shared.Http.Requests.Admin.Nodes
@using MoonlightServers.Shared.Http.Responses.Admin.Nodes
@@ -63,7 +61,16 @@
private async Task Load(LazyLoader _)
{
Node = await ApiClient.GetJson<NodeResponse>($"api/admin/servers/nodes/{Id}");
Request = Mapper.Map<UpdateNodeRequest>(Node);
Request = new UpdateNodeRequest()
{
Name = Node.Name,
EnableDynamicFirewall = Node.EnableDynamicFirewall,
EnableTransparentMode = Node.EnableTransparentMode,
Fqdn = Node.Fqdn,
FtpPort = Node.FtpPort,
HttpPort = Node.HttpPort
};
}
private async Task OnSubmit()

View File

@@ -3,8 +3,6 @@
@using Microsoft.AspNetCore.Components.Authorization
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonCore.Helpers
@using MoonlightServers.Shared.Http.Requests.Admin.Stars
@@ -29,15 +27,15 @@
<HandleForm @ref="Form" Model="Request" OnValidSubmit="OnSubmit">
<div class="grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Name</label>
<label class="block text-sm font-medium leading-6 text-base-content">Name</label>
<div class="mt-2">
<input @bind="Request.Name" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.Name" type="text" autocomplete="off" class="input w-full">
</div>
</div>
<div class="sm:col-span-2">
<label class="block text-sm font-medium leading-6 text-white">Author</label>
<label class="block text-sm font-medium leading-6 text-base-content">Author</label>
<div class="mt-2">
<input @bind="Request.Author" type="text" autocomplete="off" class="form-input w-full">
<input @bind="Request.Author" type="text" autocomplete="off" class="input w-full">
</div>
</div>
</div>

View File

@@ -4,15 +4,11 @@
@using MoonCore.Blazor.FlyonUi.DataTables
@using MoonCore.Blazor.FlyonUi.Helpers
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Alerts
@using MoonCore.Helpers
@using MoonCore.Models
@using MoonlightServers.Shared.Http.Responses.Admin.Stars
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Dt
@using MoonCore.Blazor.Tailwind.Services
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonCore.Exceptions
@using MoonCore.Blazor.FlyonUi.Components
@inject HttpApiClient ApiClient
@inject DownloadService DownloadService
@@ -28,7 +24,7 @@
<div class="mb-5">
<PageHeader Title="Stars">
<InputFile id="import-file" hidden="" multiple OnChange="OnImportFiles"/>
<label for="import-file" class="btn btn-tertiary cursor-pointer">
<label for="import-file" class="btn btn-accent cursor-pointer">
<i class="icon-file-up mr-2"></i>
Import
</label>
@@ -58,7 +54,7 @@
<div class="flex justify-end">
@if (!string.IsNullOrEmpty(context.DonateUrl))
{
<a href="@context.DonateUrl" target="_blank" class="text-red-500 mr-3">
<a href="@context.DonateUrl" target="_blank" class="text-accent mr-3">
<i class="icon-heart align-middle"></i>
<span class="align-middle">Donate</span>
</a>
@@ -66,7 +62,7 @@
@if (!string.IsNullOrEmpty(context.UpdateUrl))
{
<a href="#" @onclick:preventDefault class="text-tertiary mr-3">
<a href="#" @onclick:preventDefault class="text-accent mr-3">
<i class="icon-refresh-cw align-middle"></i>
<span class="align-middle">Update</span>
</a>
@@ -82,7 +78,7 @@
</a>
<a href="#" @onclick="() => Delete(context)" @onclick:preventDefault
class="text-danger">
class="text-error">
<i class="icon-trash text-base"></i>
</a>
</div>
@@ -119,7 +115,7 @@
var formattedFileName = star.Name.Replace(" ", "_") + ".json";
await DownloadService.DownloadString(formattedFileName, json);
await DownloadService.Download(formattedFileName, json);
await ToastService.Success($"Successfully exported '{star.Name}'");
}
@@ -141,7 +137,7 @@
{
if (!file.Name.EndsWith(".json"))
{
await ToastService.Danger($"Failed to import '{file.Name}': Only json files are supported");
await ToastService.Error($"Failed to import '{file.Name}': Only json files are supported");
continue;
}
@@ -155,7 +151,7 @@
}
catch (HttpApiException e)
{
await ToastService.Danger($"Failed to import '{file.Name}': {e.Title}");
await ToastService.Error($"Failed to import '{file.Name}': {e.Title}");
}
}

View File

@@ -2,8 +2,6 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.FlyonUi.Toasts
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Blazor.Tailwind.Toasts
@using MoonCore.Helpers
@using MoonlightServers.Shared.Http.Requests.Admin.Stars
@using MoonlightServers.Shared.Http.Responses.Admin.Stars
@@ -75,7 +73,24 @@
private async Task Load(LazyLoader _)
{
Detail = await ApiClient.GetJson<StarDetailResponse>($"api/admin/servers/stars/{Id}");
Request = Mapper.Map<UpdateStarRequest>(Detail);
Request = new()
{
Name = Detail.Name,
AllowDockerImageChange = Detail.AllowDockerImageChange,
Author = Detail.Author,
DefaultDockerImage = Detail.DefaultDockerImage,
DonateUrl = Detail.DonateUrl,
InstallDockerImage = Detail.InstallDockerImage,
InstallScript = Detail.InstallScript,
InstallShell = Detail.InstallShell,
OnlineDetection = Detail.OnlineDetection,
ParseConfiguration = Detail.ParseConfiguration,
RequiredAllocations = Detail.RequiredAllocations,
StartupCommand = Detail.StartupCommand,
StopCommand = Detail.StopCommand,
UpdateUrl = Detail.UpdateUrl,
Version = Detail.Version
};
}
private async Task OnSubmit()

View File

@@ -2,7 +2,6 @@
@using MoonCore.Blazor.FlyonUi.Components
@using MoonlightServers.Frontend.UI.Components.Servers
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Models
@using MoonlightServers.Frontend.Services
@using MoonlightServers.Shared.Http.Responses.Client.Servers

View File

@@ -3,7 +3,6 @@
@using Microsoft.AspNetCore.SignalR.Client
@using MoonCore.Blazor.FlyonUi.Components
@using MoonCore.Blazor.Tailwind.Components
@using MoonCore.Exceptions
@using MoonCore.Helpers
@using MoonlightServers.Frontend.Interfaces
@@ -21,15 +20,9 @@
<LazyLoader Load="Load">
@if (NotFound)
{
<div class="flex flex-col justify-center text-center">
<img class="h-48 mt-5 mb-3" src="/svg/notfound.svg" alt="Not found illustration">
<h3 class="mt-2 font-semibold text-white text-lg">
Server not found
</h3>
<p class="mt-1 text-gray-300">
The server you requested does not exist
</p>
</div>
<IconAlert Title="Server not found" Icon="icon-search" Color="text-primary">
The requested server could not be found
</IconAlert>
}
else
{
@@ -39,7 +32,7 @@
var bgColor = State switch
{
ServerState.Installing => "bg-primary",
ServerState.Offline => "bg-danger",
ServerState.Offline => "bg-error",
ServerState.Starting => "bg-warning",
ServerState.Stopping => "bg-warning",
ServerState.Online => "bg-success",
@@ -51,7 +44,7 @@
<div class="flex flex-col">
<div class="hidden sm:flex text-lg font-semibold">@Server.Name</div>
<div class="hidden text-sm text-gray-400 md:flex gap-x-3">
<div class="hidden text-sm text-base-content/60 md:flex gap-x-3">
<span>
<i class="icon-sparkles me-0.5 align-middle"></i>
<span class="align-middle">@Server.StarName</span>
@@ -102,14 +95,14 @@
{
if (State == ServerState.Stopping)
{
<WButton CssClasses="btn btn-danger" OnClick="_ => Kill()">
<WButton CssClasses="btn btn-error" OnClick="_ => Kill()">
<i class="icon-bomb me-1 align-middle"></i>
<span class="align-middle">Kill</span>
</WButton>
}
else
{
<WButton CssClasses="btn btn-danger" OnClick="_ => Stop()">
<WButton CssClasses="btn btn-error" OnClick="_ => Stop()">
<i class="icon-squircle me-1 align-middle"></i>
<span class="align-middle">Stop</span>
</WButton>
@@ -117,7 +110,7 @@
}
else
{
<button type="button" class="btn btn-danger" disabled="disabled">
<button type="button" class="btn btn-error" disabled="disabled">
<i class="icon-squircle me-1 align-middle"></i>
<span class="align-middle">Stop</span>
</button>
@@ -135,7 +128,7 @@
<span class="align-middle">Restart</span>
</button>
<button type="button" class="btn btn-danger" disabled="disabled">
<button type="button" class="btn btn-error" disabled="disabled">
<i class="icon-squircle me-1 align-middle"></i>
<span class="align-middle">Stop</span>
</button>
@@ -160,7 +153,7 @@
{
<a href="/servers/@(ServerId)/@(tab.Path)" @onclick:preventDefault
@onclick="() => SwitchTab(tab)"
class="inline-flex items-center justify-center text-sm font-medium leading-5 rounded-full px-3 py-1 border border-gray-700/60 hover:border-gray-600 shadow-sm bg-gray-800 text-gray-400 transition">
class="inline-flex items-center justify-center text-sm font-medium leading-5 rounded-full px-3 py-1 border border-gray-700/60 hover:border-gray-600 shadow-sm bg-gray-800 text-base-content/60 transition">
@tab.Name
</a>
}

View File

@@ -3,7 +3,7 @@ namespace MoonlightServers.Shared.Http.Responses.Client.Servers.Files;
public class ServerFilesEntryResponse
{
public string Name { get; set; }
public bool IsFile { get; set; }
public bool IsFolder { get; set; }
public long Size { get; set; }
public DateTime CreatedAt { get; set; }